#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <stdarg.h>
+#include <stdint.h>
#include <doldaconnect/uilib.h>
#include <doldaconnect/uimisc.h>
#include <doldaconnect/utils.h>
struct trinfo {
int ostate;
+ intmax_t opos, spos;
+ int speed;
+ time_t lastprog;
+ int warned;
+ double sprog;
};
void updatewrite(void);
+int remote = 0;
+char *server;
GtkStatusIcon *tray;
pid_t dpid = 0, dcpid = 0;
int connected = 0;
tr->udata = tri = memset(smalloc(sizeof(*tri)), 0, sizeof(*tri));
tr->destroycb = destroytr;
tri->ostate = tr->state;
+ tri->spos = tri->opos = tr->curpos;
+ tri->speed = -1;
+ tri->lastprog = time(NULL);
+ tri->sprog = ntime();
}
#ifdef HAVE_NOTIFY
}
#endif
+/* XXX: Achtung! Too DC-specific! */
+wchar_t *getfilename(wchar_t *path)
+{
+ wchar_t *p;
+
+ if((p = wcsrchr(path, L'\\')) == NULL)
+ return(path);
+ else
+ return(p + 1);
+}
+
+char *bytes2si(long long bytes)
+{
+ int i;
+ double b;
+ char *sd;
+ static char ret[64];
+
+ b = bytes;
+ for(i = 0; (b >= 1024) && (i < 4); i++)
+ b /= 1024;
+ if(i == 0)
+ sd = "B";
+ else if(i == 1)
+ sd = "kiB";
+ else if(i == 2)
+ sd = "MiB";
+ else if(i == 3)
+ sd = "GiB";
+ else
+ sd = "TiB";
+ snprintf(ret, 64, "%.1f %s", b, sd);
+ return(ret);
+}
+
+void updatetooltip(void)
+{
+ struct dc_transfer *tr;
+ struct trinfo *tri;
+ int t, i, a, st;
+ intmax_t bc, bt;
+ char *buf;
+ size_t bufsize, bufdata;
+
+ t = i = a = 0;
+ st = bc = bt = -1;
+ for(tr = dc_transfers; tr != NULL; tr = tr->next) {
+ if(tr->dir != DC_TRNSD_DOWN)
+ continue;
+ tri = tr->udata;
+ t++;
+ if(tr->state == DC_TRNS_WAITING)
+ i++;
+ else if((tr->state == DC_TRNS_HS) || (tr->state == DC_TRNS_MAIN))
+ a++;
+ if((tr->state == DC_TRNS_MAIN)) {
+ if(bt == -1)
+ bc = bt = 0;
+ bc += tr->curpos;
+ bt += tr->size;
+ if(tri->speed != -1) {
+ if(st == -1)
+ st = 0;
+ st += tri->speed;
+ }
+ }
+ }
+ buf = NULL;
+ bufsize = bufdata = 0;
+ bprintf(buf, "%s: %i", _("Transfers"), t);
+ if(t > 0)
+ bprintf(buf, " (%i/%i)", i, a);
+ if(bt > 0)
+ bprintf(buf, ", %.1f%%", ((double)bc / (double)bt) * 100.0);
+ if(st != -1)
+ bprintf(buf, ", %s/s", bytes2si(st));
+ addtobuf(buf, 0);
+ gtk_status_icon_set_tooltip(tray, buf);
+ free(buf);
+}
+
void trstatechange(struct dc_transfer *tr, int ostate)
{
- if(ostate == DC_TRNS_MAIN) {
+ struct trinfo *tri;
+
+ tri = tr->udata;
+ if((ostate == DC_TRNS_MAIN) && (tr->dir == DC_TRNSD_DOWN)) {
if(tr->state == DC_TRNS_DONE) {
#ifdef HAVE_NOTIFY
- notify(&trnote, "transfer.complete", _("Transfer complete"), _("Finished downloading %ls from %ls"), tr->path, tr->peernick);
+ if(dcpid == 0)
+ notify(&trnote, "transfer.complete", _("Transfer complete"), _("Finished downloading %ls from %ls"), getfilename(tr->path), tr->peernick);
#endif
} else {
#ifdef HAVE_NOTIFY
- notify(&trnote, "transfer.error", _("Transfer interrupted"), _("The transfer of %ls from %ls was interrupted from the other side"), tr->path, tr->peernick);
+ if(dcpid == 0)
+ notify(&trnote, "transfer.error", _("Transfer interrupted"), _("The transfer of %ls from %ls was interrupted from the other side"), getfilename(tr->path), tr->peernick);
#endif
}
}
+ if(tr->state == DC_TRNS_MAIN) {
+ tri->speed = -1;
+ tri->spos = tr->curpos;
+ tri->sprog = ntime();
+ }
}
void updatetrinfo(void)
{
struct dc_transfer *tr;
struct trinfo *tri;
+ time_t now;
+ double dnow;
+ now = time(NULL);
+ dnow = ntime();
for(tr = dc_transfers; tr != NULL; tr = tr->next) {
if(tr->udata == NULL) {
inittr(tr);
trstatechange(tr, tri->ostate);
tri->ostate = tr->state;
}
+ if(tri->opos != tr->curpos) {
+ tri->opos = tr->curpos;
+ tri->lastprog = now;
+ tri->warned = 0;
+ }
+#ifdef HAVE_NOTIFY
+ if((tr->state = DC_TRNS_MAIN) && (now - tri->lastprog > 600) && !tri->warned) {
+ if(dcpid == 0) {
+ notify(&trnote, "transfer.error", _("Transfer stalled"), _("The transfer of %ls from %ls has not made progress for 10 minutes"), getfilename(tr->path), tr->peernick);
+ tri->warned = 1;
+ }
+ }
+#endif
+ if((tr->state == DC_TRNS_MAIN) && (dnow - tri->sprog > 10)) {
+ tri->speed = ((double)(tr->curpos - tri->spos) / (dnow - tri->sprog));
+ tri->spos = tr->curpos;
+ tri->sprog = dnow;
+ }
}
}
+ updatetooltip();
}
void trlscb(int resp, void *data)
updatetrinfo();
}
+gint trupdatecb(gpointer data)
+{
+ updatetrinfo();
+ return(TRUE);
+}
+
void logincb(int err, wchar_t *reason, void *data)
{
if(err != DC_LOGIN_ERR_SUCCESS) {
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect to server"));
exit(1);
}
- gtk_status_icon_set_tooltip(tray, "Dolda Connect");
dc_queuecmd(NULL, NULL, L"notify", L"trans:act", L"on", L"trans:prog", L"on", NULL);
dc_gettrlistasync(trlscb, NULL);
connected = 1;
dc_uimisc_handlenotify(resp);
updatetrinfo();
}
+ dc_freeresp(resp);
}
updatewrite();
}
void connectdc(void)
{
- if((dcfd = dc_connect(dc_srv_local)) < 0) {
+ if((dcfd = dc_connect(server)) < 0) {
msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect to server: %s"), strerror(errno));
exit(1);
}
{
char pf[1024];
int pfd[2], i;
+ sigset_t ss;
if(getenv("HOME") != NULL)
snprintf(pf, sizeof(pf), "%s/.doldacond.pid", getenv("HOME"));
snprintf(pf, sizeof(pf), "%s/.doldacond.pid", getpwuid(getuid())->pw_dir);
if(access(pf, F_OK) || !running(pf)) {
pipe(pfd);
+ sigemptyset(&ss);
+ sigaddset(&ss, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &ss, NULL);
if((dpid = fork()) == 0) {
+ sigprocmask(SIG_UNBLOCK, &ss, NULL);
dup2(pfd[1], 2);
for(i = 3; i < FD_SETSIZE; i++)
close(i);
create_start_wnd();
gtk_widget_show(start_wnd);
gtk_status_icon_set_tooltip(tray, _("Starting..."));
+ sigprocmask(SIG_UNBLOCK, &ss, NULL);
} else {
connectdc();
}
if((dcpid = fork()) == 0) {
for(i = 3; i < FD_SETSIZE; i++)
close(i);
- execlp("dolcon", "dolcon", NULL);
+ if(remote)
+ execlp("dolcon", "dolcon", NULL);
+ else
+ execlp("dolcon", "dolcon", "-l", NULL);
perror("dolcon");
exit(127);
}
}
+void cb_shm_dolconf_activate(GtkWidget *uu1, gpointer uu2)
+{
+ int i;
+
+ if((dcpid = fork()) == 0) {
+ for(i = 3; i < FD_SETSIZE; i++)
+ close(i);
+ execlp("dolconf", "dolconf", NULL);
+ perror("dolconf");
+ exit(127);
+ }
+}
+
void cb_shm_dolcon_activate(GtkWidget *uu1, gpointer uu2)
{
dolcon();
int main(int argc, char **argv)
{
+ int c;
+
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
signal(SIGCHLD, sighandler);
dc_init();
+ server = dc_srv_local;
gtk_init(&argc, &argv);
#ifdef HAVE_NOTIFY
notify_init("Dolda Connect");
#endif
+ while((c = getopt(argc, argv, "Vrhs:")) != -1) {
+ switch(c) {
+ case 'r':
+ remote = 1;
+ server = NULL;
+ break;
+ case 's':
+ remote = 1;
+ server = optarg;
+ break;
+ case 'h':
+ printf("usage: doldacond-shell [-hr]\n");
+ printf("\t-h\tDisplay this help message\n");
+ printf("\t-r\tConnect to a remote host\n");
+ printf("\t-V\tDisplay version info and exit\n");
+ exit(0);
+ case 'V':
+ printf("%s", RELEASEINFO);
+ exit(0);
+ default:
+ fprintf(stderr, "usage: doldacond-shell [-hr]\n");
+ exit(1);
+ }
+ }
create_shm_wnd();
dcicon = gdk_pixbuf_new_from_xpm_data((const char **)dolda_icon_xpm);
gtk_window_set_default_icon(dcicon);
inittray();
- startdaemon();
+ if(remote)
+ connectdc();
+ else
+ startdaemon();
+ g_timeout_add(10000, trupdatecb, NULL);
gtk_main();
return(0);