📄 downloads.cc
字号:
/* * File: downloads.cc * * Copyright (C) 2005 Jorge Arellano Cid <jcid@dillo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * A FLTK2-based GUI for the downloads dpi (dillo plugin). */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <ctype.h>#include <math.h>#include <time.h>#include <signal.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/un.h>#include <sys/wait.h>#include <glib.h>#include <fltk/run.h>#include <fltk/Window.h>#include <fltk/Widget.h>#include <fltk/damage.h>#include <fltk/Box.h>#include <fltk/draw.h>#include <fltk/HighlightButton.h>#include <fltk/PackedGroup.h>#include <fltk/ScrollGroup.h>#include <fltk/ask.h>#include <fltk/file_chooser.h>#include "dpiutil.h"#include "../dpip/dpip.h"using namespace fltk;/* * Debugging macros */#define _MSG(fmt...)#define MSG(fmt...) g_print("[downloads dpi]: " fmt)/* * Internal types */typedef enum { DL_NEWFILE, DL_CONTINUE, DL_RENAME, DL_OVERWRITE, DL_ABORT} DLAction;/* * Class declarations */// ProgressBar widget --------------------------------------------------------// class FL_API ProgressBar : public Widget {class ProgressBar : public Widget {protected: double mMin; double mMax; double mPresent; double mStep; bool mShowPct, mShowMsg; char mMsg[64]; Color mTextColor; void draw();public: ProgressBar(int x, int y, int w, int h, const char *lbl = 0); void range(double min, double max, double step = 1) { mMin = min; mMax = max; mStep = step; }; void step(double step) { mPresent += step; redraw(); }; void move(double step); double minimum() { return mMin; } double maximum() { return mMax; } void minimum(double nm) { mMin = nm; }; void maximum(double nm) { mMax = nm; }; double position () { return mPresent; } double step() { return mStep; } void position(double pos) { mPresent = pos; redraw(); } void showtext(bool st) { mShowPct = st; } void message(char *msg) { mShowMsg = true; strncpy(mMsg,msg,63); redraw(); } bool showtext() { return mShowPct; } void text_color(Color col) { mTextColor = col; } Color text_color() { return mTextColor; }};// Download-item class -------------------------------------------------------class DLItem { enum { ST_newline, ST_number, ST_discard, ST_copy }; pid_t mPid; int LogPipe[2]; char *shortname, *fullname; char *target_dir; int log_len, log_max, log_state; char *log_text; time_t init_time; char **dl_argv; time_t twosec_time, onesec_time; int twosec_bytesize, onesec_bytesize; int init_bytesize, curr_bytesize, total_bytesize; int DataDone, LogDone, ForkDone, UpdatesDone, WidgetDone; int WgetStatus; int gw, gh; Group *group; ProgressBar *prBar; HighlightButton *prButton; Widget *prTitle, *prGot, *prSize, *prRate, *pr_Rate, *prETA, *prETAt;public: DLItem(const char *full_filename, const char *url, DLAction action); ~DLItem(); void child_init(); void father_init(); void update_size(int new_sz); void log_text_add(char *buf, ssize_t st); void log_text_show(); void abort_dl(); void prButton_cb(); pid_t pid() { return mPid; } void pid(pid_t p) { mPid = p; } void child_finished(int status); void status_msg(char *msg) { prBar->message(msg); } Widget *get_widget() { return group; } int widget_done() { return WidgetDone; } void widget_done(int val) { WidgetDone = val; } int updates_done() { return UpdatesDone; } void updates_done(int val) { UpdatesDone = val; } int fork_done() { return ForkDone; } void fork_done(int val) { ForkDone = val; } int log_done() { return LogDone; } void log_done(int val) { LogDone = val; } int wget_status() { return WgetStatus; } void wget_status(int val) { WgetStatus = val; } void update_prSize(int newsize); void update();};// DLItem List ---------------------------------------------------------------/// BUG: make dynamicclass DLItemList { DLItem *mList[32]; int mNum, mMax;public: DLItemList() { mNum = 0; mMax = 32; } ~DLItemList() { } int num() { return mNum; } void add(DLItem *i) { if (mNum < mMax) mList[mNum++] = i; } DLItem *get(int n) { return (n >= 0 && n < mNum) ? mList[n] : NULL; } void del(int n) { if (n >= 0 && n < mNum) mList[n] = mList[--mNum]; }};// DLWin ---------------------------------------------------------------------class DLWin { DLItemList *mDList; Window *mWin; ScrollGroup *mScroll; PackedGroup *mPG;public: DLWin(int ww, int wh); void add(const char *full_filename, const char *url, DLAction action); void del(int n_item); int num(); int num_running(); void listen(int req_fd); void show() { mWin->show(); } void hide() { mWin->hide(); } void abort_all(); DLAction check_filename(char **p_dl_dest);};/* * Global variables */// SIGCHLD masksigset_t mask_sigchld;// SIGCHLD flagvolatile sig_atomic_t caught_sigchld = 0;// The download window objectstatic class DLWin *dl_win = NULL;// ProgressBar widget --------------------------------------------------------void ProgressBar::move(double step){ mPresent += step; if (mPresent > mMax) mPresent = mMin; redraw();}ProgressBar::ProgressBar(int x, int y, int w, int h, const char *lbl): Widget(x, y, w, h, lbl){ mMin = mPresent = 0; mMax = 100; mShowPct = true; mShowMsg = false; box(DOWN_BOX); selection_color(BLUE); color(WHITE); textcolor(RED);}void ProgressBar::draw(){ drawstyle(style(), flags()); if (damage() & DAMAGE_ALL) draw_box(); Rectangle r(w(), h()); box()->inset(r); if (mPresent > mMax) mPresent = mMax; if (mPresent < mMin) mPresent = mMin; double pct = (mPresent - mMin) / mMax; if (vertical()) { int barHeight = int (r.h() * pct + .5); r.y(r.y() + r.h() - barHeight); r.h(barHeight); } else { r.w(int (r.w() * pct + .5)); } setcolor(selection_color()); if (mShowPct) { fillrect(r); } else { Rectangle r2(int (r.w() * pct), 0, int (w() * .1), h()); push_clip(r2); fillrect(r); pop_clip(); } if (mShowMsg) { setcolor(textcolor()); setfont(this->labelfont(), this->labelsize()); drawtext(mMsg, Rectangle(w(), h()), ALIGN_CENTER); } else if (mShowPct) { char buffer[30]; sprintf(buffer, "%d%%", int (pct * 100 + .5)); setcolor(textcolor()); setfont(this->labelfont(), this->labelsize()); drawtext(buffer, Rectangle(w(), h()), ALIGN_CENTER); }}// Download-item class -------------------------------------------------------static void prButton_scb(Widget *, void *cb_data){ DLItem *i = (DLItem *)cb_data; i->prButton_cb();}DLItem::DLItem(const char *full_filename, const char *url, DLAction action){ struct stat ss; char *p, *esc_url; if (pipe(LogPipe) < 0) { MSG("pipe, %s\n", strerror(errno)); return; } /* Set FD to background */ fcntl(LogPipe[0], F_SETFL, O_NONBLOCK | fcntl(LogPipe[0], F_GETFL)); fullname = strdup(full_filename); p = strrchr(fullname, '/'); shortname = (p) ? strdup(p + 1) : strdup("??"); p = strrchr(full_filename, '/'); target_dir= p ? g_strndup(full_filename,p-full_filename+1) : g_strdup("??"); log_len = 0; log_max = 0; log_state = ST_newline; log_text = NULL; onesec_bytesize = twosec_bytesize = curr_bytesize = init_bytesize = 0; total_bytesize = -1; // Init value. Reset later, upon the first data bytes arrival init_time = time(NULL); // BUG:? test a URL with ' inside. /* escape "'" character for the shell. Is it necessary? */ esc_url = Escape_uri_str(url, "'"); /* avoid malicious SMTP relaying with FTP urls */ if (g_strncasecmp(esc_url, "ftp:/", 5) == 0) Filter_smtp_hack(esc_url); dl_argv = new char*[8]; int i = 0; dl_argv[i++] = "wget"; if (action == DL_CONTINUE) { if (stat(fullname, &ss) == 0) init_bytesize = (int)ss.st_size; dl_argv[i++] = "-c"; } dl_argv[i++] = "--load-cookies"; dl_argv[i++] = g_strconcat(g_get_home_dir(), "/.dillo/cookies.txt", NULL); dl_argv[i++] = "-O"; dl_argv[i++] = fullname; dl_argv[i++] = esc_url; //g_strdup_printf("'%s'", esc_url); dl_argv[i++] = NULL; //g_free(esc_url); DataDone = 0; LogDone = 0; UpdatesDone = 0; ForkDone = 0; WidgetDone = 0; WgetStatus = -1; gw = 470, gh = 70; group = new Group(0,0,gw,gh); group->begin(); prTitle = new Widget(24, 7, 290, 23, shortname); prTitle->box(fltk::RSHADOW_BOX); prTitle->align(ALIGN_LEFT|ALIGN_INSIDE|ALIGN_CLIP); // Attach this 'log_text' to the tooltip log_text_add("Target File: ", 13); log_text_add(fullname, strlen(fullname)); log_text_add("\n\n", 2); prBar = new ProgressBar(24, 40, 92, 20); prBar->box(BORDER_BOX); // ENGRAVED_BOX prBar->tooltip("Progress Status"); int ix = 122, iy = 36, iw = 50, ih = 14; Widget *o = new Widget(ix,iy,iw,ih, "Got"); o->box(RFLAT_BOX); o->color((Color)0xc0c0c000); o->tooltip("Downloaded Size"); prGot = new Widget(ix,iy+14,iw,ih, "0KB"); prGot->labelcolor((Color)0x6c6cbd00); prGot->box(fltk::NO_BOX); ix += iw; o = new Widget(ix,iy,iw,ih, "Size"); o->box(RFLAT_BOX); o->color((Color)0xc0c0c000); o->tooltip("Total Size"); prSize = new Widget(ix,iy+14,iw,ih, "??"); prSize->box(fltk::NO_BOX); ix += iw; o = new Widget(ix,iy,iw,ih, "Rate"); o->box(RFLAT_BOX); o->color((Color)0xc0c0c000); o->tooltip("Current transfer Rate (KBytes/sec)"); prRate = new Widget(ix,iy+14,iw,ih, "??"); prRate->box(fltk::NO_BOX); ix += iw; o = new Widget(ix,iy,iw,ih, "~Rate"); o->box(RFLAT_BOX); o->color((Color)0xc0c0c000); o->tooltip("Average transfer Rate (KBytes/sec)"); pr_Rate = new Widget(ix,iy+14,iw,ih, "??"); pr_Rate->box(fltk::NO_BOX); ix += iw; prETAt = o = new Widget(ix,iy,iw,ih, "ETA"); o->box(RFLAT_BOX); o->color((Color)0xc0c0c000); o->tooltip("Estimated Time of Arrival"); prETA = new Widget(ix,iy+14,iw,ih, "??"); prETA->box(fltk::NO_BOX); //ix += 50; //prButton = new HighlightButton(ix, 41, 38, 19, "Stop"); prButton = new HighlightButton(328, 9, 38, 19, "Stop"); prButton->tooltip("Stop this transfer"); prButton->box(UP_BOX); prButton->clear_tab_to_focus(); prButton->callback(prButton_scb, this); //group->resizable(group); group->box(ROUND_UP_BOX); group->end();}DLItem::~DLItem(){ free(shortname); g_free(fullname); g_free(target_dir); free(log_text); int idx = (strcmp(dl_argv[1], "-c")) ? 2 : 3; g_free(dl_argv[idx]); g_free(dl_argv[idx+3]); delete(dl_argv); delete(group);}/* * Abort a running download */void DLItem::abort_dl(){ if (!log_done()) { close(LogPipe[0]); remove_fd(LogPipe[0]); log_done(1); // Stop wget if (!fork_done()) kill(pid(), SIGTERM); } widget_done(1);}void DLItem::prButton_cb(){ prButton->deactivate(); abort_dl();}void DLItem::child_init(){ close(0); // stdin close(1); // stdout close(LogPipe[0]); dup2(LogPipe[1], 2); // stderr // set the locale to C for log parsing setenv("LC_ALL", "C", 1); // start wget execvp(dl_argv[0], dl_argv);}/* * Update displayed size */void DLItem::update_prSize(int newsize){ char num[64]; if (newsize > 1024 * 1024) snprintf(num, 64, "%.1fMB", (float)newsize / (1024*1024)); else snprintf(num, 64, "%.0fKB", (float)newsize / 1024); prSize->copy_label(num); prSize->redraw();}void DLItem::log_text_add(char *buf, ssize_t st){ char *p, *q, *d, num[64]; // Make room... if (log_len + st >= log_max) { log_max = log_len + st + 1024; log_text = (char *) realloc (log_text, log_max); log_text[log_len] = 0; prTitle->tooltip(log_text); } // FSM to remove wget's "dot-progress" (i.e. "^ " || "^[0-9]+K") q = log_text + log_len; for (p = buf; (p - buf) < st; ++p) { switch (log_state) { case ST_newline: if (*p == ' ') { log_state = ST_discard; } else if (isdigit(*p)) { *q++ = *p; log_state = ST_number; } else if (*p == '\n') { *q++ = *p; } else { *q++ = *p; log_state = ST_copy; } break; case ST_number: if (isdigit(*q++ = *p)) { // keep here } else if (*p == 'K') { for(--q; isdigit(q[-1]); --q); log_state = ST_discard; } else { log_state = ST_copy; } break; case ST_discard: if (*p == '\n') log_state = ST_newline; break; case ST_copy: if ((*q++ = *p) == '\n') log_state = ST_newline; break; } } *q = 0; log_len = strlen(log_text); // Now scan for the length of the file if (total_bytesize == -1) { p = strstr(log_text, "\nLength: "); if (p && isdigit(p[9]) && strchr(p + 9, ' ')) { for (p += 9, d = &num[0]; *p != ' '; ++p) if (isdigit(*p)) *d++ = *p; *d = 0; total_bytesize = strtol (num, NULL, 10); // Update displayed size update_prSize(total_bytesize); } } // Show we're connecting... if (curr_bytesize == 0) { prTitle->label("Connecting..."); prTitle->redraw(); }}///void DLItem::log_text_show(){ fprintf(stderr, "\nStored Log:\n%s", log_text);}void DLItem::update_size(int new_sz){ char buf[64]; if (curr_bytesize == 0 && new_sz) { // Start the timer with the first bytes got init_time = time(NULL); // Update the title prTitle->label(shortname); prTitle->redraw();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -