2 private Curl.EasyHandle curl;
3 private Cancellable cancellable;
4 private FileStream file;
5 private string dirname;
6 private HashTable<string,int> file_size;
8 public FtpDownloader (Cancellable? _cancellable) {
9 cancellable = _cancellable;
10 curl = new Curl.EasyHandle ();
13 [CCode (instance_pos = -1)]
14 size_t write_callback (void *buffer, size_t size, size_t nmemb) {
15 if (cancellable != null && cancellable.is_cancelled ())
18 unowned uint8[] buf = (uint8[]) buffer;
19 buf.length = (int) (size * nmemb);
26 private int last_dlnow;
28 int progress_callback (double dltotal, double dlnow, double ultotal, double ulnow) {
29 if (cancellable != null && cancellable.is_cancelled ())
31 if (last_dlnow != (int) dlnow) {
32 last_dlnow = (int) dlnow;
33 progress ((int) dltotal, last_dlnow);
38 public void download (string url, string filename) throws IOError {
39 print ("download (\"%s\", \"%s\")\n", url, filename);
40 download_dir (Path.get_dirname (url) + "/");
41 string basename = Path.get_basename (url);
42 int size = file_size.lookup (basename);
45 Posix.stat (filename, out st);
46 if (size == st.st_size) {
47 progress (size, size);
52 curl.setopt (Curl.Option.URL, url);
53 curl.setopt (Curl.Option.WRITEFUNCTION, write_callback);
54 curl.setopt (Curl.Option.WRITEDATA, this);
55 curl.setopt (Curl.Option.NOPROGRESS, 0L);
56 curl.setopt (Curl.Option.PROGRESSFUNCTION, progress_callback);
57 curl.setopt (Curl.Option.PROGRESSDATA, this);
60 file = FileStream.open (filename, "w");
62 var res = curl.perform ();
63 if (Curl.Code.ABORTED_BY_CALLBACK == res) {
64 throw new IOError.CANCELLED ("Download cancelled.");
65 } else if (res != 0) {
66 stderr.printf ("cURL performed: %d\n", res);
72 void parse_dir_entry (string line) {
74 Regex re_dir_entry = new Regex ("^.* ([0-9]*) [A-Z][a-z]* *[0-9]* [0-9]* [0-9]*:[0-9]* ([^ ]*)$");
76 if (re_dir_entry.match (line, 0, out match_info)) {
77 string name = match_info.fetch (2);
78 int size = match_info.fetch (1).to_int ();
79 file_size.insert (name, size);
81 } catch (RegexError e) {
85 string last_line = null;
86 [CCode (instance_pos = -1)]
87 size_t dir_callback (void *buffer, size_t size, size_t nmemb) {
88 if (cancellable != null && cancellable.is_cancelled ())
91 unowned char[] buf = (char[]) buffer;
92 buf.length = (int) (size * nmemb);
97 for (i = 0, j = 0; i < buf.length; i++, j++) {
100 if (last_line != null) {
101 parse_dir_entry (last_line + (string) p);
104 parse_dir_entry ((string) p);
111 last_line = ((string) p).ndup (j);
116 public void download_dir (string url) throws IOError {
117 if (dirname != null && dirname == url)
119 print ("download_dir (\"%s\")\n", url);
121 curl.setopt (Curl.Option.URL, url);
122 curl.setopt (Curl.Option.WRITEFUNCTION, dir_callback);
123 curl.setopt (Curl.Option.WRITEDATA, this);
124 curl.setopt (Curl.Option.NOPROGRESS, 1L);
125 curl.setopt (Curl.Option.PROGRESSFUNCTION, null);
126 curl.setopt (Curl.Option.PROGRESSDATA, null);
128 file_size = new HashTable<string, int> (str_hash, int_equal);
130 var res = curl.perform ();
131 if (Curl.Code.ABORTED_BY_CALLBACK == res) {
132 throw new IOError.CANCELLED ("Dir listing cancelled.");
133 } else if (res != 0) {
134 stderr.printf ("cURL performed: %d\n", res);
139 public signal void progress (int dltotal, int dlnow);