Use gtkh header files to clean up dolcon{,f} a bit.
[doldaconnect.git] / clients / gtk2 / dolcon.c
CommitLineData
d3372da9 1/*
2 * Dolda Connect - Modular multiuser Direct Connect-style client
3 * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19
a745644c 20/* This file is a complete and total mess, mostly because of my
21 * inability to structure GUI programs properly. Looking at it too
22 * closely may cause ocular hemorrhaging. */
23
b5010caa 24#include <stdlib.h>
d3372da9 25#include <stdio.h>
26#include <unistd.h>
27#include <string.h>
d3372da9 28#include <stdarg.h>
29#include <gtk/gtk.h>
30#include <sys/socket.h>
31#include <netinet/in.h>
32#include <gdk/gdkkeysyms.h>
33#include <doldaconnect/uilib.h>
34#include <doldaconnect/uimisc.h>
35#include <doldaconnect/utils.h>
36#include <errno.h>
37#include <regex.h>
38#include <signal.h>
39#include <time.h>
8d9ec191 40#include <sys/time.h>
d3372da9 41#include <pwd.h>
42#include <locale.h>
43#include <libintl.h>
44#include <assert.h>
45
a745644c 46/* "Programming with libxml2 is like the thrilling embrace of an
47 * exotic strangler."
48 * --Me */
49#include <libxml/parser.h>
50#include <libxml/tree.h>
51
d3372da9 52#ifdef HAVE_CONFIG_H
53#include <config.h>
54#endif
55#include "progressbar.h"
56
8d9ec191 57#define TRHISTSIZE 10
a745644c 58#define PHO_INIT 0
59#define PHO_DATA 1
60#define PHO_EOF 2
61#define PHO_FINI 3
8d9ec191 62
63struct trdata
64{
65 size_t poshist[TRHISTSIZE];
66 double timehist[TRHISTSIZE];
67 int hc;
68};
d3372da9 69
70struct fndata
71{
72 GtkTextBuffer *textbuf;
73};
74
75struct srchsize
76{
77 int size;
78 int num;
79 int slots;
80 double resptime;
81 GtkTreeRowReference *ref;
82};
83
84struct knownspeed
85{
86 char *userid;
87 int speed, seq;
88 time_t fetched;
89};
90
91GtkWidget *inpdialog;
a745644c 92GtkListStore *fnmodel, *ulmodel, *dlmodel, *reslist;
93int (*pubhubhandler)(int, char *, size_t *) = NULL;
d3372da9 94GtkTreeStore *srchmodel;
95GtkTreeModelFilter *srchmodelfilter;
96GtkTextTagTable *chattags;
97int dcfd = -1, gdkread = -1, gdkwrite = -1;
98int pubhubfd = -1, pubhubtag = -1, filterpubhub = 0;
99int curchat = -1;
100regex_t pubhubfilter;
101pid_t pubhubproc = 0;
102char *pubhubaddr = NULL;
103char *connectas = NULL;
104char *dcserver = NULL;
ef0f20e9 105int autoconn = 1;
d3372da9 106int srchautoupdate = 0;
107int cursrch = -1, nextsrch = -1;
108time_t srcheta;
109struct srchsize *srchsizes = NULL;
110struct knownspeed *knownspeeds = NULL;
4c27a5f2 111int numsizes = 0, numspeeds = 0, ksqueryseq = -1, ksquerytag = -1, lsrestag = -1;
d3372da9 112
d3372da9 113void dcfdcallback(gpointer data, gint source, GdkInputCondition condition);
114void srchstatupdate(void);
d3372da9 115
116#define DCCHARSET "windows-1252"
117
118#define _(text) gettext(text)
119
b1099f1f
FT
120#include "mainwnd.gtkh"
121#include "inpdialog.gtkh"
122#include "pref.gtkh"
123#include "reslist.gtkh"
d3372da9 124
125void updatewrite(void)
126{
127 if(dcfd < 0)
128 return;
129 if(dc_wantwrite())
130 {
131 if(gdkwrite == -1)
132 gdkwrite = gdk_input_add(dcfd, GDK_INPUT_WRITE, dcfdcallback, NULL);
133 } else {
134 if(gdkwrite != -1)
135 {
136 gdk_input_remove(gdkwrite);
137 gdkwrite = -1;
138 }
139 }
140}
141
8d9ec191 142double ntime(void)
143{
144 struct timeval tv;
145
146 gettimeofday(&tv, NULL);
147 return((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
148}
149
d3372da9 150void fndestroycb(struct dc_fnetnode *fn)
151{
152 struct fndata *data;
153 GtkTextBuffer *textbuf;
154
155 data = fn->udata;
156 g_object_unref(data->textbuf);
157 free(data);
158 if(curchat == fn->id)
159 {
160 textbuf = gtk_text_buffer_new(chattags);
161 gtk_text_view_set_buffer(GTK_TEXT_VIEW(main_chatview), textbuf);
162 g_object_unref(textbuf);
163 }
164}
165
166void addfndata(struct dc_fnetnode *fn)
167{
168 struct fndata *data;
169
170 if(fn->udata != NULL)
171 return;
172 fn->destroycb = fndestroycb;
173 data = smalloc(sizeof(*data));
174 data->textbuf = gtk_text_buffer_new(chattags);
175 fn->udata = data;
176}
177
8d9ec191 178void trdestroycb(struct dc_transfer *tr)
179{
180 free(tr->udata);
181}
182
183void addtrdata(struct dc_transfer *tr)
184{
185 struct trdata *data;
186
187 if(tr->udata != NULL)
188 return;
189 tr->destroycb = trdestroycb;
190 data = smalloc(sizeof(*data));
191 memset(data, 0, sizeof(*data));
192 tr->udata = data;
193}
194
195void updatetrdata(struct dc_transfer *tr)
196{
197 int i;
198 struct trdata *data;
199
200 data = tr->udata;
201 if(data->hc < TRHISTSIZE)
202 {
203 data->poshist[data->hc] = tr->curpos;
204 data->timehist[data->hc] = ntime();
205 data->hc++;
206 } else {
207 for(i = 0; i < TRHISTSIZE - 1; i++)
208 {
209 data->poshist[i] = data->poshist[i + 1];
210 data->timehist[i] = data->timehist[i + 1];
211 }
212 data->poshist[i] = tr->curpos;
213 data->timehist[i] = ntime();
214 }
215}
216
d3372da9 217char *getfnstatestock(int state)
218{
219 if(state == DC_FNN_STATE_SYN)
220 return("gtk-jump-to");
221 if(state == DC_FNN_STATE_HS)
222 return("gtk-execute");
223 if(state == DC_FNN_STATE_EST)
224 return("gtk-yes");
225 if(state == DC_FNN_STATE_DEAD)
226 return("gtk-cancel");
227 return(NULL);
228}
229
230void updatehublist(void)
231{
232 int done;
233 struct dc_fnetnode *fn;
234 GtkTreeIter iter;
235 int id;
236 char *buf;
237 char *name;
238 int state, numusers;
239
240 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
241 fn->found = 0;
242 done = 0;
243 while(!done)
244 {
245 done = 1;
246 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(fnmodel), &iter))
247 {
248 do
249 {
250 gtk_tree_model_get(GTK_TREE_MODEL(fnmodel), &iter, 0, &id, -1);
251 if((fn = dc_findfnetnode(id)) == NULL)
252 {
253 /* I can't seem to get a sensible reply fromp
254 * gtk_list_store, so I'm just doing this
255 * instead. */
256 gtk_list_store_remove(fnmodel, &iter);
257 done = 0;
258 break;
259 } else {
260 gtk_tree_model_get(GTK_TREE_MODEL(fnmodel), &iter, 1, &name, 2, &state, 3, &numusers, -1);
261 if(fn->name == NULL)
262 buf = _("Unknown");
263 else
264 buf = icswcstombs(fn->name, "UTF-8", NULL);
265 if(strcmp(buf, name))
266 gtk_list_store_set(fnmodel, &iter, 1, buf, -1);
267 if(state != fn->state)
268 {
269 gtk_list_store_set(fnmodel, &iter, 2, fn->state, -1);
270 gtk_list_store_set(fnmodel, &iter, 4, getfnstatestock(fn->state), -1);
271 }
272 if(numusers != fn->numusers)
273 gtk_list_store_set(fnmodel, &iter, 3, fn->numusers, -1);
274 g_free(name);
275 fn->found = 1;
276 }
277 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(fnmodel), &iter));
278 }
279 }
280 for(fn = dc_fnetnodes; fn != NULL; fn = fn->next)
281 {
282 if(!fn->found)
283 {
284 if(fn->name == NULL)
285 buf = _("Unknown");
286 else
287 buf = icswcstombs(fn->name, "UTF-8", NULL);
288 gtk_list_store_append(fnmodel, &iter);
289 gtk_list_store_set(fnmodel, &iter, 0, fn->id, 1, buf, 2, fn->state, 3, fn->numusers, 4, getfnstatestock(fn->state), -1);
290 addfndata(fn);
291 }
292 }
293}
294
cac656ef 295char *bytes2si(long long bytes)
8d9ec191 296{
297 int i;
298 double b;
299 char *sd;
300 static char ret[64];
301
302 b = bytes;
cac656ef 303 for(i = 0; (b >= 1024) && (i < 4); i++)
8d9ec191 304 b /= 1024;
305 if(i == 0)
306 sd = "B";
307 else if(i == 1)
308 sd = "kiB";
309 else if(i == 2)
310 sd = "MiB";
311 else if(i == 3)
312 sd = "GiB";
313 else
314 sd = "TiB";
315 snprintf(ret, 64, "%.1f %s", b, sd);
316 return(ret);
317}
318
d3372da9 319void percentagefunc(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
320{
321 int colnum;
322 float val;
323 char buf[64];
324
a2f77326 325 colnum = GPOINTER_TO_INT(data);
d3372da9 326 gtk_tree_model_get(model, iter, colnum, &val, -1);
327 snprintf(buf, 64, "%.2f%%", (double)(val * 100.0));
328 g_object_set(rend, "text", buf, NULL);
329}
330
331void transnicebytefunc(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
332{
333 int colnum, val;
334 char buf[64];
335
a2f77326 336 colnum = GPOINTER_TO_INT(data);
d3372da9 337 gtk_tree_model_get(model, iter, colnum, &val, -1);
338 if(val >= 0)
339 snprintf(buf, 64, "%'i", val);
340 else
341 strcpy(buf, _("Unknown"));
342 g_object_set(rend, "text", buf, NULL);
343}
344
cac656ef 345void transnicebytefunc2(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
346{
347 int colnum;
348 long long val;
349 char buf[64];
350
a2f77326 351 colnum = GPOINTER_TO_INT(data);
cac656ef 352 gtk_tree_model_get(model, iter, colnum, &val, -1);
353 if(val >= 0)
354 strcpy(buf, bytes2si(val));
355 else
356 strcpy(buf, _("Unknown"));
357 g_object_set(rend, "text", buf, NULL);
358}
359
d3372da9 360void hidezerofunc(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
361{
362 int colnum, val;
363 char buf[64];
364
a2f77326 365 colnum = GPOINTER_TO_INT(data);
d3372da9 366 gtk_tree_model_get(model, iter, colnum, &val, -1);
367 if(val > 0)
368 snprintf(buf, 64, "%i", val);
369 else
370 strcpy(buf, "");
371 g_object_set(rend, "text", buf, NULL);
372}
373
374void speedtimefunc(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
375{
376 int speed, size, time;
377 char buf[64];
378
379 gtk_tree_model_get(model, iter, 4, &size, 8, &speed, -1);
380 if(speed > 0)
381 {
382 time = (size / speed) / 60;
383 if(time < 1)
384 snprintf(buf, 64, "%'i (<00:01)", speed);
385 else
386 snprintf(buf, 64, "%'i (%02i:%02i)", speed, time / 60, time % 60);
387 } else if(speed == 0) {
388 strcpy(buf, "0");
389 } else {
390 strcpy(buf, _("Unknown"));
391 }
392 g_object_set(rend, "text", buf, NULL);
393}
394
8d9ec191 395void transspeedinfo(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
396{
397 int id;
398 struct dc_transfer *tr;
399 struct trdata *d;
400 char buf[64];
401 int speed;
402
403 gtk_tree_model_get(model, iter, 0, &id, -1);
404 if((tr = dc_findtransfer(id)) != NULL)
405 {
406 d = tr->udata;
407 if((tr->state != DC_TRNS_MAIN) || (d == NULL))
408 {
409 buf[0] = 0;
410 } else if(d->hc < 2) {
411 strcpy(buf, "...");
412 } else {
413 speed = (((double)(d->poshist[d->hc - 1] - d->poshist[0])) / (d->timehist[d->hc - 1] - d->timehist[0]));
414 snprintf(buf, 64, "%s/s", bytes2si(speed));
415 }
416 } else {
417 buf[0] = 0;
418 }
419 g_object_set(rend, "text", buf, NULL);
420}
421
d3372da9 422void transerrorinfo(GtkTreeViewColumn *col, GtkCellRenderer *rend, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
423{
424 int error;
425 time_t errortime;
426 char finbuf[64], tbuf[64], *errstr;
427
428 gtk_tree_model_get(model, iter, 10, &error, 11, &errortime, -1);
429 if(error != DC_TRNSE_NOERROR)
430 {
431 if(error == DC_TRNSE_NOTFOUND)
432 errstr = _("Not found");
433 else if(error == DC_TRNSE_NOSLOTS)
434 errstr = _("No slots");
435 strftime(tbuf, 64, _("%H:%M:%S"), localtime(&errortime));
436 snprintf(finbuf, 64, _("%s (reported at %s)"), errstr, tbuf);
437 } else {
438 *finbuf = 0;
439 }
440 g_object_set(rend, "text", finbuf, NULL);
441}
442
443char *gettrstatestock(int state)
444{
445 if(state == DC_TRNS_WAITING)
446 return("gtk-jump-to");
447 if(state == DC_TRNS_HS)
448 return("gtk-execute");
449 if(state == DC_TRNS_MAIN)
450 return("gtk-network");
451 if(state == DC_TRNS_DONE)
452 return("gtk-yes");
453 return(NULL);
454}
455
8d9ec191 456gint updatetransfers(gpointer data)
457{
458 struct dc_transfer *tr;
459 struct trdata *d;
460 double now;
461
462 now = ntime();
463 for(tr = dc_transfers; tr != NULL; tr = tr->next)
464 {
465 if((d = tr->udata) != NULL)
466 {
467 if((d->hc > 0) && ((now - d->timehist[d->hc - 1]) > 2))
468 updatetrdata(tr);
469 }
470 }
471 return(TRUE);
472}
473
d3372da9 474void updatetransferlists(void)
475{
476 int i;
477 int done;
478 struct dc_transfer *transfer;
479 GtkTreeIter iter;
480 int id;
481 char *buf;
ab9f4164 482 char *peerid, *peernick, *path, *hash;
d3372da9 483 int state, dir, size, curpos, error;
484 time_t errortime;
485 GtkListStore *stores[3];
486
487 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
488 transfer->found = 0;
489 stores[DC_TRNSD_UNKNOWN] = NULL;
490 stores[DC_TRNSD_UP] = ulmodel;
491 stores[DC_TRNSD_DOWN] = dlmodel;
492 for(i = 0; i < 3; i++)
493 {
494 if(stores[i] == NULL)
495 continue;
496 done = 0;
497 while(!done)
498 {
499 done = 1;
500 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(stores[i]), &iter))
501 {
502 do
503 {
504 gtk_tree_model_get(GTK_TREE_MODEL(stores[i]), &iter, 0, &id, 1, &dir, -1);
505 if(((transfer = dc_findtransfer(id)) == NULL) || (transfer->dir != dir))
506 {
507 gtk_list_store_remove(stores[i], &iter);
508 done = 0;
509 break;
510 } else {
511 transfer->found = 1;
ab9f4164 512 gtk_tree_model_get(GTK_TREE_MODEL(stores[i]), &iter, 2, &state, 3, &peerid, 4, &peernick, 5, &path, 6, &size, 7, &curpos, 10, &error, 11, &errortime, 12, &hash, -1);
d3372da9 513 if(state != transfer->state)
514 gtk_list_store_set(stores[i], &iter, 2, transfer->state, 8, gettrstatestock(transfer->state), -1);
515 if(size != transfer->size)
516 gtk_list_store_set(stores[i], &iter, 6, transfer->size, -1);
517 if(curpos != transfer->curpos)
8d9ec191 518 {
d3372da9 519 gtk_list_store_set(stores[i], &iter, 7, transfer->curpos, -1);
8d9ec191 520 if(transfer->udata != NULL)
521 updatetrdata(transfer);
522 }
d3372da9 523 if(error != transfer->error)
524 gtk_list_store_set(stores[i], &iter, 10, transfer->error, -1);
525 if(errortime != transfer->errortime)
526 gtk_list_store_set(stores[i], &iter, 11, transfer->errortime, -1);
527 if((transfer->size > 0) && (transfer->curpos > 0))
528 gtk_list_store_set(stores[i], &iter, 9, (float)transfer->curpos / (float)transfer->size, -1);
529 buf = icswcstombs(transfer->peerid, "UTF-8", NULL);
530 if(strcmp(buf, peerid))
531 gtk_list_store_set(stores[i], &iter, 3, buf, -1);
532 buf = icswcstombs(((transfer->peernick == NULL) || (transfer->peernick[0] == L'\0'))?transfer->peerid:transfer->peernick, "UTF-8", NULL);
533 if(strcmp(buf, peernick))
534 gtk_list_store_set(stores[i], &iter, 4, buf, -1);
535 buf = (transfer->path == NULL)?_("Unknown"):icswcstombs(transfer->path, "UTF-8", NULL);
536 if(strcmp(buf, path))
537 gtk_list_store_set(stores[i], &iter, 5, buf, -1);
ab9f4164 538 buf = (transfer->hash == NULL)?"":icswcstombs(transfer->hash, "UTF-8", NULL);
539 if(strcmp(buf, path))
540 gtk_list_store_set(stores[i], &iter, 12, buf, -1);
541 g_free(hash);
d3372da9 542 g_free(peerid);
543 g_free(peernick);
544 g_free(path);
545 }
546 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(stores[i]), &iter));
547 }
548 }
549 }
550 for(transfer = dc_transfers; transfer != NULL; transfer = transfer->next)
551 {
552 if(!transfer->found)
553 {
554 if(stores[transfer->dir] != NULL)
555 {
556 peerid = icwcstombs(transfer->peerid, "UTF-8");
557 peernick = icwcstombs(((transfer->peernick == NULL) || (transfer->peernick[0] == L'\0'))?transfer->peerid:transfer->peernick, "UTF-8");
558 path = (transfer->path == NULL)?_("Unknown"):icwcstombs(transfer->path, "UTF-8");
ab9f4164 559 hash = (transfer->hash == NULL)?"":icwcstombs(transfer->hash, "UTF-8");
d3372da9 560 gtk_list_store_append(stores[transfer->dir], &iter);
561 gtk_list_store_set(stores[transfer->dir], &iter,
562 0, transfer->id,
563 1, transfer->dir,
564 2, transfer->state,
565 3, peerid,
566 4, peernick,
567 5, path,
568 6, transfer->size,
569 7, transfer->curpos,
570 8, gettrstatestock(transfer->state),
571 9, 0.0,
572 10, transfer->error,
573 11, transfer->errortime,
ab9f4164 574 12, hash,
d3372da9 575 -1);
576 free(peerid);
577 free(peernick);
578 if(transfer->path != NULL)
579 free(path);
ab9f4164 580 if(transfer->hash != NULL)
581 free(hash);
8d9ec191 582 addtrdata(transfer);
d3372da9 583 }
584 }
585 }
586}
587
588void updatesbar(char *msg)
589{
590 gtk_statusbar_pop(GTK_STATUSBAR(main_statusbar), 0);
591 gtk_statusbar_push(GTK_STATUSBAR(main_statusbar), 0, msg);
592}
593
594void freesrchsizes(void)
595{
596 int i;
597
598 for(i = 0; i < numsizes; i++)
599 {
600 if(srchsizes[i].ref != NULL)
601 gtk_tree_row_reference_free(srchsizes[i].ref);
602 }
603 if(srchsizes != NULL)
604 free(srchsizes);
605 srchsizes = NULL;
606 numsizes = 0;
607}
608
609void dcdisconnected(void)
610{
611 if(gdkread != -1)
612 {
613 gdk_input_remove(gdkread);
614 gdkread = -1;
615 }
616 dcfd = -1;
617 updatehublist();
618 updatetransferlists();
619 cursrch = nextsrch = -1;
620 gtk_tree_store_clear(srchmodel);
621 freesrchsizes();
622 gtk_widget_set_sensitive(main_connmenu, TRUE);
623 gtk_widget_set_sensitive(main_dconnmenu, FALSE);
624 gtk_widget_set_sensitive(main_simplesrch, TRUE);
625 gtk_widget_set_sensitive(main_realsrch, TRUE);
626 gtk_widget_set_sensitive(main_srchbtn, TRUE);
627 gtk_widget_set_sensitive(main_srchcanbtn, FALSE);
628 updatesbar(_("Disconnected"));
629}
630
631char *inputbox(char *title, char *prompt, char *def, int echo)
632{
633 int resp;
634 GtkWidget *swnd;
635 char *buf;
636
637 inpdialog = gtk_dialog_new_with_buttons(title, GTK_WINDOW(main_wnd), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
638 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(inpdialog)->vbox), swnd = create_inpdialog_wnd(), TRUE, TRUE, 0);
639 gtk_widget_show(swnd);
640 if(!echo)
641 gtk_entry_set_visibility(GTK_ENTRY(inpdialog_entry), FALSE);
642 gtk_label_set_text(GTK_LABEL(inpdialog_prompt), prompt);
643 gtk_entry_set_text(GTK_ENTRY(inpdialog_entry), def);
644 resp = gtk_dialog_run(GTK_DIALOG(inpdialog));
645 if(!echo)
646 gtk_entry_set_visibility(GTK_ENTRY(inpdialog_entry), TRUE);
647 if(resp == GTK_RESPONSE_ACCEPT)
648 buf = strdup(gtk_entry_get_text(GTK_ENTRY(inpdialog_entry)));
649 else
650 buf = NULL;
651 gtk_widget_destroy(inpdialog);
652 updatewrite();
653 return(buf);
654}
655
656int msgbox(int type, int buttons, char *format, ...)
a2f77326 657#if defined(__GNUC__)
658 __attribute__ ((format (printf, 3, 4)))
659#endif
660;
661
662int msgbox(int type, int buttons, char *format, ...)
d3372da9 663{
664 GtkWidget *swnd;
665 va_list args;
666 char *buf;
667 int resp;
668
669 va_start(args, format);
670 buf = vsprintf2(format, args);
671 va_end(args);
672 swnd = gtk_message_dialog_new(GTK_WINDOW(main_wnd), GTK_DIALOG_MODAL, type, buttons, "%s", buf);
673 resp = gtk_dialog_run(GTK_DIALOG(swnd));
674 gtk_widget_destroy(swnd);
675 free(buf);
676 return(resp);
677}
678
679void readconfigfile(void)
680{
681 FILE *cfgfile;
682 char *homedir, *buf, *p;
683 int w, h;
684
685 if((homedir = getenv("HOME")) == NULL)
686 {
687 fprintf(stderr, "warning: could not find home directory!\n");
688 return;
689 }
690 buf = sprintf2("%s/.dolconrc", homedir);
691 if((cfgfile = fopen(buf, "r")) == NULL)
692 {
693 if(errno != ENOENT)
694 perror(buf);
695 free(buf);
696 return;
697 }
698 free(buf);
699 buf = smalloc(1024);
700 while(fgets(buf, 1024, cfgfile) != NULL)
701 {
702 if(strlen(buf) < 1)
703 continue;
704 p = buf + strlen(buf);
705 if(p[-1] == '\n')
706 *(--p) = 0;
707 if((p = strchr(buf, ':')) == NULL)
708 continue;
709 *(p++) = 0;
710 while((*p == ' ') || (*p == '\t'))
711 p++;
712 if(!strcmp(buf, "wnd-width"))
713 {
714 w = atoi(p);
715 } else if(!strcmp(buf, "wnd-height")) {
716 h = atoi(p);
717 } else if(!strcmp(buf, "pane1-pos")) {
718 gtk_paned_set_position(GTK_PANED(main_pane1), atoi(p));
719 } else if(!strcmp(buf, "pane2-pos")) {
720 gtk_paned_set_position(GTK_PANED(main_pane2), atoi(p));
721 } else if(!strcmp(buf, "pane3-pos")) {
722 gtk_paned_set_position(GTK_PANED(main_pane3), atoi(p));
723 } else if(!strcmp(buf, "pubhubaddr")) {
724 free(pubhubaddr);
725 pubhubaddr = sstrdup(p);
726 } else if(!strcmp(buf, "dcserver")) {
727 free(dcserver);
728 dcserver = sstrdup(p);
729 } else if(!strcmp(buf, "advexpanded")) {
730 gtk_expander_set_expanded(GTK_EXPANDER(main_advexp), atoi(p));
731 } else if(!strcmp(buf, "connectas")) {
732 free(connectas);
733 connectas = sstrdup(p);
734 } else if(!strcmp(buf, "autoconn")) {
735 autoconn = atoi(p);
736 } else if(!strcmp(buf, "filternoslots")) {
737 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(main_filternoslots), atoi(p));
738 }
739 }
740 free(buf);
741 fclose(cfgfile);
742/*
743 if(w != 1589)
744 abort();
745*/
746 gtk_window_resize(GTK_WINDOW(main_wnd), w, h);
747}
748
749void updateconfigfile(void)
750{
751 FILE *cfgfile;
752 char *homedir, *buf;
753 int w, h;
754
755 if((homedir = getenv("HOME")) == NULL)
756 {
757 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not get your home directory!"));
758 return;
759 }
760 buf = sprintf2("%s/.dolconrc", homedir);
761 if((cfgfile = fopen(buf, "w")) == NULL)
762 {
763 free(buf);
764 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not open configuration file for writing: %s"), strerror(errno));
765 return;
766 }
767 free(buf);
768 gtk_window_get_size(GTK_WINDOW(main_wnd), &w, &h);
769 fprintf(cfgfile, "wnd-width: %i\n", w);
770 fprintf(cfgfile, "wnd-height: %i\n", h);
771 fprintf(cfgfile, "pane1-pos: %i\n", gtk_paned_get_position(GTK_PANED(main_pane1)));
772 fprintf(cfgfile, "pane2-pos: %i\n", gtk_paned_get_position(GTK_PANED(main_pane2)));
773 fprintf(cfgfile, "pane3-pos: %i\n", gtk_paned_get_position(GTK_PANED(main_pane3)));
774 fprintf(cfgfile, "pubhubaddr: %s\n", pubhubaddr);
775 fprintf(cfgfile, "dcserver: %s\n", dcserver);
776 fprintf(cfgfile, "advexpanded: %i\n", gtk_expander_get_expanded(GTK_EXPANDER(main_advexp)));
777 fprintf(cfgfile, "connectas: %s\n", connectas);
778 fprintf(cfgfile, "autoconn: %i\n", autoconn);
779 fprintf(cfgfile, "filternoslots: %i\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(main_filternoslots)));
780 fclose(cfgfile);
781}
782
783gboolean initdeath(GtkWidget *widget, gpointer data)
784{
785 updateconfigfile();
786 gtk_main_quit();
787 return(TRUE);
788}
789
790void cb_inpdialog_entry_activate(GtkWidget *widget, gpointer data)
791{
792 gtk_dialog_response(GTK_DIALOG(inpdialog), GTK_RESPONSE_ACCEPT);
793}
794
795int loginconv(int type, wchar_t *prompt, char **resp, void *data)
796{
797 int ret;
798 char *buf;
799
800 ret = 0;
801 buf = icwcstombs(prompt, "UTF-8");
802 switch(type)
803 {
804 case DC_LOGIN_CONV_NOECHO:
805 if((*resp = inputbox(_("Login"), buf, "", 0)) == NULL)
806 ret = 1;
807 break;
808 case DC_LOGIN_CONV_ECHO:
809 if((*resp = inputbox(_("Login"), buf, "", 1)) == NULL)
810 ret = 1;
811 break;
812 case DC_LOGIN_CONV_INFO:
813 msgbox(GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", buf);
814 break;
815 case DC_LOGIN_CONV_ERROR:
816 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", buf);
817 break;
818 }
819 free(buf);
820 updatewrite();
821 return(ret);
822}
823
824void getfnlistcallback(int resp, void *data)
825{
826 updatehublist();
827}
828
829void gettrlistcallback(int resp, void *data)
830{
831 updatetransferlists();
832}
833
834void logincallback(int err, wchar_t *reason, void *data)
835{
836 switch(err)
837 {
838 case DC_LOGIN_ERR_SUCCESS:
839 dc_queuecmd(NULL, NULL, L"notify", L"all", L"on", NULL);
840 dc_getfnlistasync(getfnlistcallback, NULL);
841 dc_gettrlistasync(gettrlistcallback, NULL);
842 updatesbar("Authenticated");
843 break;
844 case DC_LOGIN_ERR_NOLOGIN:
845 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not negotiate an acceptable authentication mechanism"));
846 dc_disconnect();
847 dcdisconnected();
848 break;
849 case DC_LOGIN_ERR_SERVER:
850 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The server has encountered an error"));
851 dc_disconnect();
852 dcdisconnected();
853 break;
854 case DC_LOGIN_ERR_USER:
855 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Internal client error"));
856 dc_disconnect();
857 dcdisconnected();
858 break;
859 case DC_LOGIN_ERR_CONV:
860 dc_disconnect();
861 dcdisconnected();
862 break;
863 case DC_LOGIN_ERR_AUTHFAIL:
864 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Login attempt failed!"));
865 dc_disconnect();
866 dcdisconnected();
867 break;
868 }
869 updatewrite();
870}
871
872GtkTreeIter *ref2iter(GtkTreeRowReference *ref)
873{
874 static GtkTreeIter iter;
875 GtkTreePath *path;
876
877 assert((path = gtk_tree_row_reference_get_path(ref)) != NULL);
878 assert(gtk_tree_model_get_iter(GTK_TREE_MODEL(srchmodel), &iter, path));
879 gtk_tree_path_free(path);
880 return(&iter);
881}
882
883GtkTreeRowReference *iter2ref(GtkTreeIter *iter)
884{
885 GtkTreePath *path;
886 GtkTreeRowReference *ref;
887
888 assert((path = gtk_tree_model_get_path(GTK_TREE_MODEL(srchmodel), iter)) != NULL);
889 assert((ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(srchmodel), path)) != NULL);
890 gtk_tree_path_free(path);
891 return(ref);
892}
893
894struct srchsize *finddiscsize(void)
895{
896 int i;
897 GtkTreeIter iter;
898
899 for(i = 0; i < numsizes; i++)
900 {
901 if(srchsizes[i].size == -1)
902 return(&srchsizes[i]);
903 }
904 srchsizes = srealloc(srchsizes, sizeof(*srchsizes) * ++numsizes);
905 srchsizes[i].size = -1;
906 srchsizes[i].num = 1;
907 srchsizes[i].slots = 0;
908 srchsizes[i].resptime = 0.0;
909 gtk_tree_store_append(srchmodel, &iter, NULL);
910 gtk_tree_store_set(srchmodel, &iter, 3, _("Discrete sizes"), 7, 1, -1);
911 srchsizes[i].ref = iter2ref(&iter);
912 return(&srchsizes[i]);
913}
914
915struct knownspeed *findksentbyname(char *userid)
916{
917 int i;
918
919 for(i = 0; i < numspeeds; i++)
920 {
921 if(!strcmp(knownspeeds[i].userid, userid))
922 return(&knownspeeds[i]);
923 }
924 return(NULL);
925}
926
927struct knownspeed *findksentbyseq(int seq)
928{
929 int i;
930
931 for(i = 0; i < numspeeds; i++)
932 {
933 if(knownspeeds[i].seq == seq)
934 return(&knownspeeds[i]);
935 }
936 return(NULL);
937}
938
939gboolean ksupdaterow(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
940{
941 struct knownspeed *ks;
942 char *userid;
943
944 gtk_tree_model_get(GTK_TREE_MODEL(model), iter, 1, &userid, -1);
945 if(userid == NULL)
946 return(FALSE);
947 ks = findksentbyname(userid);
948 if(ks == NULL)
949 {
950 knownspeeds = srealloc(knownspeeds, (numspeeds + 1) * sizeof(*knownspeeds));
951 ks = &knownspeeds[numspeeds];
952 numspeeds++;
953 ks->userid = sstrdup(userid);
954 ks->speed = -1;
955 ks->seq = -2;
956 ksqueryseq = -2;
957 }
958 g_free(userid);
959 if(ks->speed != -1)
960 gtk_tree_store_set(GTK_TREE_STORE(model), iter, 8, ks->speed, -1);
961 return(FALSE);
962}
963
964gint ksupdatecb(gpointer data)
965{
966 int i, oldnum;
967 time_t now;
968 wchar_t **users, *buf;
969 size_t userssize, usersdata;
970
971 if(ksquerytag != -1)
972 return(TRUE);
973 now = time(NULL);
974 oldnum = numspeeds;
975 for(i = 0; i < numspeeds;)
976 {
977 if(now - knownspeeds[i].fetched > 60)
978 {
979 free(knownspeeds[i].userid);
980 memmove(&knownspeeds[i], &knownspeeds[i + 1], (--numspeeds - i) * sizeof(*knownspeeds));
981 } else {
982 i++;
983 }
984 }
985 if(oldnum != numspeeds)
65123ca2 986 {
987 if(numspeeds == 0)
988 {
989 free(knownspeeds);
990 knownspeeds = NULL;
991 } else {
992 knownspeeds = srealloc(knownspeeds, numspeeds * sizeof(*knownspeeds));
993 }
994 }
d3372da9 995 gtk_tree_model_foreach(GTK_TREE_MODEL(srchmodel), ksupdaterow, NULL);
996 if(ksqueryseq == -2)
997 {
998 users = NULL;
999 userssize = usersdata = 0;
1000 ksqueryseq = 0;
1001 for(i = 0; i < numspeeds; i++)
1002 {
1003 if(knownspeeds[i].seq == -2)
1004 {
1005 assert((buf = icmbstowcs(knownspeeds[i].userid, "UTF-8")) != NULL);
1006 knownspeeds[i].seq = ksqueryseq++;
1007 addtobuf(users, buf);
1008 }
1009 }
1010 addtobuf(users, NULL);
0931eb36 1011 ksquerytag = dc_queuecmd(NULL, NULL, L"filtercmd", L"userspeeda", L"%a", users, NULL);
d3372da9 1012 dc_freewcsarr(users);
1013 }
1014 return(TRUE);
1015}
1016
1017void handleresps(void)
1018{
1019 int i;
1020 struct dc_response *resp;
1021 struct dc_intresp *ires;
1022 struct dc_fnetnode *fn;
1023 struct fndata *fndata;
1024 GtkTextIter iter;
1025 GtkTreeIter titer, piter;
1026 char *buf, *p;
1027 int tosbuf;
1028 struct srchsize *ss;
1029 struct knownspeed *ks;
1030
1031 while((resp = dc_getresp()) != NULL)
1032 {
1033 if(!wcscmp(resp->cmdname, L".connect"))
1034 {
5e1e52f1 1035 if(resp->code != 201)
d3372da9 1036 {
5e1e52f1 1037 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The server refused the connection"));
1038 dc_disconnect();
1039 dcdisconnected();
1040 } else if(dc_checkprotocol(resp, DC_LATEST)) {
1041 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Server protocol revision mismatch"));
1042 dc_disconnect();
1043 dcdisconnected();
1044 } else {
ae1213f7 1045 tosbuf = 0x10; /* Minimum delay */
48f7dc10 1046 setsockopt(dcfd, IPPROTO_IP, IP_TOS, &tosbuf, sizeof(tosbuf));
d3372da9 1047 updatesbar(_("Connected"));
1048 dc_loginasync(connectas, 1, loginconv, logincallback, NULL);
d3372da9 1049 }
1050 } else if(!wcscmp(resp->cmdname, L".notify")) {
1051 dc_uimisc_handlenotify(resp);
1052 switch(resp->code)
1053 {
1054 case 600:
1055 if((ires = dc_interpret(resp)) != NULL)
1056 {
1057 if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL)
1058 {
1059 fndata = fn->udata;
1060 gtk_text_buffer_get_end_iter(fndata->textbuf, &iter);
1061 if((buf = icwcstombs(ires->argv[3].val.str, "UTF-8")) != NULL)
1062 {
1063 gtk_text_buffer_insert_with_tags_by_name(fndata->textbuf, &iter, "<", -1, "sender", NULL);
1064 gtk_text_buffer_insert_with_tags_by_name(fndata->textbuf, &iter, buf, -1, "sender", NULL);
1065 gtk_text_buffer_insert_with_tags_by_name(fndata->textbuf, &iter, ">", -1, "sender", NULL);
1066 gtk_text_buffer_insert(fndata->textbuf, &iter, " ", -1);
1067 free(buf);
1068 }
1069 if((buf = icwcstombs(ires->argv[4].val.str, "UTF-8")) != NULL)
1070 {
1071 gtk_text_buffer_insert(fndata->textbuf, &iter, buf, -1);
1072 gtk_text_buffer_insert(fndata->textbuf, &iter, "\n", -1);
1073 free(buf);
1074 if(curchat == fn->id)
1075 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(main_chatview), &iter, 0, 0, 0, 0);
1076 }
1077 }
1078 dc_freeires(ires);
1079 }
1080 break;
1081 case 601:
1082 case 602:
1083 case 603:
1084 case 604:
1085 case 605:
1086 updatehublist();
1087 break;
1088 case 610:
1089 case 611:
1090 case 612:
1091 case 613:
1092 case 614:
1093 case 615:
1094 case 616:
1095 case 617:
ab9f4164 1096 case 618:
d3372da9 1097 updatetransferlists();
1098 break;
1099 case 620:
1100 if((ires = dc_interpret(resp)) != NULL)
1101 {
1102 if(ires->argv[0].val.num == nextsrch)
1103 srcheta = time(NULL) + ires->argv[0].val.num;
1104 dc_freeires(ires);
1105 }
1106 break;
1107 case 621:
1108 if((ires = dc_interpret(resp)) != NULL)
1109 {
1110 if(ires->argv[0].val.num == nextsrch)
1111 {
1112 if(cursrch != -1)
0931eb36 1113 dc_queuecmd(NULL, NULL, L"cansrch", L"%i", cursrch, NULL);
d3372da9 1114 cursrch = nextsrch;
1115 nextsrch = -1;
1116 gtk_widget_set_sensitive(main_realsrch, TRUE);
1117 gtk_widget_set_sensitive(main_simplesrch, TRUE);
1118 gtk_widget_set_sensitive(main_srchbtn, TRUE);
1119 gtk_widget_set_sensitive(main_srchcanbtn, FALSE);
1120 srchstatupdate();
1121 gtk_entry_set_text(GTK_ENTRY(main_realsrch), "");
1122 gtk_entry_set_text(GTK_ENTRY(main_simplesrch), "");
1123 gtk_tree_store_clear(srchmodel);
1124 freesrchsizes();
1125 }
1126 dc_freeires(ires);
1127 }
1128 break;
1129 case 622:
1130 if((ires = dc_interpret(resp)) != NULL)
1131 {
1132 if(ires->argv[0].val.num == cursrch)
1133 {
1134 for(i = 0; i < numsizes; i++)
1135 {
1136 if(srchsizes[i].size == ires->argv[4].val.num)
1137 break;
1138 }
1139 if(i == numsizes)
1140 {
1141 srchsizes = srealloc(srchsizes, sizeof(*srchsizes) * ++numsizes);
1142 srchsizes[i].size = ires->argv[4].val.num;
1143 srchsizes[i].num = 1;
1144 srchsizes[i].slots = ires->argv[5].val.num;
1145 srchsizes[i].resptime = ires->argv[7].val.flnum;
1146 ss = finddiscsize();
1147 ss->slots += ires->argv[5].val.num;
1148 if((ss->resptime == 0.0) || (ss->resptime > ires->argv[7].val.flnum))
1149 ss->resptime = ires->argv[7].val.flnum;
1150 piter = *ref2iter(ss->ref);
1151 gtk_tree_store_set(srchmodel, &piter, 5, ss->slots, 6, ss->resptime, -1);
1152 gtk_tree_store_append(srchmodel, &titer, &piter);
1153 srchsizes[i].ref = iter2ref(&titer);
1154 } else if(srchsizes[i].num == 1) {
ab9f4164 1155 char *filename, *peername, *fnetname, *hash;
d3372da9 1156 int slots, speed;
1157 double resptime;
1158
ab9f4164 1159 gtk_tree_model_get(GTK_TREE_MODEL(srchmodel), ref2iter(srchsizes[i].ref), 0, &fnetname, 1, &peername, 3, &filename, 5, &slots, 6, &resptime, 8, &speed, 9, &hash, -1);
d3372da9 1160 gtk_tree_store_remove(srchmodel, ref2iter(srchsizes[i].ref));
1161 gtk_tree_row_reference_free(srchsizes[i].ref);
1162 ss = finddiscsize();
1163 ss->slots -= slots;
1164 gtk_tree_store_set(srchmodel, ref2iter(ss->ref), 5, ss->slots, -1);
1165 gtk_tree_store_append(srchmodel, &piter, NULL);
1166 srchsizes[i].slots = ires->argv[5].val.num + slots;
1167 srchsizes[i].resptime = (ires->argv[7].val.flnum < resptime)?ires->argv[7].val.flnum:resptime;
1168 srchsizes[i].num = 2;
1169 srchsizes[i].ref = iter2ref(&piter);
1170 gtk_tree_store_set(srchmodel, &piter, 4, srchsizes[i].size, 5, srchsizes[i].slots, 6, srchsizes[i].resptime, 7, 2, -1);
1171 if((buf = icwcstombs(ires->argv[1].val.str, "UTF-8")) != NULL)
1172 {
1173 p = buf;
ab9f4164 1174 /* XXX: Too NMDC-specific! */
d3372da9 1175 if(strrchr(p, '\\') != NULL)
1176 p = strrchr(p, '\\') + 1;
1177 gtk_tree_store_set(srchmodel, &piter, 3, p, -1);
1178 free(buf);
1179 }
1180 gtk_tree_store_append(srchmodel, &titer, &piter);
ab9f4164 1181 gtk_tree_store_set(srchmodel, &titer, 0, fnetname, 1, peername, 2, peername, 3, filename, 4, srchsizes[i].size, 5, slots, 6, resptime, 8, speed, 9, hash, -1);
1182 g_free(filename); g_free(peername); g_free(fnetname); g_free(hash);
d3372da9 1183 gtk_tree_store_append(srchmodel, &titer, &piter);
1184 } else {
1185 srchsizes[i].num++;
1186 srchsizes[i].slots += ires->argv[5].val.num;
1187 if(ires->argv[7].val.flnum < srchsizes[i].resptime)
1188 srchsizes[i].resptime = ires->argv[7].val.flnum;
1189 piter = *ref2iter(srchsizes[i].ref);
1190 gtk_tree_store_set(srchmodel, &piter, 5, srchsizes[i].slots, 6, srchsizes[i].resptime, 7, srchsizes[i].num, -1);
1191 gtk_tree_store_append(srchmodel, &titer, &piter);
1192 }
1193 if((buf = icwcstombs(ires->argv[1].val.str, "UTF-8")) != NULL)
1194 {
1195 gtk_tree_store_set(srchmodel, &titer, 3, buf, -1);
1196 free(buf);
1197 }
1198 if((buf = icwcstombs(ires->argv[2].val.str, "UTF-8")) != NULL)
1199 {
1200 gtk_tree_store_set(srchmodel, &titer, 0, buf, -1);
1201 free(buf);
1202 }
1203 if((buf = icwcstombs(ires->argv[3].val.str, "UTF-8")) != NULL)
1204 {
1205 gtk_tree_store_set(srchmodel, &titer, 1, buf, -1);
1206 gtk_tree_store_set(srchmodel, &titer, 2, buf, -1);
1207 free(buf);
1208 }
ab9f4164 1209 if((buf = icwcstombs(ires->argv[8].val.str, "UTF-8")) != NULL)
1210 {
1211 gtk_tree_store_set(srchmodel, &titer, 9, buf, -1);
1212 free(buf);
1213 }
d3372da9 1214 gtk_tree_store_set(srchmodel, &titer, 4, ires->argv[4].val.num, 5, ires->argv[5].val.num, 6, ires->argv[7].val.flnum, 8, -1, -1);
1215 }
1216 dc_freeires(ires);
1217 }
1218 break;
1219 default:
1220 break;
1221 }
1222 } else if(!wcscmp(resp->cmdname, L"filtercmd")) {
1223 if((ksquerytag >= 0) && (ksquerytag == resp->tag))
1224 {
1225 for(i = 0; i < resp->numlines; i++)
1226 {
1227 assert((ks = findksentbyseq(i)) != NULL);
1228 ks->speed = wcstol(resp->rlines[i].argv[1], NULL, 10);
1229 ks->seq = -1;
1230 ks->fetched = time(NULL);
1231 }
1232 ksquerytag = -1;
1233 ksupdatecb(NULL);
4c27a5f2 1234 } else if((lsrestag >= 0) && (lsrestag == resp->tag)) {
1235 for(i = 0; i < resp->numlines; i++)
1236 {
1237 if(!wcsncmp(resp->rlines[i].argv[1], L"id:", 3))
1238 {
1239 gtk_list_store_append(reslist, &titer);
1240 gtk_list_store_set(reslist, &titer, 0, icswcstombs(resp->rlines[i].argv[1] + 3, "UTF-8", NULL), -1);
1241 } else if(!wcsncmp(resp->rlines[i].argv[1], L"size:", 5)) {
1242 gtk_list_store_set(reslist, &titer, 1, wcstol(resp->rlines[i].argv[1] + 5, NULL, 10), -1);
1243 } else if(!wcsncmp(resp->rlines[i].argv[1], L"prog:", 5)) {
1244 gtk_list_store_set(reslist, &titer, 2, wcstol(resp->rlines[i].argv[1] + 5, NULL, 10), -1);
1245 } else if(!wcsncmp(resp->rlines[i].argv[1], L"name:", 5)) {
1246 gtk_list_store_set(reslist, &titer, 3, icswcstombs(resp->rlines[i].argv[1] + 5, "UTF-8", NULL), -1);
1247 } else if(!wcsncmp(resp->rlines[i].argv[1], L"lock:", 5)) {
1248 if(!wcscmp(resp->rlines[i].argv[1] + 5, L"yes"))
1249 gtk_list_store_set(reslist, &titer, 4, TRUE, -1);
1250 else
1251 gtk_list_store_set(reslist, &titer, 4, FALSE, -1);
1252 } else if(!wcsncmp(resp->rlines[i].argv[1], L"hash:", 5)) {
1253 gtk_list_store_set(reslist, &titer, 5, icswcstombs(resp->rlines[i].argv[1] + 5, "UTF-8", NULL), -1);
1254 }
1255 }
1256 lsrestag = -1;
1257 gtk_widget_set_sensitive(reslist_reload, TRUE);
d3372da9 1258 }
1259 }
1260 dc_freeresp(resp);
1261 }
1262 updatewrite();
1263}
1264
1265void dcfdcallback(gpointer data, gint source, GdkInputCondition condition)
1266{
1267 int errnobak;
1268
1269 if(((condition & GDK_INPUT_READ) && dc_handleread()) || ((condition & GDK_INPUT_WRITE) && dc_handlewrite()))
1270 {
1271 errnobak = errno;
1272 dcdisconnected();
1273 if(errnobak == 0)
1274 {
1275 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The server has closed the connection"));
1276 } else {
1277 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The connection to the server failed:\n\n%s"), strerror(errnobak));
1278 }
1279 return;
1280 }
1281 handleresps();
1282}
1283
1284void cb_main_dconnmenu_activate(GtkWidget *widget, gpointer data)
1285{
1286 if(dcfd < 0)
1287 return;
1288 dc_disconnect();
1289 dcdisconnected();
1290}
1291
1292void cb_main_prefmenu_activate(GtkWidget *widget, gpointer data)
1293{
1294 GtkWidget *dialog, *swnd;
1295 int resp;
1296
1297 dialog = gtk_dialog_new_with_buttons(_("Preferences"), GTK_WINDOW(main_wnd), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
1298 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), swnd = create_pref_wnd(), TRUE, TRUE, 0);
1299 gtk_entry_set_text(GTK_ENTRY(pref_pubhuburl), pubhubaddr);
1300 gtk_entry_set_text(GTK_ENTRY(pref_connectas), connectas);
1301 gtk_entry_set_text(GTK_ENTRY(pref_dcserver), dcserver);
1302 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pref_autoconn), autoconn);
1303 gtk_widget_show(swnd);
1304 resp = gtk_dialog_run(GTK_DIALOG(dialog));
1305 if(resp == GTK_RESPONSE_ACCEPT)
1306 {
1307 free(pubhubaddr);
1308 pubhubaddr = sstrdup(gtk_entry_get_text(GTK_ENTRY(pref_pubhuburl)));
1309 free(connectas);
1310 connectas = sstrdup(gtk_entry_get_text(GTK_ENTRY(pref_connectas)));
1311 free(dcserver);
1312 dcserver = sstrdup(gtk_entry_get_text(GTK_ENTRY(pref_dcserver)));
1313 autoconn = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pref_autoconn));
1314 }
1315 gtk_widget_destroy(dialog);
1316}
1317
4c27a5f2 1318void cb_main_lsres_activate(GtkWidget *widget, gpointer data)
1319{
1320 gtk_list_store_clear(reslist);
1321 gtk_widget_set_sensitive(reslist_delete, FALSE);
1322 gtk_widget_set_sensitive(reslist_search, FALSE);
1323 gtk_widget_show(reslist_wnd);
1324 if(lsrestag == -1)
1325 {
1326 lsrestag = dc_queuecmd(NULL, NULL, L"filtercmd", L"lsres", NULL);
1327 gtk_widget_set_sensitive(reslist_reload, FALSE);
1328 }
1329}
1330
d3372da9 1331void dcconnect(char *host)
1332{
65bf229b 1333 dcfd = dc_connect(host);
d3372da9 1334 if(dcfd < 0)
1335 {
1336 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not connect:\n\n%s"), strerror(errno));
1337 return;
1338 }
1339 gdkread = gdk_input_add(dcfd, GDK_INPUT_READ, dcfdcallback, NULL);
1340 updatewrite();
1341 gtk_widget_set_sensitive(main_connmenu, FALSE);
1342 gtk_widget_set_sensitive(main_dconnmenu, TRUE);
1343 updatesbar(_("Connecting..."));
1344}
1345
1346void cb_main_connmenu_activate(GtkWidget *widget, gpointer data)
1347{
1348 char *buf;
1349
1350 if(dcfd >= 0)
1351 return;
1352 if((buf = inputbox(_("Connect"), _("Server address:"), dcserver, 1)) == NULL)
1353 return;
1354 dcconnect(buf);
1355 free(buf);
1356}
1357
1358void cb_main_sdmenu_activate(GtkWidget *widget, gpointer data)
1359{
1360 int tag;
1361 struct dc_response *resp;
1362
1363 if(dcfd < 0)
1364 {
1365 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Not connected to DC server"));
1366 return;
1367 }
1368 tag = dc_queuecmd(NULL, NULL, L"shutdown", NULL);
1369 if((resp = dc_gettaggedrespsync(tag)) != NULL)
1370 {
1371 if(resp->code == 502)
1372 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
1373 dc_freeresp(resp);
1374 }
1375 handleresps();
1376}
1377
1378void cb_main_fnaddr_activate(GtkWidget *widget, gpointer data)
1379{
1380 int tag;
d3372da9 1381 struct dc_response *resp;
0783994d 1382 wchar_t **toks;
d3372da9 1383
1384 if(dcfd < 0)
1385 {
1386 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Not connected to DC server"));
1387 return;
1388 }
0783994d 1389 toks = dc_lexsexpr(icsmbstowcs((char *)gtk_entry_get_text(GTK_ENTRY(main_fnaddr)), "UTF-8", NULL));
1390 if(*toks == NULL)
d3372da9 1391 {
0783994d 1392 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Illegal address entered"));
1393 return;
d3372da9 1394 }
0783994d 1395 if(wcschr(toks[0], L':') == NULL)
1396 {
1397 toks[0] = srealloc(toks[0], (wcslen(toks[0]) + 5) * sizeof(wchar_t));
1398 wcscat(toks[0], L":411");
1399 }
0931eb36 1400 tag = dc_queuecmd(NULL, NULL, L"cnct", L"dc", L"%a", toks, NULL);
0783994d 1401 dc_freewcsarr(toks);
d3372da9 1402 if((resp = dc_gettaggedrespsync(tag)) != NULL)
1403 {
1404 if(resp->code == 502)
1405 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
1406 if(resp->code == 509)
1407 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The server could not parse that address"));
eaf3d948 1408 if(resp->code == 515)
1409 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("There are too many hubs connected"));
d3372da9 1410 dc_freeresp(resp);
1411 }
1412 gtk_entry_set_text(GTK_ENTRY(main_fnaddr), "");
1413 handleresps();
1414}
1415
eba4327a 1416void setpubhubmodel(GtkTreeModel *model, int sortcol, int numcols, int *cols, char **names)
d3372da9 1417{
a745644c 1418 GtkTreeViewColumn *col;
cac656ef 1419 GtkCellRenderer *rnd;
a745644c 1420 GtkTreeModel *sortmodel;
eba4327a 1421 int i;
a745644c 1422
1423 while((col = gtk_tree_view_get_column(GTK_TREE_VIEW(main_phublist), 0)) != NULL)
1424 gtk_tree_view_remove_column(GTK_TREE_VIEW(main_phublist), col);
eba4327a 1425 for(i = 0; i < numcols; i++) {
cac656ef 1426 if(gtk_tree_model_get_column_type(model, cols[i]) == G_TYPE_INT64)
1427 {
1428 col = gtk_tree_view_column_new();
1429 gtk_tree_view_column_set_title(col, names[i]);
1430 rnd = gtk_cell_renderer_text_new();
1431 gtk_tree_view_column_pack_start(col, rnd, TRUE);
a2f77326 1432 gtk_tree_view_column_set_cell_data_func(col, rnd, transnicebytefunc2, GINT_TO_POINTER(cols[i]), NULL);
cac656ef 1433 } else {
1434 col = gtk_tree_view_column_new_with_attributes(names[i], gtk_cell_renderer_text_new(), "text", cols[i], NULL);
1435 }
eba4327a 1436 gtk_tree_view_column_set_sort_column_id(col, cols[i]);
a745644c 1437 gtk_tree_view_column_set_resizable(col, TRUE);
1438 gtk_tree_view_append_column(GTK_TREE_VIEW(main_phublist), col);
1439 }
a745644c 1440 sortmodel = gtk_tree_model_sort_new_with_model(model);
1441 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(sortmodel), sortcol, GTK_SORT_DESCENDING);
1442 gtk_tree_view_set_model(GTK_TREE_VIEW(main_phublist), sortmodel);
1443 g_object_unref(sortmodel);
1444}
1445
eba4327a 1446xmlNodePtr findnode(xmlNodePtr node, char *name)
1447{
1448 for(; node != NULL; node = node->next)
1449 {
1450 if(!strcmp((char *)node->name, name))
1451 break;
1452 }
1453 return(node);
1454}
1455
1456int pubhubxmlhandler(int op, char *buf, size_t *len)
1457{
1458 static xmlParserCtxtPtr ctxt = NULL;
1459 int i, match;
1460 xmlNodePtr dr, r, cr, c, n;
1461 int numcols, *cols, sortcol;
1462 GType type, *types;
1463 char **names, *name, *stype, *attr;
1464 GtkListStore *model;
1465 GtkTreeIter iter;
1466
1467 numcols = 0;
1468 names = NULL;
1469 types = NULL;
1470 switch(op)
1471 {
1472 case PHO_INIT:
1473 break;
1474 case PHO_DATA:
1475 if(ctxt == NULL) {
1476 ctxt = xmlCreatePushParserCtxt(NULL, NULL, buf, *len, pubhubaddr);
1477 *len = 0;
1478 if(ctxt == NULL)
1479 return(1);
1480 } else {
1481 xmlParseChunk(ctxt, buf, *len, 0);
1482 *len = 0;
1483 }
1484 break;
1485 case PHO_EOF:
031b283f 1486 if(ctxt == NULL)
1487 {
1488 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("A hub list could not be read from %s"), pubhubaddr);
1489 break;
1490 }
eba4327a 1491 xmlParseChunk(ctxt, NULL, 0, 1);
1492 if(!ctxt->wellFormed)
1493 {
1494 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The hub list at %s is not valid"), pubhubaddr);
1495 break;
1496 }
1497 dr = r = cr = NULL;
1498 dr = xmlDocGetRootElement(ctxt->myDoc);
1499 if(dr != NULL)
1500 r = findnode(dr->children, "Hubs");
1501 if(r != NULL)
1502 cr = findnode(r->children, "Columns");
1503 if(cr == NULL)
1504 {
1505 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The hub list at %s cannot be understood"), pubhubaddr);
1506 break;
1507 }
1508 for(c = findnode(cr->children, "Column"); c != NULL; c = findnode(c->next, "Column"))
1509 {
1510 name = (char *)xmlGetProp(c, (xmlChar *)"Name");
1511 stype = (char *)xmlGetProp(c, (xmlChar *)"Type");
1512 type = G_TYPE_INVALID;
1513 if(stype != NULL)
1514 {
1515 if(!strcmp(stype, "string"))
1516 type = G_TYPE_STRING;
1517 else if(!strcmp(stype, "int"))
1518 type = G_TYPE_INT;
1519 else if(!strcmp(stype, "bytes"))
1520 type = G_TYPE_INT64;
1521 }
1522 if((name != NULL) && (type != G_TYPE_INVALID))
1523 {
1524 names = srealloc(names, (numcols + 1) * sizeof(*names));
1525 types = srealloc(types, (numcols + 1) * sizeof(*names));
1526 names[numcols] = sstrdup(name);
1527 types[numcols] = type;
1528 numcols++;
1529 }
1530 if(name != NULL)
1531 xmlFree(name);
1532 if(stype != NULL)
1533 xmlFree(stype);
1534 }
1535 if(numcols == 0)
1536 {
1537 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The hub list at %s did not contain any columns"), pubhubaddr);
1538 break;
1539 }
1540 for(i = 0; i < numcols; i++)
1541 {
1542 if(!strcmp(names[i], "Address"))
1543 {
1544 name = names[0];
1545 names[0] = names[i];
1546 names[i] = name;
1547 type = types[0];
1548 types[0] = types[i];
1549 types[i] = type;
1550 break;
1551 }
1552 }
1553 if(i == numcols)
1554 {
a2f77326 1555 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The hub list at %s did not contain the address to any hubs"), pubhubaddr);
eba4327a 1556 break;
1557 }
1558 model = gtk_list_store_newv(numcols, types);
1559 for(n = findnode(r->children, "Hub"); n != NULL; n = findnode(n->next, "Hub"))
1560 {
1561 if(!xmlHasProp(n, (xmlChar *)"Address") || !xmlHasProp(n, (xmlChar *)"Name"))
1562 continue;
1563 if(filterpubhub)
1564 {
1565 match = 0;
1566 attr = (char *)xmlGetProp(n, (xmlChar *)"Name");
1567 if(!regexec(&pubhubfilter, attr, 0, NULL, 0))
1568 match = 1;
1569 xmlFree(attr);
1570 if((attr = (char *)xmlGetProp(n, (xmlChar *)"Description")) != NULL)
1571 {
1572 if(!regexec(&pubhubfilter, attr, 0, NULL, 0))
1573 match = 1;
1574 xmlFree(attr);
1575 }
1576 if(!match)
1577 continue;
1578 }
1579 gtk_list_store_append(model, &iter);
1580 for(i = 0; i < numcols; i++)
1581 {
1582 attr = (char *)xmlGetProp(n, (xmlChar *)names[i]);
1583 if(attr != NULL)
1584 {
1585 if(types[i] == G_TYPE_STRING)
1586 gtk_list_store_set(model, &iter, i, attr, -1);
1587 else if(types[i] == G_TYPE_INT)
1588 gtk_list_store_set(model, &iter, i, atoi(attr), -1);
1589 else if(types[i] == G_TYPE_INT64)
1590 gtk_list_store_set(model, &iter, i, strtoll(attr, NULL, 0), -1);
1591 xmlFree(attr);
1592 }
1593 }
1594 }
1595 cols = smalloc((numcols - 1) * sizeof(*cols));
1596 for(i = 1; i < numcols; i++)
1597 cols[i - 1] = i;
1598 sortcol = 0;
1599 for(i = 0; i < numcols; i++)
1600 {
1601 if(!strcmp(names[i], "Users"))
1602 sortcol = i;
1603 }
1604 setpubhubmodel(GTK_TREE_MODEL(model), sortcol, numcols - 1, cols, names + 1);
1605 free(cols);
dd30d71b 1606 g_object_unref(model);
eba4327a 1607 break;
1608 case PHO_FINI:
1609 if(ctxt != NULL)
1610 {
1611 if(ctxt->myDoc != NULL)
1612 xmlFreeDoc(ctxt->myDoc);
1613 xmlFreeParserCtxt(ctxt);
1614 ctxt = NULL;
1615 }
1616 break;
1617 }
1618 if(numcols != 0)
1619 {
1620 for(i = 0; i < numcols; i++)
1621 free(names[i]);
1622 free(names);
1623 free(types);
1624 }
1625 return(0);
1626}
1627
a745644c 1628int pubhuboldhandler(int op, char *buf, size_t *len)
1629{
1630 static GtkListStore *model = NULL;
1631 int i;
d3372da9 1632 char *p, *p2;
d3372da9 1633 wchar_t *wbuf;
eba4327a 1634 char *fields[4], *names[3];
1635 int cols[3];
d3372da9 1636 GtkTreeIter iter;
d3372da9 1637
a745644c 1638 switch(op)
d3372da9 1639 {
a745644c 1640 case PHO_INIT:
1641 model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
1642 break;
1643 case PHO_DATA:
1644 while((p = memchr(buf, '\n', *len)) != NULL)
d3372da9 1645 {
a745644c 1646 *(p++) = 0;
1647 for(i = 0, p2 = buf; i < 4; i++) {
d3372da9 1648 fields[i] = p2;
1649 if((p2 = strchr(p2, '|')) == NULL)
1650 break;
1651 *(p2++) = 0;
1652 }
a745644c 1653 if(i == 4) {
1654 for(i = 0; i < 4; i++) {
1655 if((wbuf = icsmbstowcs(fields[i], DCCHARSET, NULL)) == NULL) {
efea2eaf 1656 fields[i] = sstrdup(_("(Invalid character)"));
1657 } else {
1658 if((fields[i] = icwcstombs(wbuf, "UTF-8")) == NULL)
1659 break;
d3372da9 1660 }
d3372da9 1661 }
a745644c 1662 if(i == 4) {
1663 if(!filterpubhub || !regexec(&pubhubfilter, fields[0], 0, NULL, 0) || !regexec(&pubhubfilter, fields[2], 0, NULL, 0)) {
1664 gtk_list_store_append(model, &iter);
1665 gtk_list_store_set(model, &iter, 0, fields[1], 1, fields[0], 2, fields[2], 3, atoi(fields[3]), -1);
1666 }
d3372da9 1667 }
1668 for(i--; i >= 0; i--)
1669 free(fields[i]);
1670 }
a745644c 1671 memmove(buf, p, *len -= p - buf);
1672 }
1673 break;
1674 case PHO_EOF:
eba4327a 1675 cols[0] = 3; names[0] = _("# users");
1676 cols[1] = 1; names[1] = _("Name");
1677 cols[2] = 2; names[2] = _("Description");
1678 setpubhubmodel(GTK_TREE_MODEL(model), 3, 3, cols, names);
a745644c 1679 break;
1680 case PHO_FINI:
1681 if(model != NULL)
1682 g_object_unref(model);
1683 model = NULL;
1684 break;
1685 }
1686 return(0);
1687}
1688
1689void pubhubfdcallback(gpointer data, gint source, GdkInputCondition condition)
1690{
1691 static char buf[65536];
1692 static size_t bufpos = 0;
1693 int ret, reset;
1694
1695 if(!(condition & GDK_INPUT_READ))
1696 return;
1697 if(bufpos == sizeof(buf))
1698 bufpos = 0;
1699 ret = read(pubhubfd, buf + bufpos, sizeof(buf) - bufpos);
1700 reset = 0;
1701 if(ret <= 0)
1702 {
1703 if(ret < 0)
1704 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not read from public hub listing process: %s"), strerror(errno));
1705 else
eba4327a 1706 pubhubhandler(PHO_EOF, NULL, NULL);
a745644c 1707 reset = 1;
1708 } else {
1709 bufpos += ret;
1710 if(pubhubhandler(PHO_DATA, buf, &bufpos))
1711 reset = 1;
1712 }
1713 if(reset)
1714 {
1715 pubhubhandler(PHO_FINI, NULL, NULL);
1716 pubhubhandler = NULL;
1717 gdk_input_remove(pubhubtag);
1718 close(pubhubfd);
1719 kill(pubhubproc, SIGINT);
1720 pubhubfd = pubhubtag = -1;
1721 pubhubproc = 0;
1722 bufpos = 0;
1723 if(filterpubhub)
1724 {
1725 regfree(&pubhubfilter);
1726 filterpubhub = 0;
d3372da9 1727 }
d3372da9 1728 }
d3372da9 1729}
1730
1731void cb_main_pubhubfilter_activate(GtkWidget *widget, gpointer data)
1732{
1733 int pipe1[2], pipe2[2];
1734 int len, err;
a745644c 1735 const char *buf, *p;
d3372da9 1736 char errbuf[1024];
1737
1738 if(pubhubtag >= 0)
1739 gdk_input_remove(pubhubtag);
1740 if(pubhubfd >= 0)
1741 close(pubhubfd);
1742 if(pubhubproc > 0)
1743 kill(pubhubproc, SIGINT);
a745644c 1744 if(pubhubhandler != NULL)
1745 {
1746 pubhubhandler(PHO_FINI, NULL, NULL);
1747 pubhubhandler = NULL;
1748 }
d3372da9 1749 if(filterpubhub)
1750 {
1751 regfree(&pubhubfilter);
1752 filterpubhub = 0;
1753 }
1754 buf = gtk_entry_get_text(GTK_ENTRY(main_pubhubfilter));
1755 if(*buf)
1756 {
1757 if((err = regcomp(&pubhubfilter, buf, REG_EXTENDED | REG_ICASE | REG_NOSUB)) != 0)
1758 {
1759 regerror(err, &pubhubfilter, errbuf, sizeof(errbuf));
1760 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not compile regex: %s", errbuf);
1761 regfree(&pubhubfilter);
1762 filterpubhub = 0;
1763 return;
1764 }
1765 filterpubhub = 1;
1766 }
d3372da9 1767 pipe(pipe1);
1768 if((pubhubproc = fork()) == 0)
1769 {
1770 dup2(pipe1[1], 1);
1771 close(pipe1[0]);
1772 close(pipe1[1]);
1773 execlp("wget", "wget", "-qO", "-", pubhubaddr, NULL);
1774 perror("wget");
1775 exit(127);
1776 }
1777 close(pipe1[1]);
1778 pubhubfd = pipe1[0];
1779 len = strlen(pubhubaddr);
a745644c 1780 p = pubhubaddr + len;
1781 if((len > 4) && !strncmp(p - 4, ".bz2", 4))
d3372da9 1782 {
a745644c 1783 p -= 4;
1784 len -= 4;
d3372da9 1785 pipe(pipe2);
1786 if(fork() == 0)
1787 {
1788 dup2(pipe1[0], 0);
1789 dup2(pipe2[1], 1);
1790 close(pipe1[0]);
1791 close(pipe2[0]);
1792 close(pipe2[1]);
1793 execlp("bzcat", "bzcat", NULL);
1794 perror("bzcat");
1795 exit(127);
1796 }
1797 close(pipe1[0]);
1798 close(pipe2[1]);
1799 pubhubfd = pipe2[0];
1800 }
a745644c 1801 if((len > 4) && !strncmp(p - 4, ".xml", 4))
1802 {
1803 p -= 4;
1804 len -= 4;
eba4327a 1805 pubhubhandler = pubhubxmlhandler;
a745644c 1806 } else {
1807 pubhubhandler = pubhuboldhandler;
1808 }
1809 pubhubhandler(PHO_INIT, NULL, NULL);
d3372da9 1810 pubhubtag = gdk_input_add(pubhubfd, GDK_INPUT_READ, pubhubfdcallback, NULL);
1811}
1812
1813void cb_main_dcnctbtn_clicked(GtkWidget *widget, gpointer data)
1814{
1815 GtkTreeIter iter;
1816 int tag, id;
1817 struct dc_response *resp;
1818
1819 if(dcfd < 0)
1820 {
1821 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Not connected to DC server"));
1822 return;
1823 }
1824 if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(main_fnetnodes)), NULL, &iter))
1825 {
1826 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("No hub selected"));
1827 return;
1828 }
1829 gtk_tree_model_get(GTK_TREE_MODEL(fnmodel), &iter, 0, &id, -1);
0931eb36 1830 tag = dc_queuecmd(NULL, NULL, L"dcnct", L"%i", id, NULL);
d3372da9 1831 if((resp = dc_gettaggedrespsync(tag)) != NULL)
1832 {
1833 if(resp->code == 502)
1834 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
1835 dc_freeresp(resp);
1836 }
1837 handleresps();
1838}
1839
1840void cb_main_phublist_cchange(GtkWidget *widget, gpointer data)
1841{
1842 GtkTreeIter iter;
1843 GtkTreeModel *model;
1844 char *addr;
1845
1846 if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(main_phublist)), &model, &iter))
1847 return;
a745644c 1848 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &addr, -1);
d3372da9 1849 gtk_entry_set_text(GTK_ENTRY(main_fnaddr), addr);
1850 g_free(addr);
1851}
1852
1853void cb_main_phublist_activate(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
1854{
1855 int tag;
1856 struct dc_response *resp;
1857 GtkTreeIter iter;
1858 GtkTreeModel *model;
1859 char *buf;
1860
1861 if(dcfd < 0)
1862 {
1863 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Not connected to DC server"));
1864 return;
1865 }
1866 model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
1867 if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path))
1868 return;
a745644c 1869 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &buf, -1);
d3372da9 1870 if(strchr(buf, ':') == NULL)
1871 {
1872 buf = g_realloc(buf, strlen(buf) + 5);
1873 strcat(buf, ":411");
1874 }
0931eb36 1875 tag = dc_queuecmd(NULL, NULL, L"cnct", L"dc", L"%s", buf, NULL);
d3372da9 1876 g_free(buf);
1877 gtk_entry_set_text(GTK_ENTRY(main_fnaddr), "");
1878 if((resp = dc_gettaggedrespsync(tag)) != NULL)
1879 {
1880 if(resp->code == 502)
1881 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
1882 if(resp->code == 509)
1883 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The server could not parse that address"));
eaf3d948 1884 if(resp->code == 515)
1885 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("There are too many hubs connected"));
d3372da9 1886 dc_freeresp(resp);
1887 }
1888 handleresps();
1889}
1890
1891void cb_main_chatnodes_activate(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col, gpointer uudata)
1892{
1893 GtkTreeIter iter;
1894 int id;
1895 struct dc_fnetnode *fn;
1896 struct fndata *data;
1897
1898 if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(fnmodel), &iter, path))
1899 return;
1900 gtk_tree_model_get(GTK_TREE_MODEL(fnmodel), &iter, 0, &id, -1);
1901 if((fn = dc_findfnetnode(id)) == NULL)
1902 return;
1903 data = fn->udata;
1904 curchat = id;
1905 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(fnmodel), &iter))
1906 {
1907 do
1908 {
1909 gtk_tree_model_get(GTK_TREE_MODEL(fnmodel), &iter, 0, &id, -1);
1910 if(id == curchat)
1911 gtk_list_store_set(fnmodel, &iter, 5, "gtk-apply", -1);
1912 else
1913 gtk_list_store_set(fnmodel, &iter, 5, NULL, -1);
1914 } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(fnmodel), &iter));
1915 }
1916 gtk_text_view_set_buffer(GTK_TEXT_VIEW(main_chatview), GTK_TEXT_BUFFER(data->textbuf));
1917}
1918
1919void cb_main_chatstr_activate(GtkWidget *widget, gpointer data)
1920{
1921 int tag;
1922 const char *buf;
1923 struct dc_response *resp;
1924
1925 if(dcfd < 0)
1926 {
1927 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Not connected to DC server"));
1928 return;
1929 }
1930 if(curchat < 0)
1931 {
1932 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("No hub selected"));
1933 return;
1934 }
1935 buf = gtk_entry_get_text(GTK_ENTRY(main_chatstr));
0931eb36 1936 tag = dc_queuecmd(NULL, NULL, L"sendchat", L"%i", curchat, L"1", L"", L"%s", buf, NULL);
d3372da9 1937 if((resp = dc_gettaggedrespsync(tag)) != NULL)
1938 {
1939 if(resp->code == 502)
1940 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
1941 else if(resp->code == 504)
1942 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("This hub could not support all the types of characters in your chat message"));
1943 else if(resp->code == 513)
1944 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("This hub does not support chatting"));
1945 else if(resp->code != 200)
1946 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("An error occurred while trying to chat (%i)"), resp->code);
1947 dc_freeresp(resp);
1948 }
1949 gtk_entry_set_text(GTK_ENTRY(main_chatstr), "");
1950 handleresps();
1951}
1952
1953void updatesrchfld(const char *simple)
1954{
1955 char *buf, *s;
1956 char *p, *p2;
1957 size_t bufsize, bufdata;
1958
1959 s = sstrdup(simple);
1960 buf = NULL;
1961 bufsize = bufdata = 0;
1962 p = s;
1963 do
1964 {
1965 p2 = strchr(p, ' ');
1966 if(p2 != NULL)
1967 *(p2++) = 0;
1968 if(*p)
1969 {
1970 if(bufdata > 0)
1971 bufcat(buf, " & ", 3);
1972 bufcat(buf, "N~", 2);
1973 for(; *p; p++)
1974 {
ab9f4164 1975 if(strchr("[]()$^.*?+\\|\"!", *p) != NULL)
d3372da9 1976 addtobuf(buf, '\\');
1977 addtobuf(buf, *p);
1978 }
1979 }
1980 p = p2;
1981 } while(p2 != NULL);
1982 addtobuf(buf, 0);
1983 gtk_entry_set_text(GTK_ENTRY(main_realsrch), buf);
1984 free(buf);
1985 free(s);
1986}
1987
1988void cb_main_simplesrch_changed(GtkWidget *widget, gpointer data)
1989{
1990 if(srchautoupdate)
1991 return;
1992 srchautoupdate = 1;
1993 updatesrchfld(gtk_entry_get_text(GTK_ENTRY(main_simplesrch)));
1994 srchautoupdate = 0;
1995}
1996
1997void cb_main_realsrch_changed(GtkWidget *widget, gpointer data)
1998{
1999 if(srchautoupdate)
2000 return;
2001 srchautoupdate = 1;
2002 gtk_entry_set_text(GTK_ENTRY(main_simplesrch), "");
2003 srchautoupdate = 0;
2004}
2005
2006void cb_main_srchbtn_clicked(GtkWidget *widget, gpointer data)
2007{
2008 wchar_t **toks;
2009 int tag;
2010 struct dc_response *resp;
2011 struct dc_intresp *ires;
2012
2013 if(dcfd < 0)
2014 {
2015 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Not connected to DC server"));
2016 return;
2017 }
2018 if(nextsrch != -1) /* Impossible case, but oh well... */
2019 return;
2020 toks = dc_lexsexpr(icsmbstowcs((char *)gtk_entry_get_text(GTK_ENTRY(main_realsrch)), "UTF-8", NULL));
2021 if(*toks == NULL)
2022 {
2023 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Please enter a search expression before searching"));
2024 return;
2025 }
0931eb36 2026 tag = dc_queuecmd(NULL, NULL, L"search", L"all", L"%a", toks, NULL);
d3372da9 2027 dc_freewcsarr(toks);
2028 if((resp = dc_gettaggedrespsync(tag)) != NULL)
2029 {
2030 if(resp->code == 501)
2031 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Could not find any hubs to search on"));
2032 else if(resp->code == 502)
2033 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
2034 else if(resp->code == 509)
2035 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The server could not parse your search expression"));
2036 else if(resp->code != 200)
2037 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("An error occurred while trying to search (%i)"), resp->code);
2038 if(resp->code == 200)
2039 {
2040 if((ires = dc_interpret(resp)) != NULL)
2041 {
2042 nextsrch = ires->argv[0].val.num;
2043 srcheta = time(NULL) + ires->argv[1].val.num;
2044 dc_freeires(ires);
2045 }
2046 gtk_widget_set_sensitive(main_realsrch, FALSE);
2047 gtk_widget_set_sensitive(main_simplesrch, FALSE);
2048 gtk_widget_set_sensitive(main_srchbtn, FALSE);
2049 gtk_widget_set_sensitive(main_srchcanbtn, TRUE);
2050 srchstatupdate();
2051 }
2052 dc_freeresp(resp);
2053 }
2054 handleresps();
2055}
2056
2057void cb_main_srchcanbtn_clicked(GtkWidget *widget, gpointer data)
2058{
2059 if(nextsrch == -1)
2060 return;
0931eb36 2061 dc_queuecmd(NULL, NULL, L"cansrch", L"%i", nextsrch, NULL);
d3372da9 2062 nextsrch = -1;
2063 gtk_widget_set_sensitive(main_realsrch, TRUE);
2064 gtk_widget_set_sensitive(main_simplesrch, TRUE);
2065 gtk_widget_set_sensitive(main_srchbtn, TRUE);
2066 gtk_widget_set_sensitive(main_srchcanbtn, FALSE);
2067 srchstatupdate();
2068}
2069
ab9f4164 2070gboolean cb_main_trlist_keypress(GtkWidget *widget, GdkEventKey *event, gpointer data)
d3372da9 2071{
2072 int id, tag;
2073 GtkTreeSelection *sel;
2074 GtkTreeModel *model;
2075 GtkTreeIter iter;
2076 struct dc_response *resp;
2077
2078 if((event->type == GDK_KEY_PRESS) && (event->keyval == GDK_Delete))
2079 {
2080 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
2081 if(gtk_tree_selection_get_selected(sel, &model, &iter))
2082 {
2083 gtk_tree_model_get(model, &iter, 0, &id, -1);
0931eb36 2084 tag = dc_queuecmd(NULL, NULL, L"cancel", L"%i", id, NULL);
d3372da9 2085 if((resp = dc_gettaggedrespsync(tag)) != NULL)
2086 {
2087 if(resp->code == 502)
2088 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
2089 else if(resp->code != 200)
2090 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("An error occurred while trying to cancel (%i)"), resp->code);
2091 dc_freeresp(resp);
2092 }
2093 handleresps();
2094 }
ab9f4164 2095 return(TRUE);
d3372da9 2096 }
ab9f4164 2097 return(FALSE);
d3372da9 2098}
2099
2100void cb_main_srchres_activate(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
2101{
2102 int tag;
2103 struct dc_response *resp;
2104 GtkTreeIter iter;
2105 GtkTreeModel *model;
2106 int size, num;
419385f3 2107 char *tfnet, *tpeerid, *tfilename, *thash, *arg;
2108 wchar_t *fnet, *peerid, *filename, *hash;
d3372da9 2109
2110 if(dcfd < 0)
2111 {
2112 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Not connected to DC server"));
2113 return;
2114 }
2115 model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
2116 if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path))
2117 return;
2118 gtk_tree_model_get(model, &iter, 7, &num, -1);
2119 if(num > 0)
2120 return;
419385f3 2121 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &tfnet, 1, &tpeerid, 3, &tfilename, 4, &size, 9, &thash, -1);
d3372da9 2122 fnet = icmbstowcs(tfnet, "UTF-8");
2123 peerid = icmbstowcs(tpeerid, "UTF-8");
2124 filename = icmbstowcs(tfilename, "UTF-8");
419385f3 2125 hash = (thash == NULL)?NULL:icmbstowcs(thash, "UTF-8");
d3372da9 2126 if((fnet == NULL) || (peerid == NULL) || (filename == NULL))
2127 {
2128 if(fnet != NULL)
2129 free(fnet);
2130 if(peerid != NULL)
2131 free(peerid);
2132 if(filename != NULL)
2133 free(filename);
419385f3 2134 if(hash != NULL)
2135 free(hash);
d3372da9 2136 g_free(tfnet);
2137 g_free(tpeerid);
2138 g_free(tfilename);
419385f3 2139 if(thash != NULL)
2140 g_free(thash);
d3372da9 2141 return;
2142 }
2143 g_free(tfnet);
2144 g_free(tpeerid);
2145 g_free(tfilename);
2146 arg = (char *)gtk_entry_get_text(GTK_ENTRY(main_dlarg));
2147 if(*arg)
0931eb36 2148 tag = dc_queuecmd(NULL, NULL, L"download", fnet, L"%ls", peerid, L"%ls", filename, L"%i", size, L"hash", L"%ls", (hash == NULL)?L"":hash, L"user", L"%s", arg, NULL);
d3372da9 2149 else
0931eb36 2150 tag = dc_queuecmd(NULL, NULL, L"download", fnet, L"%ls", peerid, L"%ls", filename, L"%i", size, L"hash", L"%ls", (hash == NULL)?L"":hash, NULL);
d3372da9 2151 free(fnet);
2152 free(peerid);
2153 free(filename);
419385f3 2154 if(hash != NULL)
2155 free(hash);
d3372da9 2156 if((resp = dc_gettaggedrespsync(tag)) != NULL)
2157 {
2158 if(resp->code == 502)
2159 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
2160 if(resp->code != 200)
2161 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("An error occurred while trying to queue the download (%i)"), resp->code);
2162 dc_freeresp(resp);
2163 }
2164 handleresps();
2165}
2166
2167gboolean srchfilterfunc(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
2168{
2169 int slots;
2170 int filteratall;
2171
2172 filteratall = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(main_filternoslots));
2173 if(!filteratall)
2174 return(TRUE);
2175 gtk_tree_model_get(model, iter, 5, &slots, -1);
2176 if(slots < 1)
2177 return(FALSE);
2178 return(TRUE);
2179}
2180
2181void cb_main_filternoslots_toggled(GtkToggleButton *widget, gpointer data)
2182{
2183 gtk_tree_model_filter_refilter(srchmodelfilter);
2184}
2185
ab9f4164 2186void cb_main_srhash_activate(GtkWidget *widget, gpointer data)
2187{
2188 GtkTreeSelection *sel;
2189 GtkTreeModel *model;
2190 GtkTreeIter iter;
2191 char *hash, *buf;
2192
2193 if(nextsrch != -1)
2194 return;
2195 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(main_srchres));
2196 if(gtk_tree_selection_get_selected(sel, &model, &iter))
2197 {
2198 gtk_tree_model_get(model, &iter, 9, &hash, -1);
2199 buf = sprintf2("H=%s", hash);
2200 gtk_entry_set_text(GTK_ENTRY(main_realsrch), buf);
2201 g_free(hash);
2202 free(buf);
2203 cb_main_srchbtn_clicked(widget, NULL);
2204 } else {
2205 return;
2206 }
2207}
2208
415daf6c 2209void cb_main_srcopy_activate(GtkWidget *widget, gpointer data)
2210{
2211 GtkClipboard *cb;
2212 GtkTreeSelection *sel;
2213 GtkTreeModel *model;
2214 GtkTreeIter iter;
2215 char *hash;
2216
2217 if(nextsrch != -1)
2218 return;
2219 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(main_srchres));
2220 if(!gtk_tree_selection_get_selected(sel, &model, &iter))
2221 return;
2222 gtk_tree_model_get(model, &iter, 9, &hash, -1);
2223 cb = gtk_clipboard_get(gdk_atom_intern("PRIMARY", FALSE));
2224 gtk_clipboard_set_text(cb, hash, -1);
2225 g_free(hash);
2226}
2227
ab9f4164 2228void cb_main_trhash_activate(GtkWidget *widget, gpointer data)
2229{
2230 GtkTreeSelection *sel;
2231 GtkTreeModel *model;
2232 GtkTreeIter iter;
2233 char *hash, *buf;
2234
2235 if(nextsrch != -1)
2236 return;
2237 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(main_downloads));
2238 if(gtk_tree_selection_get_selected(sel, &model, &iter))
2239 {
2240 gtk_tree_model_get(model, &iter, 12, &hash, -1);
2241 buf = sprintf2("H=%s", hash);
2242 gtk_entry_set_text(GTK_ENTRY(main_realsrch), buf);
2243 g_free(hash);
2244 free(buf);
2245 cb_main_srchbtn_clicked(widget, NULL);
2246 } else {
2247 return;
2248 }
2249}
2250
415daf6c 2251void cb_main_trcopy_activate(GtkWidget *widget, gpointer data)
2252{
2253 GtkClipboard *cb;
2254 GtkTreeSelection *sel;
2255 GtkTreeModel *model;
2256 GtkTreeIter iter;
2257 char *hash;
2258
2259 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(main_downloads));
2260 if(!gtk_tree_selection_get_selected(sel, &model, &iter))
2261 return;
2262 gtk_tree_model_get(model, &iter, 12, &hash, -1);
2263 cb = gtk_clipboard_get(gdk_atom_intern("PRIMARY", FALSE));
2264 gtk_clipboard_set_text(cb, hash, -1);
2265 g_free(hash);
2266}
2267
581ace46 2268void cb_main_trreset_activate(GtkWidget *widget, gpointer data)
419385f3 2269{
2270 GtkTreeSelection *sel;
2271 GtkTreeModel *model;
2272 GtkTreeIter iter;
2273 int id, tag;
2274 struct dc_response *resp;
2275
581ace46 2276 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(main_downloads));
2277 if(gtk_tree_selection_get_selected(sel, &model, &iter))
2278 {
2279 gtk_tree_model_get(model, &iter, 0, &id, -1);
2280 tag = dc_queuecmd(NULL, NULL, L"reset", L"%i", id, NULL);
2281 if((resp = dc_gettaggedrespsync(tag)) != NULL)
2282 {
2283 if(resp->code == 502)
2284 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
2285 else if(resp->code != 200)
2286 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("An error occurred while trying to reset (%i)"), resp->code);
2287 dc_freeresp(resp);
2288 }
2289 handleresps();
2290 } else {
419385f3 2291 return;
581ace46 2292 }
2293}
2294
2295void cb_main_trcancel_activate(GtkWidget *widget, gpointer data)
2296{
2297 GtkTreeSelection *sel;
2298 GtkTreeModel *model;
2299 GtkTreeIter iter;
2300 int id, tag;
2301 struct dc_response *resp;
2302
419385f3 2303 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(main_downloads));
2304 if(gtk_tree_selection_get_selected(sel, &model, &iter))
2305 {
2306 gtk_tree_model_get(model, &iter, 0, &id, -1);
0931eb36 2307 tag = dc_queuecmd(NULL, NULL, L"cancel", L"%i", id, NULL);
419385f3 2308 if((resp = dc_gettaggedrespsync(tag)) != NULL)
2309 {
2310 if(resp->code == 502)
2311 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("You do not have permission to do that"));
2312 else if(resp->code != 200)
2313 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("An error occurred while trying to cancel (%i)"), resp->code);
2314 dc_freeresp(resp);
2315 }
2316 handleresps();
2317 } else {
2318 return;
2319 }
2320}
2321
ab9f4164 2322/* XXX: This is quite a hack, since the calling convention is
2323 * different for the popup-menu sig and the button-press-event sig. It
2324 * most certainly works, but I don't know how portable it is. */
2325gboolean cb_main_srpopup(GtkWidget *widget, GdkEventButton *event, gpointer data)
2326{
2327 GtkTreeSelection *sel;
2328 GtkTreeModel *model;
2329 GtkTreeIter iter;
2330 char *hash;
2331
2332 if((event != NULL) && (event->button != 3))
2333 return(FALSE);
2334 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
2335 if(gtk_tree_selection_get_selected(sel, &model, &iter))
2336 {
2337 gtk_tree_model_get(model, &iter, 9, &hash, -1);
4c27a5f2 2338 if((hash == NULL) || (*hash == 0))
415daf6c 2339 {
ab9f4164 2340 gtk_widget_set_sensitive(main_srhash, FALSE);
415daf6c 2341 gtk_widget_set_sensitive(main_srcopy, FALSE);
2342 } else {
4c27a5f2 2343 if(nextsrch == -1)
2344 gtk_widget_set_sensitive(main_srhash, TRUE);
2345 else
2346 gtk_widget_set_sensitive(main_srhash, FALSE);
415daf6c 2347 gtk_widget_set_sensitive(main_srcopy, TRUE);
2348 }
ab9f4164 2349 g_free(hash);
2350 } else {
2351 return(FALSE);
2352 }
2353 if(event == NULL)
2354 gtk_menu_popup(GTK_MENU(main_srpopup), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
2355 else
2356 gtk_menu_popup(GTK_MENU(main_srpopup), NULL, NULL, NULL, NULL, event->button, event->time);
2357 return(FALSE);
2358}
2359
2360/* The above hack note goes for this one too. */
2361gboolean cb_main_trpopup(GtkWidget *widget, GdkEventButton *event, gpointer data)
2362{
2363 GtkTreeSelection *sel;
2364 GtkTreeModel *model;
2365 GtkTreeIter iter;
2366 char *hash;
2367
2368 if((event != NULL) && (event->button != 3))
2369 return(FALSE);
2370 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
2371 if(gtk_tree_selection_get_selected(sel, &model, &iter))
2372 {
2373 gtk_tree_model_get(model, &iter, 12, &hash, -1);
4c27a5f2 2374 if((hash == NULL) || (*hash == 0))
415daf6c 2375 {
ab9f4164 2376 gtk_widget_set_sensitive(main_trhash, FALSE);
415daf6c 2377 gtk_widget_set_sensitive(main_trcopy, FALSE);
2378 } else {
4c27a5f2 2379 if(nextsrch == -1)
2380 gtk_widget_set_sensitive(main_trhash, TRUE);
2381 else
2382 gtk_widget_set_sensitive(main_trhash, FALSE);
415daf6c 2383 gtk_widget_set_sensitive(main_trcopy, TRUE);
2384 }
ab9f4164 2385 g_free(hash);
2386 } else {
2387 return(FALSE);
2388 }
2389 if(event == NULL)
2390 gtk_menu_popup(GTK_MENU(main_trpopup), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());
2391 else
2392 gtk_menu_popup(GTK_MENU(main_trpopup), NULL, NULL, NULL, NULL, event->button, event->time);
2393 return(FALSE);
2394}
2395
4c27a5f2 2396void cb_reslist_reload_clicked(GtkWidget *widget, gpointer data)
2397{
2398 if(lsrestag != -1)
2399 return;
2400 gtk_widget_set_sensitive(reslist_delete, FALSE);
2401 gtk_widget_set_sensitive(reslist_search, FALSE);
2402 gtk_list_store_clear(reslist);
2403 lsrestag = dc_queuecmd(NULL, NULL, L"filtercmd", L"lsres", NULL);
2404 gtk_widget_set_sensitive(reslist_reload, FALSE);
2405}
2406
2407int rmres(char *id)
2408{
2409 int tag, ret;
2410 struct dc_response *resp;
2411
2412 ret = -1;
0931eb36 2413 tag = dc_queuecmd(NULL, NULL, L"filtercmd", L"rmres", L"%s", id, NULL);
4c27a5f2 2414 if((resp = dc_gettaggedrespsync(tag)) != NULL)
2415 {
2416 if(resp->numlines > 0)
2417 {
2418 if(!wcscmp(resp->rlines[0].argv[1], L"ok"))
2419 ret = 0;
2420 else if(!wcsncmp(resp->rlines[0].argv[1], L"err:", 4))
2421 msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("An error occurred (%ls)"), resp->rlines[0].argv[1] + 4);
2422 }
2423 dc_freeresp(resp);
2424 }
2425 handleresps();
2426 return(ret);
2427}
2428
2429void cb_reslist_delete_clicked(GtkWidget *widget, gpointer data)
2430{
2431 GtkTreeIter iter;
2432 GtkTreeModel *model;
2433 char *id;
2434 gboolean locked;
2435
2436 if(nextsrch != -1)
2437 return;
2438 if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(reslist_list)), &model, &iter))
2439 return;
2440 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &id, 4, &locked, -1);
2441 if(locked)
2442 {
2443 g_free(id);
2444 return;
2445 }
2446 if(!rmres(id))
2447 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
2448 g_free(id);
2449}
2450
2451void cb_reslist_search_clicked(GtkWidget *widget, gpointer data)
2452{
2453 GtkTreeIter iter;
2454 GtkTreeModel *model;
2455 char *hash, *buf;
2456
2457 if(nextsrch != -1)
2458 return;
2459 if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(reslist_list)), &model, &iter))
2460 return;
2461 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 5, &hash, -1);
2462 buf = sprintf2("H=%s", hash);
2463 gtk_entry_set_text(GTK_ENTRY(main_realsrch), buf);
2464 free(buf);
2465 g_free(hash);
2466 cb_main_srchbtn_clicked(widget, NULL);
2467}
2468
2469void cb_reslist_list_cchange(GtkWidget *widget, gpointer data)
2470{
2471 GtkTreeIter iter;
2472 GtkTreeModel *model;
2473 gboolean locked;
2474 char *hash;
2475
2476 if(!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(reslist_list)), &model, &iter))
2477 {
2478 gtk_widget_set_sensitive(reslist_delete, FALSE);
2479 gtk_widget_set_sensitive(reslist_search, FALSE);
2480 return;
2481 }
2482 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 4, &locked, 5, &hash, -1);
2483 gtk_widget_set_sensitive(reslist_delete, !locked);
2484 gtk_widget_set_sensitive(reslist_search, hash && *hash);
2485 g_free(hash);
2486}
2487
2488void cb_reslist_list_activate(GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data)
2489{
2490 GtkTreeIter iter;
2491 GtkTreeModel *model;
2492 char *hash, *buf;
2493
2494 model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
2495 if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path))
2496 return;
2497 if(nextsrch != -1)
2498 return;
2499 gtk_tree_model_get(model, &iter, 5, &hash, -1);
2500 buf = sprintf2("H=%s", hash);
2501 gtk_entry_set_text(GTK_ENTRY(main_realsrch), buf);
2502 free(buf);
2503 g_free(hash);
2504 cb_main_srchbtn_clicked(widget, NULL);
2505}
2506
2507gboolean cb_reslist_list_keypress(GtkWidget *widget, GdkEventKey *event, gpointer data)
2508{
2509 GtkTreeSelection *sel;
2510 GtkTreeModel *model;
2511 GtkTreeIter iter;
2512 char *id;
2513 gboolean locked;
2514
2515 if((event->type == GDK_KEY_PRESS) && (event->keyval == GDK_Delete))
2516 {
2517 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
2518 if(gtk_tree_selection_get_selected(sel, &model, &iter))
2519 {
2520 gtk_tree_model_get(model, &iter, 0, &id, 4, &locked, -1);
2521 if(!locked)
2522 {
2523 if(!rmres(id))
2524 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
2525 }
2526 g_free(id);
2527 }
2528 return(TRUE);
2529 }
2530 return(FALSE);
2531}
2532
d3372da9 2533void srchstatupdate(void)
2534{
2535 char buf[1024];
2536
2537 if(nextsrch == -1)
2538 {
2539 snprintf(buf, 1024, _("Ready to search"));
2540 } else {
2541 snprintf(buf, 1024, _("Search scheduled and will be submitted in %i seconds"), (int)(srcheta - time(NULL)));
2542 }
2543 if(strcmp(gtk_label_get_text(GTK_LABEL(main_srchstatus)), buf))
2544 gtk_label_set_text(GTK_LABEL(main_srchstatus), buf);
2545}
2546
2547gint srchstatupdatecb(gpointer data)
2548{
2549 srchstatupdate();
2550 return(TRUE);
2551}
2552
2553void initchattags(void)
2554{
2555 GtkTextTag *tag;
2556
2557 chattags = gtk_text_tag_table_new();
2558 tag = gtk_text_tag_new("sender");
2559 g_object_set(tag, "foreground", "blue", NULL);
2560 gtk_text_tag_table_add(chattags, tag);
2561}
2562
2563int main(int argc, char **argv)
2564{
2565 GtkWidget *wnd;
2566 PangoFontDescription *monospacefont;
2567 GtkTreeModel *sortmodel;
2568 struct passwd *pwent;
2569
2570 setlocale(LC_ALL, "");
2571 bindtextdomain(PACKAGE, LOCALEDIR);
2572 textdomain(PACKAGE);
2573 gtk_init(&argc, &argv);
2574 dc_init();
2575 signal(SIGCHLD, SIG_IGN);
9ebbbe20 2576 pubhubaddr = sstrdup("http://www.hublist.org/PublicHubList.xml.bz2");
65bf229b 2577 dcserver = sstrdup("");
d3372da9 2578 if((pwent = getpwuid(getuid())) == NULL)
2579 {
2580 fprintf(stderr, "could not get your passwd data");
2581 exit(1);
2582 }
2583 connectas = sstrdup(pwent->pw_name);
2584 wnd = create_main_wnd();
4c27a5f2 2585 create_reslist_wnd();
2586 gtk_window_resize(GTK_WINDOW(reslist_wnd), 600, 400);
d3372da9 2587 initchattags();
2588
2589 fnmodel = gtk_list_store_new(6, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING);
2590 gtk_tree_view_set_model(GTK_TREE_VIEW(main_fnetnodes), GTK_TREE_MODEL(fnmodel));
2591 gtk_tree_view_set_model(GTK_TREE_VIEW(main_chatnodes), GTK_TREE_MODEL(fnmodel));
4c27a5f2 2592
2593 reslist = gtk_list_store_new(6, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_STRING);
2594 gtk_tree_view_set_model(GTK_TREE_VIEW(reslist_list), GTK_TREE_MODEL(reslist));
2595
ab9f4164 2596 dlmodel = gtk_list_store_new(13, G_TYPE_INT, /* id */
d3372da9 2597 G_TYPE_INT, /* dir */
2598 G_TYPE_INT, /* state */
2599 G_TYPE_STRING, /* peerid */
2600 G_TYPE_STRING, /* peernick */
2601 G_TYPE_STRING, /* path */
2602 G_TYPE_INT, /* size */
2603 G_TYPE_INT, /* curpos */
2604 G_TYPE_STRING, /* stock */
2605 G_TYPE_FLOAT, /* percentage */
2606 G_TYPE_INT, /* error */
ab9f4164 2607 G_TYPE_INT, /* errortime */
2608 G_TYPE_STRING); /* hash */
d3372da9 2609 gtk_tree_view_set_model(GTK_TREE_VIEW(main_downloads), GTK_TREE_MODEL(dlmodel));
2610
ab9f4164 2611 ulmodel = gtk_list_store_new(13, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING);
d3372da9 2612 gtk_tree_view_set_model(GTK_TREE_VIEW(main_uploads), GTK_TREE_MODEL(ulmodel));
2613
ab9f4164 2614 srchmodel = gtk_tree_store_new(10, G_TYPE_STRING, /* fnetname */
2615 G_TYPE_STRING, /* peerid */
2616 G_TYPE_STRING, /* peername */
2617 G_TYPE_STRING, /* filename */
2618 G_TYPE_INT, /* size */
2619 G_TYPE_INT, /* slots */
2620 G_TYPE_DOUBLE, /* resptime */
2621 G_TYPE_INT, /* sizenum */
2622 G_TYPE_INT, /* speed */
2623 G_TYPE_STRING); /* hash */
d3372da9 2624 srchmodelfilter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(srchmodel), NULL));
2625 gtk_tree_model_filter_set_visible_func(srchmodelfilter, srchfilterfunc, NULL, NULL);
2626 sortmodel = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(srchmodelfilter));
2627 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(sortmodel), 4, GTK_SORT_DESCENDING);
2628 gtk_tree_view_set_model(GTK_TREE_VIEW(main_srchres), GTK_TREE_MODEL(sortmodel));
2629 g_object_unref(sortmodel);
2630
2631 monospacefont = pango_font_description_from_string("Monospace 10");
2632 gtk_widget_modify_font(main_chatview, monospacefont);
2633 pango_font_description_free(monospacefont);
2634 readconfigfile();
2635 updatesbar(_("Disconnected"));
2636 gtk_widget_show(wnd);
2637 if(autoconn)
2638 dcconnect(dcserver);
2639 g_timeout_add(500, srchstatupdatecb, NULL);
2640 g_timeout_add(5000, ksupdatecb, NULL);
8d9ec191 2641 g_timeout_add(1000, updatetransfers, NULL);
d3372da9 2642 gtk_main();
2643 return(0);
2644}
b1099f1f
FT
2645
2646#include "mainwnd.gtk"
2647#include "inpdialog.gtk"
2648#include "pref.gtk"
2649#include "reslist.gtk"