dillo  3.0.5
About: dillo is a small, fast, extensible Web browser particularly suitable for older or smaller computers and embedded systems (but only limited or no support for frames, CSS, JavaScript, Java).
  Fossies Dox: dillo-3.0.5.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

downloads.cc
Go to the documentation of this file.
1 /*
2  * File: downloads.cc
3  *
4  * Copyright (C) 2005-2007 Jorge Arellano Cid <jcid@dillo.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  */
11 
12 /*
13  * A FLTK-based GUI for the downloads dpi (dillo plugin).
14  */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <ctype.h>
23 #include <math.h>
24 #include <time.h>
25 #include <signal.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/stat.h>
29 #include <sys/un.h>
30 #include <sys/wait.h>
31 
32 #include <FL/Fl.H>
33 #include <FL/fl_ask.H>
34 #include <FL/fl_draw.H>
35 #include <FL/Fl_File_Chooser.H>
36 #include <FL/Fl_Window.H>
37 #include <FL/Fl_Widget.H>
38 #include <FL/Fl_Group.H>
39 #include <FL/Fl_Scroll.H>
40 #include <FL/Fl_Pack.H>
41 #include <FL/Fl_Box.H>
42 #include <FL/Fl_Button.H>
43 
44 #include "dpiutil.h"
45 #include "../dpip/dpip.h"
46 
47 /*
48  * Debugging macros
49  */
50 #define _MSG(...)
51 #define MSG(...) printf("[downloads dpi]: " __VA_ARGS__)
52 
53 /*
54  * Class declarations
55  */
56 
57 // ProgressBar widget --------------------------------------------------------
58 
59 class ProgressBar : public Fl_Box {
60 protected:
61  double mMin;
62  double mMax;
63  double mPresent;
64  double mStep;
66  char mMsg[64];
67  Fl_Color mTextColor;
68  void draw();
69 public:
70  ProgressBar(int x, int y, int w, int h, const char *lbl = 0);
71  void range(double min, double max, double step = 1) {
72  mMin = min; mMax = max; mStep = step;
73  };
74  void step(double step) { mPresent += step; redraw(); };
75  void move(double step);
76  double minimum() { return mMin; }
77  double maximum() { return mMax; }
78  void minimum(double nm) { mMin = nm; };
79  void maximum(double nm) { mMax = nm; };
80  double position () { return mPresent; }
81  double step() { return mStep; }
82  void position(double pos) { mPresent = pos; redraw(); }
83  void showtext(bool st) { mShowPct = st; }
84  void message(char *msg) { mShowMsg = true; strncpy(mMsg,msg,63); redraw(); }
85  bool showtext() { return mShowPct; }
86  void text_color(Fl_Color col) { mTextColor = col; }
87  Fl_Color text_color() { return mTextColor; }
88 };
89 
90 // Download-item class -------------------------------------------------------
91 
92 class DLItem {
93  enum {
95  };
96 
97  pid_t mPid;
98  int LogPipe[2];
100  char *target_dir;
101  size_t log_len, log_max;
103  char *log_text;
104  time_t init_time;
105  char **dl_argv;
111 
112  int gw, gh;
113  Fl_Group *group;
115  Fl_Button *prButton;
116  Fl_Widget *prTitle, *prGot, *prSize, *prRate, *pr_Rate, *prETA, *prETAt;
117 
118 public:
119  DLItem(const char *full_filename, const char *url);
120  ~DLItem();
121  void child_init();
122  void father_init();
123  void update_size(int new_sz);
124  void log_text_add(const char *buf, ssize_t st);
125  void log_text_show();
126  void abort_dl();
127  void prButton_cb();
128  pid_t pid() { return mPid; }
129  void pid(pid_t p) { mPid = p; }
130  void child_finished(int status);
131  void status_msg(const char *msg) { prBar->message((char*)msg); }
132  Fl_Widget *get_widget() { return group; }
133  int widget_done() { return WidgetDone; }
134  void widget_done(int val) { WidgetDone = val; }
135  int updates_done() { return UpdatesDone; }
136  void updates_done(int val) { UpdatesDone = val; }
137  int fork_done() { return ForkDone; }
138  void fork_done(int val) { ForkDone = val; }
139  int log_done() { return LogDone; }
140  void log_done(int val) { LogDone = val; }
141  int wget_status() { return WgetStatus; }
142  void wget_status(int val) { WgetStatus = val; }
143  void update_prSize(int newsize);
144  void update();
145 };
146 
147 // DLItem List ---------------------------------------------------------------
148 
150 class DLItemList {
151  DLItem *mList[32];
152  int mNum, mMax;
153 
154 public:
155  DLItemList() { mNum = 0; mMax = 32; }
157  int num() { return mNum; }
158  void add(DLItem *i) { if (mNum < mMax) mList[mNum++] = i; }
159  DLItem *get(int n) { return (n >= 0 && n < mNum) ? mList[n] : NULL; }
160  void del(int n) { if (n >= 0 && n < mNum) mList[n] = mList[--mNum]; }
161 };
162 
163 // DLWin ---------------------------------------------------------------------
164 
165 class DLWin {
167  Fl_Window *mWin;
168  Fl_Scroll *mScroll;
169  Fl_Pack *mPG;
170 
171 public:
172  DLWin(int ww, int wh);
173  void add(const char *full_filename, const char *url);
174  void del(int n_item);
175  int num();
176  int num_running();
177  void listen(int req_fd);
178  void show() { mWin->show(); }
179  void hide() { mWin->hide(); }
180  void abort_all();
181 };
182 
183 /*
184  * FLTK cannot be dissuaded from interpreting '@' in a tooltip
185  * as indicating a symbol unless we escape it.
186  */
187 static char *escape_tooltip(const char *buf, ssize_t len)
188 {
189  if (len < 0)
190  len = 0;
191 
192  char *ret = (char *) malloc(2 * len + 1);
193  char *dest = ret;
194 
195  while (len-- > 0) {
196  if (*buf == '@')
197  *dest++ = *buf;
198  *dest++ = *buf++;
199  }
200  *dest = '\0';
201 
202  return ret;
203 }
204 
205 
206 /*
207  * Global variables
208  */
209 
210 // SIGCHLD mask
211 sigset_t mask_sigchld;
212 
213 // SIGCHLD flag
214 volatile sig_atomic_t caught_sigchld = 0;
215 
216 // The download window object
217 static class DLWin *dl_win = NULL;
218 
219 
220 
221 // ProgressBar widget --------------------------------------------------------
222 
223 void ProgressBar::move(double step)
224 {
225  mPresent += step;
226  if (mPresent > mMax)
227  mPresent = mMin;
228  redraw();
229 }
230 
231 ProgressBar::ProgressBar(int x, int y, int w, int h, const char *lbl)
232 : Fl_Box(x, y, w, h, lbl)
233 {
234  mMin = mPresent = 0;
235  mMax = 100;
236  mShowPct = true;
237  mShowMsg = false;
238  box(FL_THIN_UP_BOX);
239  color(FL_WHITE);
240 }
241 
243 {
244  struct Rectangle {
245  int x, y, w, h;
246  };
247 
248  //drawstyle(style(), flags());
249  draw_box();
250  Rectangle r = {x(), y(), w(), h()};
251  if (mPresent > mMax)
252  mPresent = mMax;
253  if (mPresent < mMin)
254  mPresent = mMin;
255  double pct = (mPresent - mMin) / mMax;
256 
257  r.w = r.w * pct + .5;
258  fl_rectf(r.x, r.y, r.w, r.h, FL_BLUE);
259 
260  if (mShowMsg) {
261  fl_color(FL_RED);
262  fl_font(this->labelfont(), this->labelsize());
263  fl_draw(mMsg, x(), y(), w(), h(), FL_ALIGN_CENTER);
264  } else if (mShowPct) {
265  char buffer[30];
266  sprintf(buffer, "%d%%", int (pct * 100 + .5));
267  fl_color(FL_RED);
268  fl_font(this->labelfont(), this->labelsize());
269  fl_draw(buffer, x(), y(), w(), h(), FL_ALIGN_CENTER);
270  }
271 }
272 
273 
274 // Download-item class -------------------------------------------------------
275 
276 static void prButton_scb(Fl_Widget *, void *cb_data)
277 {
278  DLItem *i = (DLItem *)cb_data;
279 
280  i->prButton_cb();
281 }
282 
283 DLItem::DLItem(const char *full_filename, const char *url)
284 {
285  struct stat ss;
286  const char *p;
287  char *esc_url;
288 
289  if (pipe(LogPipe) < 0) {
290  MSG("pipe, %s\n", dStrerror(errno));
291  return;
292  }
293  /* Set FD to background */
294  fcntl(LogPipe[0], F_SETFL,
295  O_NONBLOCK | fcntl(LogPipe[0], F_GETFL));
296 
297  fullname = dStrdup(full_filename);
298  p = strrchr(fullname, '/');
299  shortname = (p) ? dStrdup(p + 1) : dStrdup("??");
300  p = strrchr(full_filename, '/');
301  target_dir= p ? dStrndup(full_filename,p-full_filename+1) : dStrdup("??");
302 
303  log_len = 0;
304  log_max = 0;
306  log_text = NULL;
308  total_bytesize = -1;
309 
310  // Init value. Reset later, upon the first data bytes arrival
311  init_time = time(NULL);
312 
314 
315  // BUG:? test a URL with ' inside.
316  /* escape "'" character for the shell. Is it necessary? */
317  esc_url = Escape_uri_str(url, "'");
318  /* avoid malicious SMTP relaying with FTP urls */
319  if (dStrnAsciiCasecmp(esc_url, "ftp:/", 5) == 0)
320  Filter_smtp_hack(esc_url);
321  dl_argv = new char*[8];
322  int i = 0;
323  dl_argv[i++] = (char*)"wget";
324  if (stat(fullname, &ss) == 0)
325  init_bytesize = (int)ss.st_size;
326  dl_argv[i++] = (char*)"-c";
327  dl_argv[i++] = (char*)"--load-cookies";
328  dl_argv[i++] = dStrconcat(dGethomedir(), "/.dillo/cookies.txt", NULL);
329  dl_argv[i++] = (char*)"-O";
330  dl_argv[i++] = fullname;
331  dl_argv[i++] = esc_url;
332  dl_argv[i++] = NULL;
333 
334  DataDone = 0;
335  LogDone = 0;
336  UpdatesDone = 0;
337  ForkDone = 0;
338  WidgetDone = 0;
339  WgetStatus = -1;
340 
341  gw = 400, gh = 70;
342  group = new Fl_Group(0,0,gw,gh);
343  group->begin();
344  prTitle = new Fl_Box(24, 7, 290, 23);
345  prTitle->box(FL_RSHADOW_BOX);
346  prTitle->color(FL_WHITE);
347  prTitle->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP);
348  prTitle->copy_label(shortname);
349  // Attach this 'log_text' to the tooltip
350  log_text_add("Target File: ", 13);
351  log_text_add(fullname, strlen(fullname));
352  log_text_add("\n\n", 2);
353 
354  prBar = new ProgressBar(24, 40, 92, 20);
355  prBar->box(FL_THIN_UP_BOX);
356  prBar->tooltip("Progress Status");
357 
358  int ix = 122, iy = 37, iw = 50, ih = 14;
359  Fl_Widget *o = new Fl_Box(ix,iy,iw,ih, "Got");
360  o->box(FL_RFLAT_BOX);
361  o->color(FL_DARK2);
362  o->labelsize(12);
363  o->tooltip("Downloaded Size");
364  prGot = new Fl_Box(ix,iy+14,iw,ih, "0KB");
365  prGot->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
366  prGot->labelcolor(FL_BLUE);
367  prGot->labelsize(12);
368  prGot->box(FL_NO_BOX);
369 
370  ix += iw;
371  o = new Fl_Box(ix,iy,iw,ih, "Size");
372  o->box(FL_RFLAT_BOX);
373  o->color(FL_DARK2);
374  o->labelsize(12);
375  o->tooltip("Total Size");
376  prSize = new Fl_Box(ix,iy+14,iw,ih, "??");
377  prSize->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
378  prSize->labelsize(12);
379  prSize->box(FL_NO_BOX);
380 
381  ix += iw;
382  o = new Fl_Box(ix,iy,iw,ih, "Rate");
383  o->box(FL_RFLAT_BOX);
384  o->color(FL_DARK2);
385  o->labelsize(12);
386  o->tooltip("Current transfer Rate (KBytes/sec)");
387  prRate = new Fl_Box(ix,iy+14,iw,ih, "??");
388  prRate->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
389  prRate->labelsize(12);
390  prRate->box(FL_NO_BOX);
391 
392  ix += iw;
393  o = new Fl_Box(ix,iy,iw,ih, "~Rate");
394  o->box(FL_RFLAT_BOX);
395  o->color(FL_DARK2);
396  o->labelsize(12);
397  o->tooltip("Average transfer Rate (KBytes/sec)");
398  pr_Rate = new Fl_Box(ix,iy+14,iw,ih, "??");
399  pr_Rate->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
400  pr_Rate->labelsize(12);
401  pr_Rate->box(FL_NO_BOX);
402 
403  ix += iw;
404  prETAt = o = new Fl_Box(ix,iy,iw,ih, "ETA");
405  o->box(FL_RFLAT_BOX);
406  o->color(FL_DARK2);
407  o->labelsize(12);
408  o->tooltip("Estimated Time of Arrival");
409  prETA = new Fl_Box(ix,iy+14,iw,ih, "??");
410  prETA->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
411  prETA->labelsize(12);
412  prETA->box(FL_NO_BOX);
413 
414  prButton = new Fl_Button(326, 9, 44, 19, "Stop");
415  prButton->tooltip("Stop this transfer");
416  prButton->box(FL_UP_BOX);
417  prButton->clear_visible_focus();
418  prButton->callback(prButton_scb, this);
419 
420  group->box(FL_ROUNDED_BOX);
421  group->end();
422 }
423 
425 {
426  free(shortname);
427  dFree(fullname);
428  dFree(target_dir);
429  free(log_text);
430  int idx = (strcmp(dl_argv[1], "-c")) ? 2 : 3;
431  dFree(dl_argv[idx]);
432  dFree(dl_argv[idx+3]);
433  delete [] dl_argv;
434 
435  delete(group);
436 }
437 
438 /*
439  * Abort a running download
440  */
442 {
443  if (!log_done()) {
444  dClose(LogPipe[0]);
445  Fl::remove_fd(LogPipe[0]);
446  log_done(1);
447  // Stop wget
448  if (!fork_done())
449  kill(pid(), SIGTERM);
450  }
451  widget_done(1);
452 }
453 
455 {
456  prButton->deactivate();
457  abort_dl();
458 }
459 
461 {
462  dClose(0); // stdin
463  dClose(1); // stdout
464  dClose(LogPipe[0]);
465  dup2(LogPipe[1], 2); // stderr
466  // set the locale to C for log parsing
467  setenv("LC_ALL", "C", 1);
468  // start wget
469  execvp(dl_argv[0], dl_argv);
470 }
471 
472 /*
473  * Update displayed size
474  */
475 void DLItem::update_prSize(int newsize)
476 {
477  char num[64];
478 
479  if (newsize > 1024 * 1024)
480  snprintf(num, 64, "%.1fMB", (float)newsize / (1024*1024));
481  else
482  snprintf(num, 64, "%.0fKB", (float)newsize / 1024);
483  prSize->copy_label(num);
484 }
485 
486 void DLItem::log_text_add(const char *buf, ssize_t st)
487 {
488  const char *p;
489  char *esc_str, *q, *d, num[64];
490  size_t esc_len;
491 
492  // WORKAROUND: We have to escape '@' in FLTK tooltips.
493  esc_str = escape_tooltip(buf, st);
494  esc_len = strlen(esc_str);
495 
496  // Make room...
497  if (log_len + esc_len >= log_max) {
498  log_max = log_len + esc_len + 1024;
499  log_text = (char *) dRealloc (log_text, log_max);
500  log_text[log_len] = 0;
501  prTitle->tooltip(log_text);
502  }
503 
504  // FSM to remove wget's "dot-progress" (i.e. "^ " || "^[0-9]+K")
505  q = log_text + log_len;
506  for (p = esc_str; (size_t)(p - esc_str) < esc_len; ++p) {
507  switch (log_state) {
508  case ST_newline:
509  if (*p == ' ') {
511  } else if (isdigit(*p)) {
512  *q++ = *p; log_state = ST_number;
513  } else if (*p == '\n') {
514  *q++ = *p;
515  } else {
516  *q++ = *p; log_state = ST_copy;
517  }
518  break;
519  case ST_number:
520  if (isdigit(*q++ = *p)) {
521  // keep here
522  } else if (*p == 'K') {
523  for (--q; isdigit(q[-1]); --q) ; log_state = ST_discard;
524  } else {
525  log_state = ST_copy;
526  }
527  break;
528  case ST_discard:
529  if (*p == '\n')
531  break;
532  case ST_copy:
533  if ((*q++ = *p) == '\n')
535  break;
536  }
537  }
538  *q = 0;
539  log_len = strlen(log_text);
540 
541  free(esc_str);
542 
543  // Now scan for the length of the file
544  if (total_bytesize == -1) {
545  p = strstr(log_text, "\nLength: ");
546  if (p && isdigit(p[9]) && strchr(p + 9, ' ')) {
547  for (p += 9, d = &num[0]; *p != ' '; ++p)
548  if (isdigit(*p))
549  *d++ = *p;
550  *d = 0;
551  total_bytesize = strtol (num, NULL, 10);
552  // Update displayed size
554 
555  // WORKAROUND: For unknown reasons a redraw is needed here for some
556  // machines --jcid
557  group->redraw();
558  }
559  }
560 
561  // Show we're connecting...
562  if (curr_bytesize == 0) {
563  prTitle->copy_label("Connecting...");
564  }
565 }
566 
569 {
570  MSG("\nStored Log:\n%s", log_text);
571 }
572 
573 void DLItem::update_size(int new_sz)
574 {
575  char buf[64];
576 
577  if (curr_bytesize == 0 && new_sz) {
578  // Start the timer with the first bytes got
579  init_time = time(NULL);
580  // Update the title
581  prTitle->copy_label(shortname);
582  // WORKAROUND: For unknown reasons a redraw is needed here for some
583  // machines --jcid
584  group->redraw();
585  }
586 
587  curr_bytesize = new_sz;
588  if (curr_bytesize > 1024 * 1024)
589  snprintf(buf, 64, "%.1fMB", (float)curr_bytesize / (1024*1024));
590  else
591  snprintf(buf, 64, "%.0fKB", (float)curr_bytesize / 1024);
592  prGot->copy_label(buf);
593  if (total_bytesize == -1) {
594  prBar->showtext(false);
595  prBar->move(1);
596  } else {
597  prBar->showtext(true);
598  double pos = 100.0;
599  if (total_bytesize > 0)
600  pos *= (double)curr_bytesize / total_bytesize;
601  prBar->position(pos);
602  }
603 }
604 
605 static void read_log_cb(int fd_in, void *data)
606 {
607  DLItem *dl_item = (DLItem *)data;
608  const int BufLen = 4096;
609  char Buf[BufLen];
610  ssize_t st;
611 
612  do {
613  st = read(fd_in, Buf, BufLen);
614  if (st < 0) {
615  if (errno == EAGAIN) {
616  break;
617  }
618  perror("read, ");
619  break;
620  } else if (st == 0) {
621  dClose(fd_in);
622  Fl::remove_fd(fd_in, 1);
623  dl_item->log_done(1);
624  break;
625  } else {
626  dl_item->log_text_add(Buf, st);
627  }
628  } while (1);
629 }
630 
632 {
633  dClose(LogPipe[1]);
634  Fl::add_fd(LogPipe[0], 1, read_log_cb, this); // Read
635 
636  // Start the timer after the child is running.
637  // (this makes a big difference with wget)
638  //init_time = time(NULL);
639 }
640 
641 /*
642  * Our wget exited, let's check its status and update the panel.
643  */
644 void DLItem::child_finished(int status)
645 {
646  wget_status(status);
647 
648  if (status == 0) {
649  prButton->label("Done");
650  prButton->tooltip("Close this information panel");
651  } else {
652  prButton->label("Close");
653  prButton->tooltip("Close this information panel");
654  status_msg("ABORTED");
655  if (curr_bytesize == 0) {
656  // Update the title
657  prTitle->copy_label(shortname);
658  }
659  }
660  prButton->activate();
661  prButton->redraw();
662  MSG("wget status %d\n", status);
663 }
664 
665 /*
666  * Convert seconds into human readable [hour]:[min]:[sec] string.
667  */
668 static void secs2timestr(int et, char *str)
669 {
670  int eh, em, es;
671 
672  eh = et / 3600; em = (et % 3600) / 60; es = et % 60;
673  if (eh == 0) {
674  if (em == 0)
675  snprintf(str, 8, "%ds", es);
676  else
677  snprintf(str, 8, "%dm%ds", em, es);
678  } else {
679  snprintf(str, 8, "%dh%dm", eh, em);
680  }
681 }
682 
683 /*
684  * Update Got, Rate, ~Rate and ETA
685  */
687 {
688  struct stat ss;
689  time_t curr_time;
690  float csec, tsec, rate, _rate = 0;
691  char str[64];
692  int et;
693 
694  if (updates_done())
695  return;
696 
697  /* Update curr_size */
698  if (stat(fullname, &ss) == -1) {
699  MSG("stat, %s\n", dStrerror(errno));
700  return;
701  }
702  update_size((int)ss.st_size);
703 
704  /* Get current time */
705  time(&curr_time);
706  csec = (float) (curr_time - init_time);
707 
708  /* Rate */
709  if (csec >= 2) {
710  tsec = (float) (curr_time - twosec_time);
711  rate = ((float)(curr_bytesize-twosec_bytesize) / 1024) / tsec;
712  snprintf(str, 64, (rate < 100) ? "%.1fK/s" : "%.0fK/s", rate);
713  prRate->copy_label(str);
714  }
715  /* ~Rate */
716  if (csec >= 1) {
717  _rate = ((float)(curr_bytesize-init_bytesize) / 1024) / csec;
718  snprintf(str, 64, (_rate < 100) ? "%.1fK/s" : "%.0fK/s", _rate);
719  pr_Rate->copy_label(str);
720  }
721 
722  /* ETA */
723  if (fork_done()) {
724  updates_done(1); // Last update
725  prETAt->label("Time");
726  prETAt->tooltip("Download Time");
727  prETAt->redraw();
728  secs2timestr((int)csec, str);
729  prETA->copy_label(str);
730  if (total_bytesize == -1) {
732  if (wget_status() == 0)
733  status_msg("Done");
734  }
735  } else {
736  if (_rate > 0 && total_bytesize > 0 && curr_bytesize > 0) {
737  et = (int)((total_bytesize-curr_bytesize) / (_rate * 1024));
738  secs2timestr(et, str);
739  prETA->copy_label(str);
740  }
741  }
742 
743  /* Update one and two secs ago times and bytesizes */
745  onesec_time = curr_time;
748 }
749 
750 // SIGCHLD -------------------------------------------------------------------
751 
754 static void raw_sigchld(int)
755 {
756  caught_sigchld = 1;
757 }
758 
760 static void est_sigchld(void)
761 {
762  struct sigaction sigact;
763  sigset_t set;
764 
765  (void) sigemptyset(&set);
766  sigact.sa_handler = raw_sigchld;
767  sigact.sa_mask = set;
768  sigact.sa_flags = SA_NOCLDSTOP;
769  if (sigaction(SIGCHLD, &sigact, NULL) == -1) {
770  perror("sigaction");
771  exit(1);
772  }
773 }
774 
775 /*
776  * Timeout function to check wget's exit status.
777  */
778 static void cleanup_cb(void *data)
779 {
780  DLItemList *list = (DLItemList *)data;
781 
782  sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
783  if (caught_sigchld) {
784  /* Handle SIGCHLD */
785  int i, status;
786  for (i = 0; i < list->num(); ++i) {
787  if (!list->get(i)->fork_done() &&
788  waitpid(list->get(i)->pid(), &status, WNOHANG) > 0) {
789  list->get(i)->child_finished(status);
790  list->get(i)->fork_done(1);
791  }
792  }
793  caught_sigchld = 0;
794  }
795  sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
796 
797  Fl::repeat_timeout(1.0,cleanup_cb,data);
798 }
799 
800 /*
801  * Timeout function to update the widget indicators,
802  * also remove widgets marked "done".
803  */
804 static void update_cb(void *data)
805 {
806  static int cb_used = 0;
807 
808  DLItemList *list = (DLItemList *)data;
809 
810  /* Update the widgets and remove the ones marked as done */
811  for (int i = 0; i < list->num(); ++i) {
812  if (!list->get(i)->widget_done()) {
813  list->get(i)->update();
814  } else if (list->get(i)->fork_done()) {
815  // widget_done and fork_done avoid a race condition.
816  dl_win->del(i); --i;
817  }
818  cb_used = 1;
819  }
820 
821  if (cb_used && list->num() == 0)
822  exit(0);
823 
824  Fl::repeat_timeout(1.0,update_cb,data);
825 }
826 
827 
828 // DLWin ---------------------------------------------------------------------
829 
830 /*
831  * Callback function for the request socket.
832  * Read the request, parse and start a new download.
833  */
834 static void read_req_cb(int req_fd, void *)
835 {
836  struct sockaddr_un clnt_addr;
837  int sock_fd;
838  socklen_t csz;
839  Dsh *sh = NULL;
840  char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *dl_dest = NULL;
841 
842  /* Initialize the value-result parameter */
843  csz = sizeof(struct sockaddr_un);
844  /* accept the request */
845  do {
846  sock_fd = accept(req_fd, (struct sockaddr *) &clnt_addr, &csz);
847  } while (sock_fd == -1 && errno == EINTR);
848  if (sock_fd == -1) {
849  MSG("accept, %s fd=%d\n", dStrerror(errno), req_fd);
850  return;
851  }
852 
853  /* create a sock handler */
854  sh = a_Dpip_dsh_new(sock_fd, sock_fd, 8*1024);
855 
856  /* Authenticate our client... */
857  if (!(dpip_tag = a_Dpip_dsh_read_token(sh, 1)) ||
858  a_Dpip_check_auth(dpip_tag) < 0) {
859  MSG("can't authenticate request: %s fd=%d\n", dStrerror(errno), sock_fd);
861  goto end;
862  }
863  dFree(dpip_tag);
864 
865  /* Read request */
866  if (!(dpip_tag = a_Dpip_dsh_read_token(sh, 1))) {
867  MSG("can't read request: %s fd=%d\n", dStrerror(errno), sock_fd);
869  goto end;
870  }
872  _MSG("Received tag={%s}\n", dpip_tag);
873 
874  if ((cmd = a_Dpip_get_attr(dpip_tag, "cmd")) == NULL) {
875  MSG("Failed to parse 'cmd' in {%s}\n", dpip_tag);
876  goto end;
877  }
878  if (strcmp(cmd, "DpiBye") == 0) {
879  MSG("got DpiBye, ignoring...\n");
880  goto end;
881  }
882  if (strcmp(cmd, "download") != 0) {
883  MSG("unknown command: '%s'. Aborting.\n", cmd);
884  goto end;
885  }
886  if (!(url = a_Dpip_get_attr(dpip_tag, "url"))){
887  MSG("Failed to parse 'url' in {%s}\n", dpip_tag);
888  goto end;
889  }
890  if (!(dl_dest = a_Dpip_get_attr(dpip_tag, "destination"))){
891  MSG("Failed to parse 'destination' in {%s}\n", dpip_tag);
892  goto end;
893  }
894  dl_win->add(dl_dest, url);
895 
896 end:
897  dFree(cmd);
898  dFree(url);
899  dFree(dl_dest);
900  dFree(dpip_tag);
902 }
903 
904 /*
905  * Callback for close window request (WM or EscapeKey press)
906  */
907 static void dlwin_esc_cb(Fl_Widget *, void *)
908 {
909  const char *msg = "There are running downloads.\n"
910  "ABORT them and EXIT anyway?";
911 
912  if (dl_win && dl_win->num_running() > 0) {
913  fl_message_title("Dillo Downloads: Abort downloads?");
914  int ch = fl_choice("%s", "Cancel", "*No", "Yes", msg);
915  if (ch == 0 || ch == 1)
916  return;
917  }
918 
919  /* abort each download properly */
920  dl_win->abort_all();
921 }
922 
923 /*
924  * Add a new download request to the main window and
925  * fork a child to do the job.
926  */
927 void DLWin::add(const char *full_filename, const char *url)
928 {
929  DLItem *dl_item = new DLItem(full_filename, url);
930  mDList->add(dl_item);
931  mPG->insert(*dl_item->get_widget(), 0);
932 
933  _MSG("Child index = %d\n", mPG->find(dl_item->get_widget()));
934 
935  // Start the child process
936  pid_t f_pid = fork();
937  if (f_pid == 0) {
938  /* child */
939  dl_item->child_init();
940  _exit(EXIT_FAILURE);
941  } else if (f_pid < 0) {
942  perror("fork, ");
943  exit(1);
944  } else {
945  /* father */
946  dl_item->get_widget()->show();
947  dl_win->show();
948  dl_item->pid(f_pid);
949  dl_item->father_init();
950  }
951 }
952 
953 /*
954  * Delete a download request from the main window.
955  */
956 void DLWin::del(int n_item)
957 {
958  DLItem *dl_item = mDList->get(n_item);
959 
960  // Remove the widget from the packed group
961  mPG->remove(dl_item->get_widget());
962  mScroll->redraw();
963  mDList->del(n_item);
964  delete(dl_item);
965 }
966 
967 /*
968  * Return number of entries
969  */
971 {
972  return mDList->num();
973 }
974 
975 /*
976  * Return number of running downloads
977  */
979 {
980  int i, nr;
981 
982  for (i = nr = 0; i < mDList->num(); ++i)
983  if (!mDList->get(i)->fork_done())
984  ++nr;
985  return nr;
986 }
987 
988 /*
989  * Set a callback function for the request socket
990  */
991 void DLWin::listen(int req_fd)
992 {
993  Fl::add_fd(req_fd, 1, read_req_cb, NULL); // Read
994 }
995 
996 /*
997  * Abort each download properly, and let the main cycle exit
998  */
1000 {
1001  for (int i = 0; i < mDList->num(); ++i)
1002  mDList->get(i)->abort_dl();
1003 }
1004 
1005 /*
1006  * A Scroll class that resizes its resizable widget to its width.
1007  * see http://seriss.com/people/erco/fltk/#ScrollableWidgetBrowser
1008  */
1009 class DlScroll : public Fl_Scroll
1010 {
1011 public:
1012  void resize(int x_, int y_, int w_, int h_)
1013  {
1014  Fl_Scroll::resize(x_, y_, w_, h_);
1015  Fl_Widget *resizable_ = resizable();
1016  int sb_size =
1017  resizable_->h() <= h() ? 0 :
1018  scrollbar_size() ? scrollbar_size() :
1019  Fl::scrollbar_size();
1020  if (resizable_)
1021  resizable_->resize(resizable_->x(),
1022  resizable_->y(),
1023  w() - sb_size,
1024  resizable_->h());
1025  }
1026  DlScroll(int x, int y, int w, int h, const char *l = 0)
1027  : Fl_Scroll(x, y, w, h, l)
1028  {
1029  }
1030 };
1031 
1032 /*
1033  * Create the main window and an empty list of requests.
1034  */
1035 DLWin::DLWin(int ww, int wh) {
1036 
1037  // Init an empty list for the download requests
1038  mDList = new DLItemList();
1039 
1040  // Create the empty main window
1041  mWin = new Fl_Window(ww, wh, "Dillo Downloads");
1042  mWin->begin();
1043  mScroll = new DlScroll(0,0,ww,wh);
1044  mScroll->begin();
1045  mPG = new Fl_Pack(0,0,ww-18,wh);
1046  mPG->end();
1047  mScroll->end();
1048  mScroll->type(Fl_Scroll::VERTICAL);
1049  mScroll->resizable(mPG);
1050  mWin->end();
1051  mWin->resizable(mScroll);
1052  mWin->callback(dlwin_esc_cb, NULL);
1053  mWin->show();
1054 
1055  // Set SIGCHLD handlers
1056  sigemptyset(&mask_sigchld);
1057  sigaddset(&mask_sigchld, SIGCHLD);
1058  est_sigchld();
1059 
1060  fl_message_title_default("Dillo Downloads: Message");
1061 
1062  // Set the cleanup timeout
1063  Fl::add_timeout(1.0, cleanup_cb, mDList);
1064  // Set the update timeout
1065  Fl::add_timeout(1.0, update_cb, mDList);
1066 }
1067 
1068 
1069 // ---------------------------------------------------------------------------
1070 
1071 /*
1072  * Set FL_NORMAL_LABEL to interpret neither symbols (@) nor shortcuts (&)
1073  */
1074 static void custLabelDraw(const Fl_Label* o, int X, int Y, int W, int H,
1075  Fl_Align align)
1076 {
1077  const int interpret_symbols = 0;
1078 
1079  fl_draw_shortcut = 0;
1080  fl_font(o->font, o->size);
1081  fl_color((Fl_Color)o->color);
1082  fl_draw(o->value, X, Y, W, H, align, o->image, interpret_symbols);
1083 }
1084 
1085 static void custLabelMeasure(const Fl_Label* o, int& W, int& H)
1086 {
1087  const int interpret_symbols = 0;
1088 
1089  fl_draw_shortcut = 0;
1090  fl_font(o->font, o->size);
1091  fl_measure(o->value, W, H, interpret_symbols);
1092 }
1093 
1094 
1095 
1096 //int main(int argc, char **argv)
1097 int main()
1098 {
1099  int ww = 420, wh = 85;
1100 
1101  Fl::lock();
1102 
1103  // Disable '@' and '&' interpretation in normal labels.
1104  Fl::set_labeltype(FL_NORMAL_LABEL, custLabelDraw, custLabelMeasure);
1105 
1106  Fl::scheme(NULL);
1107 
1108  // Create the download window
1109  dl_win = new DLWin(ww, wh);
1110 
1111  // Start listening to the request socket
1112  dl_win->listen(STDIN_FILENO);
1113 
1114  MSG("started...\n");
1115 
1116  return Fl::run();
1117 }
1118 
DLItem::target_dir
char * target_dir
Definition: downloads.cc:100
DLItem::status_msg
void status_msg(const char *msg)
Definition: downloads.cc:131
DLItemList::num
int num()
Definition: downloads.cc:157
DLWin::del
void del(int n_item)
Definition: downloads.cc:956
DlScroll
Definition: downloads.cc:1009
a_Dpip_dsh_new
Dsh * a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
Definition: dpip.c:242
DLItem::updates_done
int updates_done()
Definition: downloads.cc:135
ProgressBar::step
double step()
Definition: downloads.cc:81
DLItem::abort_dl
void abort_dl()
Definition: downloads.cc:441
DLItem::log_state
int log_state
Definition: downloads.cc:102
DLItem::init_time
time_t init_time
Definition: downloads.cc:104
ProgressBar::mMax
double mMax
Definition: downloads.cc:62
DLItemList::add
void add(DLItem *i)
Definition: downloads.cc:158
read_req_cb
static void read_req_cb(int req_fd, void *)
Definition: downloads.cc:834
ProgressBar::step
void step(double step)
Definition: downloads.cc:74
DLItem::shortname
char * shortname
Definition: downloads.cc:99
DlScroll::DlScroll
DlScroll(int x, int y, int w, int h, const char *l=0)
Definition: downloads.cc:1026
ProgressBar::mPresent
double mPresent
Definition: downloads.cc:63
ProgressBar::move
void move(double step)
Definition: downloads.cc:223
ProgressBar::showtext
void showtext(bool st)
Definition: downloads.cc:83
sh
static Dsh * sh
Definition: datauri.c:38
DLItemList::mNum
int mNum
Definition: downloads.cc:152
DLItem::init_bytesize
int init_bytesize
Definition: downloads.cc:108
dFree
void dFree(void *mem)
Definition: dlib.c:66
DLItem::UpdatesDone
int UpdatesDone
Definition: downloads.cc:109
Dsh
Definition: dpip.h:31
DLItem::twosec_bytesize
int twosec_bytesize
Definition: downloads.cc:107
dStrconcat
char * dStrconcat(const char *s1,...)
Definition: dlib.c:100
DLItem::group
Fl_Group * group
Definition: downloads.cc:113
DLItem::WidgetDone
int WidgetDone
Definition: downloads.cc:109
DLItem::DLItem
DLItem(const char *full_filename, const char *url)
Definition: downloads.cc:283
ProgressBar::maximum
void maximum(double nm)
Definition: downloads.cc:79
DLItem::prGot
Fl_Widget * prGot
Definition: downloads.cc:116
DLItem::update_prSize
void update_prSize(int newsize)
Definition: downloads.cc:475
dStrerror
#define dStrerror
Definition: dlib.h:95
DLItem::log_len
size_t log_len
Definition: downloads.cc:101
ProgressBar::draw
void draw()
Definition: downloads.cc:242
DLWin
Definition: downloads.cc:165
read_log_cb
static void read_log_cb(int fd_in, void *data)
Definition: downloads.cc:605
ProgressBar::message
void message(char *msg)
Definition: downloads.cc:84
DLItem::~DLItem
~DLItem()
Definition: downloads.cc:424
caught_sigchld
volatile sig_atomic_t caught_sigchld
Definition: downloads.cc:214
Escape_uri_str
char * Escape_uri_str(const char *str, const char *p_esc_set)
Definition: dpiutil.c:36
H
#define H(x, y, z)
DLItem::child_finished
void child_finished(int status)
Definition: downloads.cc:644
mask_sigchld
sigset_t mask_sigchld
Definition: downloads.cc:211
DLItemList::mMax
int mMax
Definition: downloads.cc:152
ProgressBar::position
void position(double pos)
Definition: downloads.cc:82
DLItem::ST_number
Definition: downloads.cc:94
dStrndup
char * dStrndup(const char *s, size_t sz)
Definition: dlib.c:86
DLItem::widget_done
void widget_done(int val)
Definition: downloads.cc:134
MSG
#define MSG(...)
Definition: downloads.cc:51
a_Dpip_dsh_read_token
char * a_Dpip_dsh_read_token(Dsh *dsh, int blocking)
Definition: dpip.c:488
DLItem::get_widget
Fl_Widget * get_widget()
Definition: downloads.cc:132
ProgressBar::text_color
void text_color(Fl_Color col)
Definition: downloads.cc:86
DLWin::mPG
Fl_Pack * mPG
Definition: downloads.cc:169
DLItem::curr_bytesize
int curr_bytesize
Definition: downloads.cc:108
lout::misc::max
T max(T a, T b)
Definition: misc.hh:20
custLabelDraw
static void custLabelDraw(const Fl_Label *o, int X, int Y, int W, int H, Fl_Align align)
Definition: downloads.cc:1074
ProgressBar::position
double position()
Definition: downloads.cc:80
lout::misc::min
T min(T a, T b)
Definition: misc.hh:19
DLItemList
BUG: make dynamic.
Definition: downloads.cc:150
DLWin::abort_all
void abort_all()
Definition: downloads.cc:999
DLItem::prRate
Fl_Widget * prRate
Definition: downloads.cc:116
prButton_scb
static void prButton_scb(Fl_Widget *, void *cb_data)
Definition: downloads.cc:276
DLItem::prTitle
Fl_Widget * prTitle
Definition: downloads.cc:116
a_Dpip_get_attr
char * a_Dpip_get_attr(const char *tag, const char *attrname)
Definition: dpip.c:187
DLItem::DataDone
int DataDone
Definition: downloads.cc:109
a_Dpip_check_auth
int a_Dpip_check_auth(const char *auth_tag)
Definition: dpip.c:196
update_cb
static void update_cb(void *data)
Definition: downloads.cc:804
DLWin::DLWin
DLWin(int ww, int wh)
Definition: downloads.cc:1035
DLItem::prETAt
Fl_Widget * prETAt
Definition: downloads.cc:116
DLItemList::mList
DLItem * mList[32]
Definition: downloads.cc:151
DLItem::onesec_time
time_t onesec_time
Definition: downloads.cc:106
DLItem::twosec_time
time_t twosec_time
Definition: downloads.cc:106
DLItem::gw
int gw
Definition: downloads.cc:112
DLItem
Definition: downloads.cc:92
DLItem::fullname
char * fullname
Definition: downloads.cc:99
DLItem::wget_status
int wget_status()
Definition: downloads.cc:141
DlScroll::resize
void resize(int x_, int y_, int w_, int h_)
Definition: downloads.cc:1012
dl_win
static class DLWin * dl_win
Definition: downloads.cc:217
DLItem::log_max
size_t log_max
Definition: downloads.cc:101
DLItem::pr_Rate
Fl_Widget * pr_Rate
Definition: downloads.cc:116
dClose
int dClose(int fd)
Definition: dlib.c:949
dRealloc
void * dRealloc(void *mem, size_t size)
Definition: dlib.c:51
DLItem::onesec_bytesize
int onesec_bytesize
Definition: downloads.cc:107
DLWin::show
void show()
Definition: downloads.cc:178
ProgressBar::ProgressBar
ProgressBar(int x, int y, int w, int h, const char *lbl=0)
Definition: downloads.cc:231
DLItem::widget_done
int widget_done()
Definition: downloads.cc:133
DLItem::pid
void pid(pid_t p)
Definition: downloads.cc:129
DLItemList::DLItemList
DLItemList()
Definition: downloads.cc:155
ProgressBar::minimum
double minimum()
Definition: downloads.cc:76
ProgressBar::maximum
double maximum()
Definition: downloads.cc:77
a_Dpip_dsh_free
void a_Dpip_dsh_free(Dsh *dsh)
Definition: dpip.c:520
ProgressBar::mTextColor
Fl_Color mTextColor
Definition: downloads.cc:67
DLItemList::get
DLItem * get(int n)
Definition: downloads.cc:159
DLItem::prETA
Fl_Widget * prETA
Definition: downloads.cc:116
DLItem::gh
int gh
Definition: downloads.cc:112
DLWin::listen
void listen(int req_fd)
Definition: downloads.cc:991
DLItem::child_init
void child_init()
Definition: downloads.cc:460
est_sigchld
static void est_sigchld(void)
Definition: downloads.cc:760
dGethomedir
char * dGethomedir()
Definition: dlib.c:904
ProgressBar::mMsg
char mMsg[64]
Definition: downloads.cc:66
DLItem::wget_status
void wget_status(int val)
Definition: downloads.cc:142
ProgressBar
Definition: downloads.cc:59
DLWin::num_running
int num_running()
Definition: downloads.cc:978
DLItem::updates_done
void updates_done(int val)
Definition: downloads.cc:136
DLItem::prButton_cb
void prButton_cb()
Definition: downloads.cc:454
DLWin::mDList
DLItemList * mDList
Definition: downloads.cc:166
DLItem::prButton
Fl_Button * prButton
Definition: downloads.cc:115
dpiutil.h
DLWin::add
void add(const char *full_filename, const char *url)
Definition: downloads.cc:927
secs2timestr
static void secs2timestr(int et, char *str)
Definition: downloads.cc:668
DLItem::ST_discard
Definition: downloads.cc:94
DLWin::num
int num()
Definition: downloads.cc:970
ProgressBar::text_color
Fl_Color text_color()
Definition: downloads.cc:87
ProgressBar::mShowMsg
bool mShowMsg
Definition: downloads.cc:65
Filter_smtp_hack
char * Filter_smtp_hack(char *url)
Definition: dpiutil.c:148
DLItemList::~DLItemList
~DLItemList()
Definition: downloads.cc:156
escape_tooltip
static char * escape_tooltip(const char *buf, ssize_t len)
Definition: downloads.cc:187
DLItem::log_text_add
void log_text_add(const char *buf, ssize_t st)
Definition: downloads.cc:486
DLItem::log_text_show
void log_text_show()
Definition: downloads.cc:568
DLItemList::del
void del(int n)
Definition: downloads.cc:160
DLItem::prSize
Fl_Widget * prSize
Definition: downloads.cc:116
DLItem::ForkDone
int ForkDone
Definition: downloads.cc:109
DLItem::father_init
void father_init()
Definition: downloads.cc:631
DLItem::update
void update()
Definition: downloads.cc:686
DLItem::LogPipe
int LogPipe[2]
Definition: downloads.cc:98
raw_sigchld
static void raw_sigchld(int)
Definition: downloads.cc:754
DLItem::log_text
char * log_text
Definition: downloads.cc:103
DLItem::dl_argv
char ** dl_argv
Definition: downloads.cc:105
DLItem::LogDone
int LogDone
Definition: downloads.cc:109
DLItem::mPid
pid_t mPid
Definition: downloads.cc:97
DLItem::WgetStatus
int WgetStatus
Definition: downloads.cc:110
DLWin::hide
void hide()
Definition: downloads.cc:179
a_Dpip_dsh_close
void a_Dpip_dsh_close(Dsh *dsh)
Definition: dpip.c:499
DLItem::ST_newline
Definition: downloads.cc:94
dlwin_esc_cb
static void dlwin_esc_cb(Fl_Widget *, void *)
Definition: downloads.cc:907
ProgressBar::mMin
double mMin
Definition: downloads.cc:61
DLItem::prBar
ProgressBar * prBar
Definition: downloads.cc:114
ProgressBar::showtext
bool showtext()
Definition: downloads.cc:85
ProgressBar::minimum
void minimum(double nm)
Definition: downloads.cc:78
dStrdup
char * dStrdup(const char *s)
Definition: dlib.c:75
DLWin::mWin
Fl_Window * mWin
Definition: downloads.cc:167
DLWin::mScroll
Fl_Scroll * mScroll
Definition: downloads.cc:168
ProgressBar::mStep
double mStep
Definition: downloads.cc:64
main
int main()
Definition: downloads.cc:1097
ProgressBar::mShowPct
bool mShowPct
Definition: downloads.cc:65
ProgressBar::range
void range(double min, double max, double step=1)
Definition: downloads.cc:71
DLItem::update_size
void update_size(int new_sz)
Definition: downloads.cc:573
custLabelMeasure
static void custLabelMeasure(const Fl_Label *o, int &W, int &H)
Definition: downloads.cc:1085
DLItem::log_done
int log_done()
Definition: downloads.cc:139
DLItem::ST_copy
Definition: downloads.cc:94
DLItem::total_bytesize
int total_bytesize
Definition: downloads.cc:108
DLItem::log_done
void log_done(int val)
Definition: downloads.cc:140
dStrnAsciiCasecmp
int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
Definition: dlib.c:213
cleanup_cb
static void cleanup_cb(void *data)
Definition: downloads.cc:778
_MSG
#define _MSG(...)
Definition: downloads.cc:50
DLItem::pid
pid_t pid()
Definition: downloads.cc:128
DLItem::fork_done
int fork_done()
Definition: downloads.cc:137
DLItem::fork_done
void fork_done(int val)
Definition: downloads.cc:138