28#include <sys/socket.h>
35#include <FL/fl_draw.H>
36#include <FL/Fl_File_Chooser.H>
37#include <FL/Fl_Window.H>
38#include <FL/Fl_Widget.H>
39#include <FL/Fl_Group.H>
40#include <FL/Fl_Scroll.H>
41#include <FL/Fl_Pack.H>
43#include <FL/Fl_Button.H>
47#include "../dpip/dpip.h"
53#define MSG(...) printf("[downloads dpi]: " __VA_ARGS__)
61class ProgressBar :
public Fl_Box {
67 bool mShowPct, mShowMsg;
72 ProgressBar(
int x,
int y,
int w,
int h,
const char *lbl = 0);
73 void range(
double min,
double max,
double step = 1) {
74 mMin = min; mMax = max; mStep = step;
76 void step(
double step) { mPresent += step; redraw(); };
77 void move(
double step);
78 double minimum() {
return mMin; }
79 double maximum() {
return mMax; }
80 void minimum(
double nm) { mMin = nm; };
81 void maximum(
double nm) { mMax = nm; };
82 double position () {
return mPresent; }
83 double step() {
return mStep; }
84 void position(
double pos) { mPresent = pos; redraw(); }
85 void showtext(
bool st) { mShowPct = st; }
86 void message(
char *msg) { mShowMsg =
true; strncpy(mMsg,msg,63); redraw(); }
87 bool showtext() {
return mShowPct; }
88 void text_color(Fl_Color col) { mTextColor = col; }
89 Fl_Color text_color() {
return mTextColor; }
96 ST_newline, ST_number, ST_discard, ST_copy
101 char *shortname, *fullname;
105 size_t log_len, log_max;
110 time_t twosec_time, onesec_time;
111 int twosec_bytesize, onesec_bytesize;
112 int init_bytesize, curr_bytesize, total_bytesize;
113 int DataDone, LogDone, ForkDone, UpdatesDone, WidgetDone;
120 Fl_Widget *prTitle, *prGot, *prSize, *prRate, *pr_Rate, *prETA, *prETAt;
123 DLItem(
const char *full_filename,
const char *url,
const char *user_agent);
127 void update_size(
int new_sz);
128 void log_text_add(
const char *buf, ssize_t st);
129 void log_text_show();
132 pid_t pid() {
return mPid; }
133 void pid(pid_t p) { mPid = p; }
134 void child_finished(
int status);
135 void status_msg(
const char *msg) { prBar->message((
char*)msg); }
136 Fl_Widget *get_widget() {
return group; }
137 int widget_done() {
return WidgetDone; }
138 void widget_done(
int val) { WidgetDone = val; }
139 int updates_done() {
return UpdatesDone; }
140 void updates_done(
int val) { UpdatesDone = val; }
141 int fork_done() {
return ForkDone; }
142 void fork_done(
int val) { ForkDone = val; }
143 int log_done() {
return LogDone; }
144 void log_done(
int val) { LogDone = val; }
145 int wget_status() {
return WgetStatus; }
146 void wget_status(
int val) { WgetStatus = val; }
147 void update_prSize(
int newsize);
159 DLItemList() { mNum = 0; mMax = 32; }
161 int num() {
return mNum; }
162 void add(DLItem *i) {
if (mNum < mMax) mList[mNum++] = i; }
163 DLItem *get(
int n) {
return (n >= 0 && n < mNum) ? mList[n] : NULL; }
164 void del(
int n) {
if (n >= 0 && n < mNum) mList[n] = mList[--mNum]; }
176 DLWin(
int ww,
int wh);
177 void add(
const char *full_filename,
const char *url,
const char *user_agent);
178 void del(
int n_item);
181 void listen(
int req_fd);
182 void show() { mWin->show(); }
183 void hide() { mWin->hide(); }
196 char *ret = (
char *) malloc(2 * len + 1);
227void ProgressBar::move(
double step)
235ProgressBar::ProgressBar(
int x,
int y,
int w,
int h,
const char *lbl)
236: Fl_Box(x, y, w, h, lbl)
246void ProgressBar::draw()
254 Rectangle r = {x(), y(), w(), h()};
259 double pct = (mPresent - mMin) / mMax;
261 r.w = r.w * pct + .5;
262 fl_rectf(r.x, r.y, r.w, r.h, FL_BLUE);
266 fl_font(this->labelfont(), this->labelsize());
267 fl_draw(mMsg, x(), y(), w(), h(), FL_ALIGN_CENTER);
268 }
else if (mShowPct) {
270 sprintf(buffer,
"%d%%",
int (pct * 100 + .5));
272 fl_font(this->labelfont(), this->labelsize());
273 fl_draw(buffer, x(), y(), w(), h(), FL_ALIGN_CENTER);
282 DLItem *i = (DLItem *)cb_data;
287DLItem::DLItem(
const char *full_filename,
const char *url,
const char *user_agent)
292 if (pipe(LogPipe) < 0) {
297 fcntl(LogPipe[0], F_SETFL,
298 O_NONBLOCK | fcntl(LogPipe[0], F_GETFL));
300 fullname =
dStrdup(full_filename);
301 p = strrchr(fullname,
'/');
303 p = strrchr(full_filename,
'/');
304 target_dir= p ?
dStrndup(full_filename,p-full_filename+1) :
dStrdup(
"??");
308 log_state = ST_newline;
310 onesec_bytesize = twosec_bytesize = curr_bytesize = init_bytesize = 0;
314 init_time = time(NULL);
316 twosec_time = onesec_time = init_time;
328 if (stat(fullname, &ss) == 0)
329 init_bytesize = (
int)ss.st_size;
331 dl_argv[i++] = (
char*) user_agent;
333 dl_argv[i++] = (
char*)
"--load-cookies";
348 group =
new Fl_Group(0,0,gw,gh);
350 prTitle =
new Fl_Box(24, 7, 290, 23);
351 prTitle->box(FL_RSHADOW_BOX);
352 prTitle->color(FL_WHITE);
353 prTitle->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP);
354 prTitle->copy_label(shortname);
356 log_text_add(
"Target File: ", 13);
357 log_text_add(fullname, strlen(fullname));
358 log_text_add(
"\n\n", 2);
360 prBar =
new ProgressBar(24, 40, 92, 20);
361 prBar->box(FL_THIN_UP_BOX);
362 prBar->tooltip(
"Progress Status");
364 int ix = 122, iy = 37, iw = 50, ih = 14;
365 Fl_Widget *o =
new Fl_Box(ix,iy,iw,ih,
"Got");
366 o->box(FL_RFLAT_BOX);
369 o->tooltip(
"Downloaded Size");
370 prGot =
new Fl_Box(ix,iy+14,iw,ih,
"0KB");
371 prGot->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
372 prGot->labelcolor(FL_BLUE);
373 prGot->labelsize(12);
374 prGot->box(FL_NO_BOX);
377 o =
new Fl_Box(ix,iy,iw,ih,
"Size");
378 o->box(FL_RFLAT_BOX);
381 o->tooltip(
"Total Size");
382 prSize =
new Fl_Box(ix,iy+14,iw,ih,
"??");
383 prSize->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
384 prSize->labelsize(12);
385 prSize->box(FL_NO_BOX);
388 o =
new Fl_Box(ix,iy,iw,ih,
"Rate");
389 o->box(FL_RFLAT_BOX);
392 o->tooltip(
"Current transfer Rate (KBytes/sec)");
393 prRate =
new Fl_Box(ix,iy+14,iw,ih,
"??");
394 prRate->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
395 prRate->labelsize(12);
396 prRate->box(FL_NO_BOX);
399 o =
new Fl_Box(ix,iy,iw,ih,
"~Rate");
400 o->box(FL_RFLAT_BOX);
403 o->tooltip(
"Average transfer Rate (KBytes/sec)");
404 pr_Rate =
new Fl_Box(ix,iy+14,iw,ih,
"??");
405 pr_Rate->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
406 pr_Rate->labelsize(12);
407 pr_Rate->box(FL_NO_BOX);
410 prETAt = o =
new Fl_Box(ix,iy,iw,ih,
"ETA");
411 o->box(FL_RFLAT_BOX);
414 o->tooltip(
"Estimated Time of Arrival");
415 prETA =
new Fl_Box(ix,iy+14,iw,ih,
"??");
416 prETA->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
417 prETA->labelsize(12);
418 prETA->box(FL_NO_BOX);
420 prButton =
new Fl_Button(326, 9, 44, 19,
"Stop");
421 prButton->tooltip(
"Stop this transfer");
422 prButton->box(FL_UP_BOX);
423 prButton->clear_visible_focus();
426 group->box(FL_ROUNDED_BOX);
446void DLItem::abort_dl()
450 Fl::remove_fd(LogPipe[0]);
454 kill(pid(), SIGTERM);
459void DLItem::prButton_cb()
461 prButton->deactivate();
465void DLItem::child_init()
472 setenv(
"LC_ALL",
"C", 1);
480void DLItem::update_prSize(
int newsize)
484 if (newsize > 1024 * 1024)
485 snprintf(num, 64,
"%.1fMB", (
float)newsize / (1024*1024));
487 snprintf(num, 64,
"%.0fKB", (
float)newsize / 1024);
488 prSize->copy_label(num);
491void DLItem::log_text_add(
const char *buf, ssize_t st)
494 char *esc_str, *q, *d, num[64];
499 esc_len = strlen(esc_str);
502 if (log_len + esc_len >= log_max) {
503 log_max = log_len + esc_len + 1024;
504 log_text = (
char *)
dRealloc (log_text, log_max);
505 log_text[log_len] = 0;
506 prTitle->tooltip(log_text);
510 q = log_text + log_len;
511 for (p = esc_str; (size_t)(p - esc_str) < esc_len; ++p) {
515 log_state = ST_discard;
516 }
else if (isdigit(*p)) {
517 *q++ = *p; log_state = ST_number;
518 }
else if (*p ==
'\n') {
521 *q++ = *p; log_state = ST_copy;
525 if (isdigit(*q++ = *p)) {
527 }
else if (*p ==
'K') {
528 for (--q; isdigit(q[-1]); --q) ;
529 log_state = ST_discard;
536 log_state = ST_newline;
539 if ((*q++ = *p) ==
'\n')
540 log_state = ST_newline;
545 log_len = strlen(log_text);
550 if (total_bytesize == -1) {
551 p = strstr(log_text,
"\nLength: ");
552 if (p && isdigit(p[9]) && strchr(p + 9,
' ')) {
553 for (p += 9, d = &num[0]; *p !=
' '; ++p)
557 total_bytesize = strtol (num, NULL, 10);
559 update_prSize(total_bytesize);
568 if (curr_bytesize == 0) {
569 prTitle->copy_label(
"Connecting...");
574void DLItem::log_text_show()
576 MSG(
"\nStored Log:\n%s", log_text);
579void DLItem::update_size(
int new_sz)
583 if (curr_bytesize == 0 && new_sz) {
585 init_time = time(NULL);
587 prTitle->copy_label(shortname);
593 curr_bytesize = new_sz;
594 if (curr_bytesize > 1024 * 1024)
595 snprintf(buf, 64,
"%.1fMB", (
float)curr_bytesize / (1024*1024));
597 snprintf(buf, 64,
"%.0fKB", (
float)curr_bytesize / 1024);
598 prGot->copy_label(buf);
599 if (total_bytesize == -1) {
600 prBar->showtext(
false);
603 prBar->showtext(
true);
605 if (total_bytesize > 0)
606 pos *= (double)curr_bytesize / total_bytesize;
607 prBar->position(pos);
613 DLItem *dl_item = (DLItem *)data;
614 const int BufLen = 4096;
619 st = read(fd_in, Buf, BufLen);
621 if (errno == EAGAIN) {
626 }
else if (st == 0) {
628 Fl::remove_fd(fd_in, 1);
629 dl_item->log_done(1);
632 dl_item->log_text_add(Buf, st);
637void DLItem::father_init()
650void DLItem::child_finished(
int status)
655 prButton->label(
"Done");
656 prButton->tooltip(
"Close this information panel");
658 prButton->label(
"Close");
659 prButton->tooltip(
"Close this information panel");
660 status_msg(
"ABORTED");
661 if (curr_bytesize == 0) {
663 prTitle->copy_label(shortname);
666 prButton->activate();
668 MSG(
"wget status %d\n", status);
678 eh = et / 3600; em = (et % 3600) / 60; es = et % 60;
681 snprintf(str, 16,
"%ds", es);
683 snprintf(str, 16,
"%dm%ds", em, es);
685 snprintf(str, 16,
"%dh%dm", eh, em);
696 float csec, tsec, rate, _rate = 0;
704 if (stat(fullname, &ss) == -1) {
708 update_size((
int)ss.st_size);
712 csec = (float) (curr_time - init_time);
716 tsec = (float) (curr_time - twosec_time);
717 rate = ((float)(curr_bytesize-twosec_bytesize) / 1024) / tsec;
718 snprintf(str, 64, (rate < 100) ?
"%.1fK/s" :
"%.0fK/s", rate);
719 prRate->copy_label(str);
723 _rate = ((float)(curr_bytesize-init_bytesize) / 1024) / csec;
724 snprintf(str, 64, (_rate < 100) ?
"%.1fK/s" :
"%.0fK/s", _rate);
725 pr_Rate->copy_label(str);
731 prETAt->label(
"Time");
732 prETAt->tooltip(
"Download Time");
735 prETA->copy_label(str);
736 if (total_bytesize == -1) {
737 update_prSize(curr_bytesize);
738 if (wget_status() == 0)
742 if (_rate > 0 && total_bytesize > 0 && curr_bytesize > 0) {
743 et = (int)((total_bytesize-curr_bytesize) / (_rate * 1024));
745 prETA->copy_label(str);
750 twosec_time = onesec_time;
751 onesec_time = curr_time;
752 twosec_bytesize = onesec_bytesize;
753 onesec_bytesize = curr_bytesize;
768 struct sigaction sigact;
771 (void) sigemptyset(&set);
773 sigact.sa_mask = set;
774 sigact.sa_flags = SA_NOCLDSTOP;
775 if (sigaction(SIGCHLD, &sigact, NULL) == -1) {
786 DLItemList *list = (DLItemList *)data;
792 for (i = 0; i < list->num(); ++i) {
793 if (!list->get(i)->fork_done() &&
794 waitpid(list->get(i)->pid(), &status, WNOHANG) > 0) {
795 list->get(i)->child_finished(status);
796 list->get(i)->fork_done(1);
812 static int cb_used = 0;
814 DLItemList *list = (DLItemList *)data;
817 for (
int i = 0; i < list->num(); ++i) {
818 if (!list->get(i)->widget_done()) {
819 list->get(i)->update();
820 }
else if (list->get(i)->fork_done()) {
827 if (cb_used && list->num() == 0)
842 struct sockaddr_un clnt_addr;
846 char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *dl_dest = NULL, *ua = NULL;
849 csz =
sizeof(
struct sockaddr_un);
852 sock_fd = accept(req_fd, (
struct sockaddr *) &clnt_addr, &csz);
853 }
while (sock_fd == -1 && errno == EINTR);
865 MSG(
"can't authenticate request: %s fd=%d\n",
dStrerror(errno), sock_fd);
873 MSG(
"can't read request: %s fd=%d\n",
dStrerror(errno), sock_fd);
878 _MSG(
"Received tag={%s}\n", dpip_tag);
881 MSG(
"Failed to parse 'cmd' in {%s}\n", dpip_tag);
884 if (strcmp(cmd,
"DpiBye") == 0) {
885 MSG(
"got DpiBye, ignoring...\n");
888 if (strcmp(cmd,
"download") != 0) {
889 MSG(
"unknown command: '%s'. Aborting.\n", cmd);
893 MSG(
"Failed to parse 'url' in {%s}\n", dpip_tag);
897 MSG(
"Failed to parse 'destination' in {%s}\n", dpip_tag);
901 MSG(
"Failed to parse 'user-agent' in {%s}\n", dpip_tag);
904 dl_win->add(dl_dest, url, ua);
919 const char *msg =
"There are running downloads.\n"
920 "ABORT them and EXIT anyway?";
923 fl_message_title(
"Dillo Downloads: Abort downloads?");
924 int ch = fl_choice(
"%s",
"Cancel",
"*No",
"Yes", msg);
925 if (ch == 0 || ch == 1)
937void DLWin::add(
const char *full_filename,
const char *url,
const char *user_agent)
939 DLItem *dl_item =
new DLItem(full_filename, url, user_agent);
940 mDList->add(dl_item);
941 mPG->insert(*dl_item->get_widget(), 0);
943 _MSG(
"Child index = %d\n", mPG->find(dl_item->get_widget()));
946 pid_t f_pid = fork();
949 dl_item->child_init();
951 }
else if (f_pid < 0) {
956 dl_item->get_widget()->show();
959 dl_item->father_init();
966void DLWin::del(
int n_item)
968 DLItem *dl_item = mDList->get(n_item);
971 mPG->remove(dl_item->get_widget());
982 return mDList->num();
988int DLWin::num_running()
992 for (i = nr = 0; i < mDList->num(); ++i)
993 if (!mDList->get(i)->fork_done())
1001void DLWin::listen(
int req_fd)
1009void DLWin::abort_all()
1011 for (
int i = 0; i < mDList->num(); ++i)
1012 mDList->get(i)->abort_dl();
1019class DlScroll :
public Fl_Scroll
1022 void resize(
int x_,
int y_,
int w_,
int h_)
1024 Fl_Scroll::resize(x_, y_, w_, h_);
1025 Fl_Widget *resizable_ = resizable();
1027 resizable_->h() <= h() ? 0 :
1028 scrollbar_size() ? scrollbar_size() :
1029 Fl::scrollbar_size();
1031 resizable_->resize(resizable_->x(),
1036 DlScroll(
int x,
int y,
int w,
int h,
const char *l = 0)
1037 : Fl_Scroll(x, y, w, h, l)
1045DLWin::DLWin(
int ww,
int wh) {
1048 mDList =
new DLItemList();
1051 mWin =
new Fl_Window(ww, wh,
"Dillo Downloads");
1053 mScroll =
new DlScroll(0,0,ww,wh);
1055 mPG =
new Fl_Pack(0,0,ww-18,wh);
1058 mScroll->type(Fl_Scroll::VERTICAL);
1059 mScroll->resizable(mPG);
1061 mWin->resizable(mScroll);
1070 fl_message_title_default(
"Dillo Downloads: Message");
1075 Fl::add_timeout(1.0,
update_cb, mDList);
1087 const int interpret_symbols = 0;
1089 fl_draw_shortcut = 0;
1090 fl_font(o->font, o->size);
1091 fl_color((Fl_Color)o->color);
1092 fl_draw(o->value, X, Y, W,
H, align, o->image, interpret_symbols);
1097 const int interpret_symbols = 0;
1099 fl_draw_shortcut = 0;
1100 fl_font(o->font, o->size);
1101 fl_measure(o->value, W,
H, interpret_symbols);
1109 int ww = 420, wh = 85;
1119 dl_win =
new DLWin(ww, wh);
1122 dl_win->listen(STDIN_FILENO);
1124 MSG(
"started...\n");
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
char * dStrdup(const char *s)
int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
int dClose(int fd)
Close a FD handling EINTR.
char * dStrndup(const char *s, size_t sz)
void * dRealloc(void *mem, size_t size)
char * dGethomedir(void)
Return the home directory in a static string (don't free)
static void custLabelMeasure(const Fl_Label *o, int &W, int &H)
static void read_log_cb(int fd_in, void *data)
static void raw_sigchld(int)
static void est_sigchld(void)
static void custLabelDraw(const Fl_Label *o, int X, int Y, int W, int H, Fl_Align align)
volatile sig_atomic_t caught_sigchld
static void secs2timestr(int et, char *str)
static char * escape_tooltip(const char *buf, ssize_t len)
static void cleanup_cb(void *data)
static void read_req_cb(int req_fd, void *)
static void prButton_scb(Fl_Widget *, void *cb_data)
static class DLWin * dl_win
static void update_cb(void *data)
static void dlwin_esc_cb(Fl_Widget *, void *)
void a_Dpip_dsh_free(Dsh *dsh)
Free the SockHandler structure.
char * a_Dpip_get_attr(const char *tag, const char *attrname)
Task: given a tag and an attribute name, return its value.
char * a_Dpip_dsh_read_token(Dsh *dsh, int blocking)
Return a newlly allocated string with the next dpip token in the socket.
void a_Dpip_dsh_close(Dsh *dsh)
Close this socket for reading and writing.
int a_Dpip_check_auth(const char *auth_tag)
Check whether the given 'auth' string equals what dpid saved.
Dsh * a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
Create and initialize a dpip socket handler.
char * Filter_smtp_hack(char *url)
char * Escape_uri_str(const char *str, const char *p_esc_set)
Dpip socket handler type.