1 #include "hx.h"
2 #include "main.h"
3 #include <stdio.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/stat.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include "xmalloc.h"
11 #include <gtk/gtk.h>
12 #include <gdk/gdkkeysyms.h>
13 #include <signal.h>
14 #include <fnmatch.h>
15 #include <ctype.h>
16 #include <dirent.h>
17 #include <glib.h>
18 #include "gtk_hlist.h"
19 #include "history.h"
20 #include "macres.h"
21
22 #define SCROLLBAR_SPACING(w) (GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT(w)->klass)->scrollbar_spacing)
23
24 #define ICON_RELOAD 205
25 #define ICON_DOWNLOAD 210
26 #define ICON_UPLOAD 211
27 #define ICON_FILE 400
28 #define ICON_FOLDER 401
29 #define ICON_FOLDER_IN 421
30 #define ICON_FILE_HTft 402
31 #define ICON_FILE_SIT 403
32 #define ICON_FILE_TEXT 404
33 #define ICON_FILE_IMAGE 406
34 #define ICON_FILE_APPL 407
35 #define ICON_FILE_HTLC 408
36 #define ICON_FILE_SITP 409
37 #define ICON_FILE_alis 422
38 #define ICON_FILE_DISK 423
39 #define ICON_FILE_NOTE 424
40 #define ICON_FILE_MOOV 425
41 #define ICON_FILE_ZIP 426
42 #define ICON_INFO 215
43 #define ICON_PREVIEW 217
44 #define ICON_TRASH 212
45 #define ICON_MSG 206
46 #define ICON_KICK 412
47 #define ICON_BAN 2003
48 #define ICON_NUKE 2003
49 #define ICON_CHAT 415
50 #define ICON_STOP 213
51 #define ICON_GO 216
52 #define ICON_NEWS 413
53 #define ICON_CONNECT 411
54 #define ICON_USER 414
55 #define ICON_YELLOWUSER 417
56 #define ICON_BLACKUSER 418
57 #define ICON_TASKS 416
58 #define ICON_OPTIONS 419
59 #define ICON_TRACKER 420
60
61 extern GdkImage *cicn_to_gdkimage (GdkColormap *colormap, GdkVisual *visual,
62 char *cicndata, unsigned int len, GdkImage **maskimp);
63
64 struct mchat {
65 guint16 uid;
66 struct ghx_window *window;
67 };
68
69 GList *mchat_list = 0;
70
71 struct ifn {
72 char **files;
73 macres_file **cicns;
74 unsigned int n;
75 };
76
77 struct ifn icon_files;
78 struct ifn user_icon_files;
79
80 struct pixmap_cache {
81 GdkPixmap *pixmap;
82 GdkBitmap *mask;
83 struct ifn *ifn;
84 u_int16_t icon;
85 u_int16_t width;
86 u_int16_t height;
87 u_int16_t depth;
88 };
89
90 #define PTYPE_NORMAL 0
91 #define PTYPE_AWAY 1
92
93 #ifdef CONFIG_DULLED
94 #define NPTYPES 2
95 #else
96 #define NPTYPES 1
97 #endif
98 static struct pixmap_cache *pixmap_cache[NPTYPES][256];
99 static unsigned int pixmap_cache_len[NPTYPES][256];
100
101 #define DEFAULT_ICON 128
102
103 static struct pixmap_cache *
pixmap_cache_look(u_int16_t icon,struct ifn * ifn,int ptype)104 pixmap_cache_look (u_int16_t icon, struct ifn *ifn, int ptype)
105 {
106 unsigned int len, i = icon % 256;
107 struct pixmap_cache *list = pixmap_cache[ptype][i];
108
109 if (list) {
110 len = pixmap_cache_len[ptype][i];
111 for (i = 0; i < len; i++) {
112 if (list[i].icon == icon && list[i].ifn == ifn)
113 return &list[i];
114 }
115 }
116
117 return 0;
118 }
119
120 static struct pixmap_cache *
pixmap_cache_add(u_int16_t icon,GdkPixmap * pixmap,GdkBitmap * mask,int width,int height,int depth,struct ifn * ifn,int ptype)121 pixmap_cache_add (u_int16_t icon, GdkPixmap *pixmap, GdkBitmap *mask,
122 int width, int height, int depth, struct ifn *ifn, int ptype)
123 {
124 unsigned int n, i = icon % 256;
125 struct pixmap_cache *list = pixmap_cache[ptype][i];
126
127 n = pixmap_cache_len[ptype][i];
128 list = realloc(list, (n + 1) * sizeof(struct pixmap_cache));
129 if (!list) {
130 pixmap_cache[ptype][i] = 0;
131 return 0;
132 }
133 list[n].pixmap = pixmap;
134 list[n].mask = mask;
135 list[n].ifn = ifn;
136 list[n].icon = icon;
137 list[n].width = width;
138 list[n].height = height;
139 list[n].depth = depth;
140 pixmap_cache[ptype][i] = list;
141 pixmap_cache_len[ptype][i] = n + 1;
142
143 gdk_pixmap_ref(pixmap);
144 if (mask)
145 gdk_bitmap_ref(mask);
146
147 return &list[n];
148 }
149
150 static GdkGC *users_gc;
151 static GdkGC *mask_gc;
152
153 #define TYPE_cicn 0x6369636e
154
155 #define default_pixc (load_icon(widget, DEFAULT_ICON, &user_icon_files, browser, 0))
156
157 static struct pixmap_cache *
load_icon(GtkWidget * widget,u_int16_t icon,struct ifn * ifn,int browser,int ptype)158 load_icon (GtkWidget *widget, u_int16_t icon, struct ifn *ifn, int browser, int ptype)
159 {
160 struct pixmap_cache *pixc;
161 GdkPixmap *pixmap;
162 GdkBitmap *mask;
163 GdkGC *gc;
164 GdkImage *image;
165 GdkImage *maskim;
166 GdkVisual *visual;
167 GdkColormap *colormap;
168 gint off, width, height, depth, x, y;
169 macres_res *cicn;
170 unsigned int i;
171
172 if (y || x) {} /* removes compiler warning */
173 #ifndef CONFIG_DULLED
174 ptype = 0;
175 #endif
176 pixc = pixmap_cache_look(icon, ifn, ptype);
177 if (pixc)
178 return pixc;
179
180 for (i = 0; i < ifn->n; i++) {
181 if (!ifn->cicns[i])
182 continue;
183 cicn = macres_file_get_resid_of_type(ifn->cicns[i], TYPE_cicn, icon);
184 if (cicn)
185 goto found;
186 }
187 if (icon == DEFAULT_ICON)
188 return 0;
189 if (!browser)
190 return load_icon(widget, DEFAULT_ICON, &user_icon_files, 0, ptype);
191 return 0;
192 found:
193 colormap = gtk_widget_get_colormap(widget);
194 visual = gtk_widget_get_visual(widget);
195 image = cicn_to_gdkimage(colormap, visual, cicn->data, cicn->datalen, &maskim);
196 if (!image)
197 return default_pixc;
198 depth = image->depth;
199 width = image->width;
200 height = image->height;
201 off = width > 400 ? 198 : 0;
202
203 #ifdef CONFIG_DULLED
204 if (ptype == PTYPE_AWAY) {
205 for (y = 0; y < height; y++) {
206 for (x = 0; x < width-off; x++) {
207 guint pixel;
208 gint r, g, b;
209 GdkColor col;
210
211 pixel = gdk_image_get_pixel(image, x, y);
212 switch (visual->depth) {
213 case 1:
214 r = g = b = pixel;
215 break;
216 case 8:
217 r = colormap->colors[pixel].red;
218 g = colormap->colors[pixel].green;
219 b = colormap->colors[pixel].blue;
220 break;
221 default:
222 r = (pixel & visual->red_mask) >> visual->red_shift;
223 g = (pixel & visual->green_mask) >> visual->green_shift;
224 b = (pixel & visual->blue_mask) >> visual->blue_shift;
225 +
226 r = r * (int)(0xff / (visual->red_mask >> visual->red_shift));
227 g = g * (int)(0xff / (visual->green_mask >> visual->green_shift));
228 b = b * (int)(0xff / (visual->blue_mask >> visual->blue_shift));
229 +
230 r = (r << 8)|0xff;
231 g = (g << 8)|0xff;
232 b = (b << 8)|0xff;
233 break;
234 }
235
236 /* g = (g + r + b)/6;
237 r = b = 0; */
238 /* r = (r * 2) / 3;
239 g = (g * 2) / 3;
240 b = (b * 2) / 3; */
241 /* r *= 2; if (r > 0xffff) r = 0xffff;
242 g *= 2; if (g > 0xffff) g = 0xffff;
243 b *= 2; if (b > 0xffff) b = 0xffff; */
244
245 r = (r + 65535) / 2; if (r > 0xffff) r = 0xffff;
246 g = (g + 65535) / 2; if (g > 0xffff) g = 0xffff;
247 b = (b + 65535) / 2; if (b > 0xffff) b = 0xffff;
248
249 col.pixel = 0;
250 col.red = r;
251 col.green = g;
252 col.blue = b;
253 if (!gdk_colormap_alloc_color(colormap, &col, 0, 1))
254 fprintf(stderr, "rgb_to_pixel: can't allocate %u/%u/%u\n",
255 r, g, b);
256 pixel = col.pixel;
257 gdk_image_put_pixel(image, x, y, pixel);
258 }
259 }
260 }
261 #endif
262
263 pixmap = gdk_pixmap_new(widget->window, width-off, height, depth);
264 if (!pixmap)
265 return default_pixc;
266 gc = users_gc;
267 if (!gc) {
268 gc = gdk_gc_new(pixmap);
269 if (!gc)
270 return default_pixc;
271 users_gc = gc;
272 }
273 gdk_draw_image(pixmap, gc, image, off, 0, 0, 0, width-off, height);
274 gdk_image_destroy(image);
275 if (maskim) {
276 mask = gdk_pixmap_new(widget->window, width-off, height, 1);
277 if (!mask)
278 return default_pixc;
279 gc = mask_gc;
280 if (!gc) {
281 gc = gdk_gc_new(mask);
282 if (!gc)
283 return default_pixc;
284 mask_gc = gc;
285 }
286 gdk_draw_image(mask, gc, maskim, off, 0, 0, 0, width-off, height);
287 gdk_image_destroy(maskim);
288 } else {
289 mask = 0;
290 }
291
292 pixc = pixmap_cache_add(icon, pixmap, mask, width-off, height, depth, ifn, ptype);
293
294 return pixc;
295 }
296
297 static void
init_icons(struct ifn * ifn,unsigned int i)298 init_icons (struct ifn *ifn, unsigned int i)
299 {
300 int fd;
301
302 ifn->cicns = xrealloc(ifn->cicns, sizeof(macres_file *) * ifn->n);
303 if (!ifn->files[i])
304 goto fark;
305 fd = open(ifn->files[i], O_RDONLY);
306 if (fd < 0) {
307 fark: ifn->cicns[i] = 0;
308 return;
309 }
310 ifn->cicns[i] = macres_file_open(fd);
311 }
312
313 static void
set_icon_files(struct ifn * ifn,const char * str,const char * varstr)314 set_icon_files (struct ifn *ifn, const char *str, const char *varstr)
315 {
316 const char *p;
317 unsigned int i, j;
318 char buf[MAXPATHLEN];
319
320 /* icon_files[*] */
321 if (varstr[10] != '[')
322 p = &varstr[16];
323 else
324 p = &varstr[11];
325 i = strtoul(p, 0, 0);
326 if (i >= ifn->n) {
327 ifn->files = xrealloc(ifn->files, sizeof(char *) * (i+1));
328 for (j = ifn->n; j < i; j++)
329 ifn->files[j] = 0;
330 ifn->n = i+1;
331 }
332 expand_tilde(buf, str);
333 ifn->files[i] = xstrdup(buf);
334 init_icons(ifn, i);
335 }
336
337 static GtkWidget *
icon_pixmap(GtkWidget * widget,u_int16_t icon)338 icon_pixmap (GtkWidget *widget, u_int16_t icon)
339 {
340 struct pixmap_cache *pixc;
341 GtkWidget *gtkpixmap;
342
343 pixc = load_icon(widget, icon, &icon_files, 0, 0);
344 if (!pixc)
345 return 0;
346 gtkpixmap = gtk_pixmap_new(pixc->pixmap, pixc->mask);
347
348 return gtkpixmap;
349 }
350
351 static GtkWidget *
icon_button_new(u_int16_t iconid,const char * str,GtkWidget * widget,GtkTooltips * tooltips)352 icon_button_new (u_int16_t iconid, const char *str, GtkWidget *widget, GtkTooltips *tooltips)
353 {
354 GtkWidget *btn;
355 GtkWidget *icon;
356
357 btn = gtk_button_new();
358 icon = icon_pixmap(widget, iconid);
359 if (icon)
360 gtk_container_add(GTK_CONTAINER(btn), icon);
361 gtk_tooltips_set_tip(tooltips, btn, str, 0);
362 gtk_widget_set_usize(btn, 24, 24);
363 return btn;
364 }
365
366 struct timer {
367 struct timer *next, *prev;
368 guint id;
369 int (*fn)();
370 void *ptr;
371 };
372
373 static struct timer *timer_list;
374
375 void
timer_add_secs(time_t secs,int (* fn)(),void * ptr)376 timer_add_secs (time_t secs, int (*fn)(), void *ptr)
377 {
378 struct timer *timer;
379 guint id;
380
381 id = gtk_timeout_add(secs * 1000, fn, ptr);
382
383 timer = xmalloc(sizeof(struct timer));
384 timer->next = 0;
385 timer->prev = timer_list;
386 if (timer_list)
387 timer_list->next = timer;
388 timer_list = timer;
389 timer->id = id;
390 timer->fn = fn;
391 timer->ptr = ptr;
392 }
393
394 void
timer_delete_ptr(void * ptr)395 timer_delete_ptr (void *ptr)
396 {
397 struct timer *timer, *prev;
398
399 for (timer = timer_list; timer; timer = prev) {
400 prev = timer->prev;
401 if (timer->ptr == ptr) {
402 if (timer->next)
403 timer->next->prev = timer->prev;
404 if (timer->prev)
405 timer->prev->next = timer->next;
406 if (timer == timer_list)
407 timer_list = timer->next;
408 gtk_timeout_remove(timer->id);
409 xfree(timer);
410 }
411 }
412 }
413
414 static void
hxd_gtk_input(gpointer data,int fd,GdkInputCondition cond)415 hxd_gtk_input (gpointer data, int fd, GdkInputCondition cond)
416 {
417 if (data) {} /* removes compiler warning */
418 if (cond == GDK_INPUT_READ) {
419 if (hxd_files[fd].ready_read)
420 hxd_files[fd].ready_read(fd);
421 } else if (cond == GDK_INPUT_WRITE) {
422 if (hxd_files[fd].ready_write)
423 hxd_files[fd].ready_write(fd);
424 }
425 }
426
427 void
hxd_fd_add(int fd)428 hxd_fd_add (int fd)
429 {
430 if (fd) {} /* removes compiler warning */
431 }
432
433 void
hxd_fd_del(int fd)434 hxd_fd_del (int fd)
435 {
436 if (fd) {} /* removes compiler warning */
437 }
438
439 static int rinput_tags[1024];
440 static int winput_tags[1024];
441
442 void
hxd_fd_set(int fd,int rw)443 hxd_fd_set (int fd, int rw)
444 {
445 int tag;
446
447 if (fd >= 1024) {
448 hxd_log("hx_gtk: fd %d >= 1024", fd);
449 hx_exit(0);
450 }
451 if (rw & FDR) {
452 if (rinput_tags[fd] != -1)
453 return;
454 tag = gdk_input_add(fd, GDK_INPUT_READ, hxd_gtk_input, 0);
455 rinput_tags[fd] = tag;
456 }
457 if (rw & FDW) {
458 if (winput_tags[fd] != -1)
459 return;
460 tag = gdk_input_add(fd, GDK_INPUT_WRITE, hxd_gtk_input, 0);
461 winput_tags[fd] = tag;
462 }
463 }
464
465 void
hxd_fd_clr(int fd,int rw)466 hxd_fd_clr (int fd, int rw)
467 {
468 int tag;
469
470 if (fd >= 1024) {
471 hxd_log("hx_gtk: fd %d >= 1024", fd);
472 hx_exit(0);
473 }
474 if (rw & FDR) {
475 tag = rinput_tags[fd];
476 gdk_input_remove(tag);
477 rinput_tags[fd] = -1;
478 }
479 if (rw & FDW) {
480 tag = winput_tags[fd];
481 gdk_input_remove(tag);
482 winput_tags[fd] = -1;
483 }
484 }
485
486 struct ghtlc_conn;
487
488 struct ghx_window {
489 struct ghx_window *next, *prev;
490 struct ghtlc_conn *ghtlc;
491 unsigned int wgi;
492 struct window_geometry *wg;
493 GtkWidget *widget;
494 };
495
496 struct gchat;
497 struct msgchat;
498 struct gtask;
499 struct gfile_list;
500 struct tracker_server;
501
502 struct ghtlc_conn {
503 struct ghtlc_conn *next, *prev;
504 struct htlc_conn *htlc;
505 unsigned int connected;
506 struct ghx_window *window_list;
507
508 GtkWidget *news_text;
509
510 struct gchat *gchat_list;
511
512 struct msgchat *msgchat_list;
513
514 GtkStyle *users_style;
515 GdkFont *users_font;
516 GdkFont *chat_font;
517
518 struct gtask *gtask_list;
519 GtkWidget *gtask_gtklist;
520
521 struct gfile_list *gfile_list;
522
523 GtkWidget *tracker_list;
524 struct tracker_server *tracker_server_list;
525 struct tracker_server *tracker_server_tail;
526
527 GtkWidget *toolbar_hbox;
528 GtkWidget *connectbtn, *disconnectbtn;
529 GtkWidget *chatbtn, *filesbtn, *newsbtn, *tasksbtn, *closebtn, *quitbtn;
530 GtkWidget *usersbtn, *usereditbtn, *trackerbtn, *optionsbtn, *aboutbtn;
531 GtkWidget *user_msgbtn, *user_infobtn, *user_kickbtn, *user_banbtn, *user_chatbtn;
532 GtkWidget *news_postbtn, *news_reloadbtn;
533 };
534
535 static struct ghtlc_conn *ghtlc_conn_list;
536
537 struct gchat {
538 struct gchat *next, *prev;
539 struct ghtlc_conn *ghtlc;
540 struct hx_chat *chat;
541 struct ghx_window *gwin;
542 unsigned int do_lf;
543 void *chat_history;
544 GtkWidget *chat_input_text;
545 GtkWidget *chat_output_text;
546 GtkWidget *chat_vscrollbar;
547 GtkWidget *chat_in_hbox;
548 GtkWidget *chat_out_hbox;
549 GtkWidget *subject_hbox;
550 GtkWidget *subject_entry;
551 GtkWidget *users_list;
552 GtkWidget *users_vbox;
553 };
554
555 static GdkColor colors[16];
556 static GdkColor gdk_user_colors[4];
557
558 static GdkColor *
colorgdk(u_int16_t color)559 colorgdk (u_int16_t color)
560 {
561 return &gdk_user_colors[color % 4];
562 }
563
564 struct connect_context;
565
566 static void create_toolbar_window (struct ghtlc_conn *ghtlc);
567 static struct connect_context *create_connect_window (struct ghtlc_conn *ghtlc);
568 static void open_news (gpointer data);
569 static void create_tasks_window (struct ghtlc_conn *ghtlc);
570 static void create_tracker_window (struct ghtlc_conn *ghtlc);
571 static void open_files (gpointer data);
572 static void open_users (gpointer data);
573 static void open_chat (gpointer data);
574
575 static gint chat_delete_event (gpointer data);
576 static struct gchat *gchat_with_widget (struct ghtlc_conn *ghtlc, GtkWidget *widget);
577 static struct ghtlc_conn *ghtlc_valid (struct ghtlc_conn *ghtlc);
578
579 static gint
key_press(GtkWidget * widget,GdkEventKey * event,gpointer data)580 key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
581 {
582 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
583 struct gchat *gchat;
584 guint k;
585
586 if (!ghtlc_valid(ghtlc))
587 return 0;
588
589 k = event->keyval;
590 /* MOD1 == ALT */
591 if ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_MOD1_MASK)) {
592 switch (k) {
593 case 'b':
594 create_toolbar_window(ghtlc);
595 break;
596 case 'f':
597 open_files(data);
598 break;
599 case 'h':
600 open_chat(data);
601 break;
602 case 'k':
603 create_connect_window(ghtlc);
604 break;
605 case 'n':
606 open_news(data);
607 break;
608 case 'q':
609 hx_exit(0);
610 break;
611 case 'r':
612 create_tracker_window(ghtlc);
613 break;
614 case 't':
615 create_tasks_window(ghtlc);
616 break;
617 case 'u':
618 if (!(event->state & GDK_CONTROL_MASK))
619 open_users(data);
620 break;
621 case 'w':
622 gchat = gchat_with_widget(ghtlc, widget);
623 if (gchat) {
624 int destroy;
625 if (!(gchat->chat && gchat->chat->cid))
626 destroy = 1;
627 else
628 destroy = 0;
629 chat_delete_event(gchat);
630 if (!destroy)
631 break;
632 }
633 gtk_widget_destroy(widget);
634 break;
635 default:
636 return 0;
637 }
638 }
639
640 return 1;
641 }
642
643 static void
keyaccel_attach(struct ghtlc_conn * ghtlc,GtkWidget * widget)644 keyaccel_attach (struct ghtlc_conn *ghtlc, GtkWidget *widget)
645 {
646 gtk_signal_connect(GTK_OBJECT(widget), "key_press_event",
647 GTK_SIGNAL_FUNC(key_press), ghtlc);
648 }
649
650 #define MSG_FROM_COLOR (&colors[9])
651 #define MSG_TO_COLOR (&colors[12])
652
653 static void
init_colors(GtkWidget * widget)654 init_colors (GtkWidget *widget)
655 {
656 GdkColormap *colormap;
657 int i;
658
659 colors[0].red = 0x0000;
660 colors[0].green = 00000;
661 colors[0].blue = 0x0000;
662 colors[1].red = 0xa000;
663 colors[1].green = 0x0000;
664 colors[1].blue = 0x0000;
665 colors[2].red = 0x0000;
666 colors[2].green = 0xa000;
667 colors[2].blue = 0x0000;
668 colors[3].red = 0xa000;
669 colors[3].green = 0xa000;
670 colors[3].blue = 0x0000;
671 colors[4].red = 0x0000;
672 colors[4].green = 0x0000;
673 colors[4].blue = 0xa000;
674 colors[5].red = 0xa000;
675 colors[5].green = 0x0000;
676 colors[5].blue = 0xa000;
677 colors[6].red = 0x0000;
678 colors[6].green = 0xa000;
679 colors[6].blue = 0xa000;
680 colors[7].red = 0xa000;
681 colors[7].green = 0xa000;
682 colors[7].blue = 0xa000;
683 colors[8].red = 0x0000;
684 colors[8].green = 00000;
685 colors[8].blue = 0x0000;
686 colors[9].red = 0xffff;
687 colors[9].green = 0x0000;
688 colors[9].blue = 0x0000;
689 colors[10].red = 0x0000;
690 colors[10].green = 0xffff;
691 colors[10].blue = 0x0000;
692 colors[11].red = 0xffff;
693 colors[11].green = 0xffff;
694 colors[11].blue = 0x0000;
695 colors[12].red = 0x0000;
696 colors[12].green = 0x0000;
697 colors[12].blue = 0xffff;
698 colors[13].red = 0xffff;
699 colors[13].green = 0x0000;
700 colors[13].blue = 0xffff;
701 colors[14].red = 0x0000;
702 colors[14].green = 0xffff;
703 colors[14].blue = 0xffff;
704 colors[15].red = 0xffff;
705 colors[15].green = 0xffff;
706 colors[15].blue = 0xffff;
707
708 colormap = gtk_widget_get_colormap(widget);
709 for (i = 0; i < 16; i++) {
710 colors[i].pixel = (gulong)(((colors[i].red & 0xff00) << 8)
711 + (colors[i].green & 0xff00)
712 + ((colors[i].blue & 0xff00) >> 8));
713 if (!gdk_colormap_alloc_color(colormap, &colors[i], 0, 1))
714 hxd_log("alloc color failed");
715 }
716
717 gdk_user_colors[0].red = 0;
718 gdk_user_colors[0].green = 0;
719 gdk_user_colors[0].blue = 0;
720 gdk_user_colors[1].red = 0xa0a0;
721 gdk_user_colors[1].green = 0xa0a0;
722 gdk_user_colors[1].blue = 0xa0a0;
723 gdk_user_colors[2].red = 0xffff;
724 gdk_user_colors[2].green = 0;
725 gdk_user_colors[2].blue = 0;
726 gdk_user_colors[3].red = 0xffff;
727 gdk_user_colors[3].green = 0xa7a7;
728 gdk_user_colors[3].blue = 0xb0b0;
729 for (i = 0; i < 4; i++) {
730 colors[i].pixel = (gulong)(((gdk_user_colors[i].red & 0xff00) << 8)
731 + (gdk_user_colors[i].green & 0xff00)
732 + ((gdk_user_colors[i].blue & 0xff00) >> 8));
733 if (!gdk_colormap_alloc_color(colormap, &gdk_user_colors[i], 0, 1))
734 hxd_log("alloc color failed");
735 }
736 }
737
738 struct window_geometry {
739 u_int16_t width, height;
740 int16_t xpos, ypos;
741 int16_t xoff, yoff;
742 };
743
744 #define NWG 11
745 #define WG_CHAT 0
746 #define WG_TOOLBAR 1
747 #define WG_TASKS 2
748 #define WG_USERS 3
749 #define WG_NEWS 4
750 #define WG_POST 5
751 #define WG_TRACKER 6
752 #define WG_OPTIONS 7
753 #define WG_USEREDIT 8
754 #define WG_CONNECT 9
755 #define WG_FILES 10
756
757 static struct window_geometry default_window_geometry[NWG];
758
759 static struct window_geometry *
wg_get(unsigned int i)760 wg_get (unsigned int i)
761 {
762 return &default_window_geometry[i];
763 }
764
765 #if 0
766 static struct ghx_window *
767 ghx_window_with_widget (struct ghtlc_conn *ghtlc, GtkWidget *widget)
768 {
769 struct ghx_window *gwin;
770
771 for (gwin = ghtlc->window_list; gwin; gwin = gwin->prev) {
772 if (gwin->widget == widget)
773 return gwin;
774 }
775
776 return 0;
777 }
778 #endif
779
780 static gint
window_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer data)781 window_configure_event (GtkWidget *widget, GdkEventConfigure *event, gpointer data)
782 {
783 struct ghx_window *gwin = (struct ghx_window *)data;
784 struct window_geometry *wg = gwin->wg;
785
786 if (widget) {} /* removes compiler warning */
787 if (event->send_event) {
788 wg->xpos = event->x;
789 wg->ypos = event->y;
790 } else {
791 wg->width = event->width;
792 wg->height = event->height;
793 wg->xoff = event->x;
794 wg->yoff = event->y;
795 }
796
797 default_window_geometry[gwin->wgi] = *wg;
798
799 return 1;
800 }
801
802 static void
window_delete_all(struct ghtlc_conn * ghtlc)803 window_delete_all (struct ghtlc_conn *ghtlc)
804 {
805 struct ghx_window *gwin, *prev;
806
807 for (gwin = ghtlc->window_list; gwin; gwin = prev) {
808 prev = gwin->prev;
809 gtk_widget_destroy(gwin->widget);
810 }
811 }
812
813 static void ghtlc_conn_delete (struct ghtlc_conn *ghtlc);
814
815 static void
window_delete(struct ghx_window * gwin)816 window_delete (struct ghx_window *gwin)
817 {
818 struct ghtlc_conn *ghtlc = gwin->ghtlc;
819
820 if (gwin->next)
821 gwin->next->prev = gwin->prev;
822 if (gwin->prev)
823 gwin->prev->next = gwin->next;
824 if (gwin == ghtlc->window_list)
825 ghtlc->window_list = gwin->prev;
826 xfree(gwin);
827 if (!ghtlc->window_list)
828 ghtlc_conn_delete(ghtlc);
829 }
830
831 static void
window_destroy(GtkWidget * widget,gpointer data)832 window_destroy (GtkWidget *widget, gpointer data)
833 {
834 struct ghx_window *gwin = (struct ghx_window *)data;
835
836 if (widget) {} /* removes compiler warning */
837 window_delete(gwin);
838 }
839
840 static struct ghx_window *
window_create(struct ghtlc_conn * ghtlc,unsigned int wgi)841 window_create (struct ghtlc_conn *ghtlc, unsigned int wgi)
842 {
843 GtkWidget *window;
844 struct ghx_window *gwin;
845 struct window_geometry *wg;
846
847 wg = wg_get(wgi);
848 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
849 if (!window)
850 return 0;
851
852 gwin = xmalloc(sizeof(struct ghx_window));
853 gwin->next = 0;
854 gwin->prev = ghtlc->window_list;
855 if (ghtlc->window_list)
856 ghtlc->window_list->next = gwin;
857 ghtlc->window_list = gwin;
858 gwin->ghtlc = ghtlc;
859 gwin->wgi = wgi;
860 gwin->wg = wg;
861 gwin->widget = window;
862
863 gtk_window_set_policy(GTK_WINDOW(window), 1, 1, 0);
864 gtk_widget_set_usize(window, wg->width, wg->height);
865 gtk_widget_set_uposition(window, wg->xpos-wg->xoff, wg->ypos-wg->yoff);
866 gtk_signal_connect(GTK_OBJECT(window), "configure_event",
867 GTK_SIGNAL_FUNC(window_configure_event), gwin);
868 gtk_signal_connect(GTK_OBJECT(window), "destroy",
869 GTK_SIGNAL_FUNC(window_destroy), gwin);
870 keyaccel_attach(ghtlc, window);
871
872 return gwin;
873 }
874
875 static struct ghx_window *
ghx_window_with_wgi(struct ghtlc_conn * ghtlc,unsigned int wgi)876 ghx_window_with_wgi (struct ghtlc_conn *ghtlc, unsigned int wgi)
877 {
878 struct ghx_window *gwin;
879
880 for (gwin = ghtlc->window_list; gwin; gwin = gwin->prev) {
881 if (gwin->wgi == wgi)
882 return gwin;
883 }
884
885 return 0;
886 }
887
888 static void
setbtns(struct ghtlc_conn * ghtlc,int on)889 setbtns (struct ghtlc_conn *ghtlc, int on)
890 {
891 if (ghtlc->user_msgbtn) {
892 gtk_widget_set_sensitive(ghtlc->user_msgbtn, on);
893 gtk_widget_set_sensitive(ghtlc->user_infobtn, on);
894 gtk_widget_set_sensitive(ghtlc->user_kickbtn, on);
895 gtk_widget_set_sensitive(ghtlc->user_banbtn, on);
896 gtk_widget_set_sensitive(ghtlc->user_chatbtn, on);
897 }
898 if (ghtlc->news_postbtn) {
899 gtk_widget_set_sensitive(ghtlc->news_postbtn, on);
900 gtk_widget_set_sensitive(ghtlc->news_reloadbtn, on);
901 }
902 if (ghtlc->disconnectbtn) {
903 gtk_widget_set_sensitive(ghtlc->disconnectbtn, on);
904 gtk_widget_set_sensitive(ghtlc->filesbtn, on);
905 }
906 }
907
908 static void
changetitle(struct ghtlc_conn * ghtlc,GtkWidget * window,char * nam)909 changetitle (struct ghtlc_conn *ghtlc, GtkWidget *window, char *nam)
910 {
911 char title[32];
912 #ifdef CONFIG_IPV6
913 char addr[HOSTLEN+1];
914
915 inet_ntop(AFINET, (char *)&ghtlc->htlc->sockaddr.SIN_ADDR, addr, sizeof(addr));
916 #else
917 char addr[16];
918
919 inet_ntoa_r(ghtlc->htlc->sockaddr.SIN_ADDR, addr, sizeof(addr));
920 #endif
921 if (ghtlc->connected) {
922 sprintf(title, "%s (%s)", nam, addr);
923 gtk_window_set_title(GTK_WINDOW(window), title);
924 } else
925 gtk_window_set_title(GTK_WINDOW(window), nam);
926 }
927
928 static void
changetitlesconnected(struct ghtlc_conn * ghtlc)929 changetitlesconnected (struct ghtlc_conn *ghtlc)
930 {
931 struct ghx_window *gwin;
932 char title[32];
933 #ifdef CONFIG_IPV6
934 char addr[HOSTLEN+1];
935
936 inet_ntop(AFINET, (char *)&ghtlc->htlc->sockaddr.SIN_ADDR, addr, sizeof(addr));
937 #else
938 char addr[16];
939
940 inet_ntoa_r(ghtlc->htlc->sockaddr.SIN_ADDR, addr, sizeof(addr));
941 #endif
942 for (gwin = ghtlc->window_list; gwin; gwin = gwin->prev) {
943 switch (gwin->wgi) {
944 case WG_CHAT:
945 sprintf(title, "Chat (%s)", addr);
946 break;
947 case WG_TOOLBAR:
948 sprintf(title, "Toolbar (%s)", addr);
949 break;
950 case WG_NEWS:
951 sprintf(title, "News (%s)", addr);
952 break;
953 case WG_TASKS:
954 sprintf(title, "Tasks (%s)", addr);
955 break;
956 case WG_USERS:
957 sprintf(title, "Users (%s)", addr);
958 break;
959 default:
960 continue;
961 }
962 gtk_window_set_title(GTK_WINDOW(gwin->widget), title);
963 }
964 }
965
966 static void
changetitlesdisconnected(struct ghtlc_conn * ghtlc)967 changetitlesdisconnected (struct ghtlc_conn *ghtlc)
968 {
969 struct ghx_window *gwin;
970 char *title;
971
972 for (gwin = ghtlc->window_list; gwin; gwin = gwin->prev) {
973 switch (gwin->wgi) {
974 case WG_CHAT:
975 title = "Chat";
976 break;
977 case WG_TOOLBAR:
978 title = "Toolbar";
979 break;
980 case WG_NEWS:
981 title = "News";
982 break;
983 case WG_TASKS:
984 title = "Tasks";
985 break;
986 case WG_USERS:
987 title = "Users";
988 break;
989 default:
990 continue;
991 }
992 gtk_window_set_title(GTK_WINDOW(gwin->widget), title);
993 }
994 }
995
996 static struct ghtlc_conn *
ghtlc_conn_new(struct htlc_conn * htlc)997 ghtlc_conn_new (struct htlc_conn *htlc)
998 {
999 struct ghtlc_conn *ghtlc;
1000
1001 ghtlc = xmalloc(sizeof(struct ghtlc_conn));
1002 memset(ghtlc, 0, sizeof(struct ghtlc_conn));
1003 ghtlc->next = 0;
1004 ghtlc->prev = ghtlc_conn_list;
1005 if (ghtlc_conn_list)
1006 ghtlc_conn_list->next = ghtlc;
1007 ghtlc->htlc = htlc;
1008 if (htlc->fd)
1009 ghtlc->connected = 1;
1010 else
1011 ghtlc->connected = 0;
1012 ghtlc_conn_list = ghtlc;
1013
1014 return ghtlc;
1015 }
1016
1017 static void gfl_delete_all (struct ghtlc_conn *ghtlc);
1018
1019 static void
ghtlc_conn_delete(struct ghtlc_conn * ghtlc)1020 ghtlc_conn_delete (struct ghtlc_conn *ghtlc)
1021 {
1022 if (!ghtlc->window_list)
1023 return;
1024 if (ghtlc->connected)
1025 hx_htlc_close(ghtlc->htlc);
1026 if (ghtlc->gfile_list)
1027 gfl_delete_all(ghtlc);
1028 if (ghtlc->window_list)
1029 window_delete_all(ghtlc);
1030 if (ghtlc->next)
1031 ghtlc->next->prev = ghtlc->prev;
1032 if (ghtlc->prev)
1033 ghtlc->prev->next = ghtlc->next;
1034 if (ghtlc == ghtlc_conn_list)
1035 ghtlc_conn_list = ghtlc->prev;
1036 if (ghtlc->htlc != &hx_htlc)
1037 xfree(ghtlc->htlc);
1038 xfree(ghtlc);
1039 if (!ghtlc_conn_list)
1040 hx_exit(0);
1041 }
1042
1043 static struct ghtlc_conn *
ghtlc_valid(struct ghtlc_conn * ghtlc)1044 ghtlc_valid (struct ghtlc_conn *ghtlc)
1045 {
1046 struct ghtlc_conn *ghtlcp;
1047
1048 for (ghtlcp = ghtlc_conn_list; ghtlcp; ghtlcp = ghtlcp->prev) {
1049 if (ghtlcp == ghtlc)
1050 return ghtlc;
1051 }
1052
1053 return 0;
1054 }
1055
1056 static struct ghtlc_conn *
ghtlc_conn_with_htlc(struct htlc_conn * htlc)1057 ghtlc_conn_with_htlc (struct htlc_conn *htlc)
1058 {
1059 struct ghtlc_conn *ghtlc;
1060
1061 for (ghtlc = ghtlc_conn_list; ghtlc; ghtlc = ghtlc->prev) {
1062 if (ghtlc->htlc == htlc)
1063 return ghtlc;
1064 }
1065
1066 return 0;
1067 }
1068
1069 static void
ghtlc_conn_connect(struct ghtlc_conn * ghtlc)1070 ghtlc_conn_connect (struct ghtlc_conn *ghtlc)
1071 {
1072 ghtlc->connected = 1;
1073 setbtns(ghtlc, 1);
1074 changetitlesconnected(ghtlc);
1075 }
1076
1077 static void
ghtlc_conn_disconnect(struct ghtlc_conn * ghtlc)1078 ghtlc_conn_disconnect (struct ghtlc_conn *ghtlc)
1079 {
1080 ghtlc->connected = 0;
1081 setbtns(ghtlc, 0);
1082 changetitlesdisconnected(ghtlc);
1083 }
1084
1085 static struct gchat *
gchat_new(struct ghtlc_conn * ghtlc,struct hx_chat * chat)1086 gchat_new (struct ghtlc_conn *ghtlc, struct hx_chat *chat)
1087 {
1088 struct gchat *gchat;
1089
1090 gchat = xmalloc(sizeof(struct gchat));
1091 memset(gchat, 0, sizeof(struct gchat));
1092 gchat->next = 0;
1093 gchat->prev = ghtlc->gchat_list;
1094 if (ghtlc->gchat_list)
1095 ghtlc->gchat_list->next = gchat;
1096 ghtlc->gchat_list = gchat;
1097 gchat->ghtlc = ghtlc;
1098 gchat->chat = chat;
1099
1100 return gchat;
1101 }
1102
1103 static void
gchat_delete(struct ghtlc_conn * ghtlc,struct gchat * gchat)1104 gchat_delete (struct ghtlc_conn *ghtlc, struct gchat *gchat)
1105 {
1106 if (gchat->gwin) {
1107 GtkWidget *widget = gchat->gwin->widget;
1108 gchat->gwin = 0;
1109 gtk_widget_destroy(widget);
1110 }
1111 if (gchat->next)
1112 gchat->next->prev = gchat->prev;
1113 if (gchat->prev)
1114 gchat->prev->next = gchat->next;
1115 if (gchat == ghtlc->gchat_list)
1116 ghtlc->gchat_list = gchat->prev;
1117 xfree(gchat);
1118 }
1119
1120 static struct gchat *
gchat_with_widget(struct ghtlc_conn * ghtlc,GtkWidget * widget)1121 gchat_with_widget (struct ghtlc_conn *ghtlc, GtkWidget *widget)
1122 {
1123 struct gchat *gchat;
1124
1125 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
1126 if (!gchat->gwin)
1127 continue;
1128 if (gchat->gwin->widget == widget)
1129 return gchat;
1130 }
1131
1132 return 0;
1133 }
1134
1135 static struct gchat *
gchat_with_users_list(struct ghtlc_conn * ghtlc,GtkWidget * users_list)1136 gchat_with_users_list (struct ghtlc_conn *ghtlc, GtkWidget *users_list)
1137 {
1138 struct gchat *gchat;
1139
1140 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
1141 if (gchat->users_list == users_list)
1142 return gchat;
1143 }
1144
1145 return 0;
1146 }
1147
1148 static struct gchat *
gchat_with_chat(struct ghtlc_conn * ghtlc,struct hx_chat * chat)1149 gchat_with_chat (struct ghtlc_conn *ghtlc, struct hx_chat *chat)
1150 {
1151 struct gchat *gchat;
1152
1153 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
1154 if (gchat->chat == chat)
1155 return gchat;
1156 }
1157
1158 return 0;
1159 }
1160
1161 static struct gchat *
gchat_with_cid(struct ghtlc_conn * ghtlc,u_int32_t cid)1162 gchat_with_cid (struct ghtlc_conn *ghtlc, u_int32_t cid)
1163 {
1164 struct gchat *gchat;
1165
1166 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
1167 if ((cid == 0 && !gchat->chat) || gchat->chat->cid == cid)
1168 return gchat;
1169 }
1170
1171 return 0;
1172 }
1173
1174 static void
chat_input_activate(GtkWidget * widget,gpointer data)1175 chat_input_activate (GtkWidget *widget, gpointer data)
1176 {
1177 struct gchat *gchat = (struct gchat *)data;
1178 GtkText *text;
1179 guint point, len;
1180 gchar *chars;
1181
1182 text = GTK_TEXT(widget);
1183 point = gtk_text_get_point(text);
1184 len = gtk_text_get_length(text);
1185 chars = gtk_editable_get_chars(GTK_EDITABLE(text), 0, -1);
1186 add_history(gchat->chat_history, chars);
1187 using_history(gchat->chat_history);
1188 LF2CR(chars, len);
1189 hotline_client_input(gchat->ghtlc->htlc, gchat->chat, chars);
1190 g_free(chars);
1191
1192 gtk_text_set_point(text, 0);
1193 gtk_text_forward_delete(text, len);
1194 gtk_text_set_editable(text, 1);
1195 }
1196
1197 static void
chat_input_changed(GtkWidget * widget,gpointer data)1198 chat_input_changed (GtkWidget *widget, gpointer data)
1199 {
1200 guint point = GPOINTER_TO_INT(data);
1201 guint len = gtk_text_get_length(GTK_TEXT(widget));
1202
1203 if (!point)
1204 point = len;
1205 gtk_text_set_point(GTK_TEXT(widget), point);
1206 gtk_editable_set_position(GTK_EDITABLE(widget), point);
1207
1208 gtk_signal_disconnect_by_func(GTK_OBJECT(widget), chat_input_changed, data);
1209 }
1210
1211 /*
1212 * sniff the keys coming to the text widget
1213 * this is called before the text's key_press function is called
1214 * gtk will emit an activate signal on return only when control
1215 * is held or the text is not editable.
1216 */
1217 static gint
chat_input_key_press(GtkWidget * widget,GdkEventKey * event,gpointer data)1218 chat_input_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
1219 {
1220 struct gchat *gchat = (struct gchat *)data;
1221 GtkText *text;
1222 char *buf = 0, *p;
1223 char *line = 0;
1224 int linepoint = 0;
1225 guint point, len;
1226 guint k;
1227 HIST_ENTRY *hent;
1228
1229 k = event->keyval;
1230 text = GTK_TEXT(widget);
1231 point = gtk_editable_get_position(GTK_EDITABLE(text));
1232 len = gtk_text_get_length(text);
1233 if (k == GDK_Return) {
1234 if (len == point)
1235 gtk_text_set_editable(text, 0);
1236 return 1;
1237 } else if (k == GDK_Tab) {
1238 gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
1239 if ((event->state & GDK_CONTROL_MASK)) {
1240 gtk_container_focus(GTK_CONTAINER(gchat->gwin->widget), GTK_DIR_TAB_BACKWARD);
1241 return 1;
1242 }
1243 buf = xmalloc(len + 4096);
1244 p = gtk_editable_get_chars(GTK_EDITABLE(text), 0, -1);
1245 strcpy(buf, p);
1246 g_free(p);
1247 linepoint = hotline_client_tab(gchat->ghtlc->htlc, gchat->chat, buf, point);
1248 line = buf;
1249 } else if (len == point) {
1250 if (k == GDK_Up) {
1251 hent = previous_history(gchat->chat_history);
1252 if (hent)
1253 line = hent->line;
1254 } else if (k == GDK_Down) {
1255 hent = next_history(gchat->chat_history);
1256 if (hent)
1257 line = hent->line;
1258 }
1259 }
1260 if (line) {
1261 GdkColor *fgcolor = &widget->style->fg[GTK_STATE_NORMAL];
1262 GdkColor *bgcolor = &widget->style->bg[GTK_STATE_NORMAL];
1263
1264 gtk_text_freeze(text);
1265 gtk_text_set_point(text, 0);
1266 len = gtk_text_get_length(text);
1267 gtk_text_forward_delete(text, len);
1268 len = strlen(line);
1269 gtk_text_set_point(text, 0);
1270 gtk_text_insert(text, 0, fgcolor, bgcolor, line, len);
1271 gtk_text_thaw(text);
1272 gtk_signal_connect(GTK_OBJECT(text), "changed",
1273 GTK_SIGNAL_FUNC(chat_input_changed), GINT_TO_POINTER(linepoint));
1274 gtk_editable_changed(GTK_EDITABLE(text));
1275 if (line == buf)
1276 xfree(buf);
1277 return 1;
1278 }
1279
1280 return 0;
1281 }
1282
1283 static char *default_font = 0;
1284
1285 static void
create_chat_text(struct ghtlc_conn * ghtlc,GtkWidget ** intextp,GtkWidget ** outtextp,GtkWidget ** vscrollbarp,GtkStyle ** stylep,int first)1286 create_chat_text (struct ghtlc_conn *ghtlc, GtkWidget **intextp, GtkWidget **outtextp, GtkWidget **vscrollbarp,
1287 GtkStyle **stylep, int first)
1288 {
1289 GtkWidget *intext, *outtext;
1290 GtkWidget *vscrollbar;
1291 GtkStyle *style;
1292 GdkFont *font;
1293
1294 outtext = gtk_text_new(0, 0);
1295 gtk_text_set_editable(GTK_TEXT(outtext), 0);
1296 gtk_text_set_word_wrap(GTK_TEXT(outtext), 1);
1297
1298 intext = gtk_text_new(0, 0);
1299 gtk_text_set_editable(GTK_TEXT(intext), 1);
1300 gtk_text_set_word_wrap(GTK_TEXT(intext), 1);
1301
1302 if (first)
1303 init_colors(outtext);
1304
1305 style = gtk_style_new();
1306 style->base[GTK_STATE_NORMAL] = colors[8];
1307 style->bg[GTK_STATE_NORMAL] = colors[8];
1308 style->fg[GTK_STATE_NORMAL] = colors[15];
1309 style->text[GTK_STATE_NORMAL] = colors[15];
1310 style->light[GTK_STATE_NORMAL] = colors[15];
1311 style->dark[GTK_STATE_NORMAL] = colors[8];
1312 font = ghtlc->chat_font;
1313 if (font)
1314 gdk_font_ref(font);
1315 else {
1316 font = gdk_font_load(default_font);
1317 if (!font)
1318 font = gdk_font_load("fixed");
1319 }
1320 style->font = font;
1321
1322 gtk_widget_set_style(intext, style);
1323 gtk_widget_set_style(outtext, style);
1324
1325 vscrollbar = gtk_vscrollbar_new(GTK_TEXT(outtext)->vadj);
1326
1327 *intextp = intext;
1328 *outtextp = outtext;
1329 *vscrollbarp = vscrollbar;
1330 *stylep = style;
1331 }
1332
1333 static void
set_subject(GtkWidget * widget,gpointer data)1334 set_subject (GtkWidget *widget, gpointer data)
1335 {
1336 struct gchat *gchat = (struct gchat *)data;
1337 char *subject;
1338
1339 subject = gtk_entry_get_text(GTK_ENTRY(widget));
1340 if (gchat && gchat->chat)
1341 hx_set_subject(gchat->ghtlc->htlc, gchat->chat->cid, subject);
1342 }
1343
1344 static void
gchat_create_chat_text(struct gchat * gchat,int first)1345 gchat_create_chat_text (struct gchat *gchat, int first)
1346 {
1347 GtkWidget *intext, *outtext;
1348 GtkWidget *vscrollbar;
1349 GtkWidget *subject_entry;
1350 GtkStyle *style;
1351
1352 create_chat_text(gchat->ghtlc, &intext, &outtext, &vscrollbar, &style, first);
1353 gchat->chat_input_text = intext;
1354 gchat->chat_output_text = outtext;
1355 gchat->chat_vscrollbar = vscrollbar;
1356
1357 subject_entry = gtk_entry_new();
1358 gtk_widget_set_style(subject_entry, style);
1359 gchat->subject_entry = subject_entry;
1360 gtk_signal_connect(GTK_OBJECT(subject_entry), "activate",
1361 GTK_SIGNAL_FUNC(set_subject), gchat);
1362
1363 gtk_signal_connect(GTK_OBJECT(intext), "key_press_event",
1364 GTK_SIGNAL_FUNC(chat_input_key_press), gchat);
1365 gtk_signal_connect(GTK_OBJECT(intext), "activate",
1366 GTK_SIGNAL_FUNC(chat_input_activate), gchat);
1367
1368 if (!(gchat->chat && gchat->chat->cid)) {
1369 gtk_object_ref(GTK_OBJECT(intext));
1370 gtk_object_sink(GTK_OBJECT(intext));
1371 gtk_object_ref(GTK_OBJECT(outtext));
1372 gtk_object_sink(GTK_OBJECT(outtext));
1373 gtk_object_ref(GTK_OBJECT(vscrollbar));
1374 gtk_object_sink(GTK_OBJECT(vscrollbar));
1375 gtk_object_ref(GTK_OBJECT(subject_entry));
1376 gtk_object_sink(GTK_OBJECT(subject_entry));
1377 }
1378
1379 gchat->chat_history = history_new();
1380 stifle_history(gchat->chat_history, hist_size);
1381 }
1382
1383 static gint
chat_delete_event(gpointer data)1384 chat_delete_event (gpointer data)
1385 {
1386 struct gchat *gchat = (struct gchat *)data;
1387 struct ghx_window *gwin;
1388
1389 if (!gchat)
1390 return 1;
1391 gwin = gchat->gwin;
1392 if (!gwin)
1393 return 1;
1394 if (gchat->chat && gchat->chat->cid) {
1395 hx_chat_part(gchat->ghtlc->htlc, gchat->chat);
1396 return 1;
1397 } else {
1398 gtk_container_remove(GTK_CONTAINER(gchat->chat_in_hbox), gchat->chat_input_text);
1399 gtk_container_remove(GTK_CONTAINER(gchat->chat_out_hbox), gchat->chat_output_text);
1400 gtk_container_remove(GTK_CONTAINER(gchat->chat_out_hbox), gchat->chat_vscrollbar);
1401 gtk_container_remove(GTK_CONTAINER(gchat->subject_hbox), gchat->subject_entry);
1402 gchat->gwin = 0;
1403 }
1404
1405 return 0;
1406 }
1407
1408 static void create_users_window (struct ghtlc_conn *ghtlc, struct gchat *gchat);
1409
1410 static GtkWidget *
create_chat_widget(struct ghtlc_conn * ghtlc,struct gchat * gchat,struct window_geometry * wg)1411 create_chat_widget (struct ghtlc_conn *ghtlc, struct gchat *gchat,
1412 struct window_geometry *wg)
1413 {
1414 GtkWidget *vbox, *hbox;
1415 GtkWidget *intext, *outtext;
1416 GtkWidget *vscrollbar;
1417 GtkWidget *outputframe, *subjectframe, *inputframe;
1418 GtkWidget *subject_entry;
1419 GtkWidget *vpane, *hpane;
1420 GtkStyle *style;
1421
1422 vbox = gtk_vbox_new(0, 4);
1423 gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
1424
1425 outputframe = gtk_frame_new(0);
1426 gtk_frame_set_shadow_type(GTK_FRAME(outputframe), GTK_SHADOW_IN);
1427 inputframe = gtk_frame_new(0);
1428 gtk_frame_set_shadow_type(GTK_FRAME(inputframe), GTK_SHADOW_IN);
1429
1430 if (gchat) {
1431 outtext = gchat->chat_output_text;
1432 if (!outtext) {
1433 gchat_create_chat_text(gchat, 0);
1434 outtext = gchat->chat_output_text;
1435 }
1436 vscrollbar = gchat->chat_vscrollbar;
1437 intext = gchat->chat_input_text;
1438 style = gtk_widget_get_style(outtext);
1439 } else {
1440 create_chat_text(ghtlc, &intext, &outtext, &vscrollbar, &style, 0);
1441 }
1442
1443 if (gchat) {
1444 hbox = gtk_hbox_new(0, 0);
1445 gchat->subject_hbox = hbox;
1446 gtk_widget_set_usize(hbox, (wg->width<<6)/82, 20);
1447 subjectframe = gtk_frame_new(0);
1448 gtk_frame_set_shadow_type(GTK_FRAME(subjectframe), GTK_SHADOW_OUT);
1449 gtk_container_add(GTK_CONTAINER(subjectframe), hbox);
1450 subject_entry = gchat->subject_entry;
1451 gtk_box_pack_start(GTK_BOX(hbox), subject_entry, 1, 1, 0);
1452 if (gchat->chat)
1453 gtk_entry_set_text(GTK_ENTRY(subject_entry), gchat->chat->subject);
1454 gtk_box_pack_start(GTK_BOX(vbox), subjectframe, 0, 1, 0);
1455 }
1456
1457 vpane = gtk_vpaned_new();
1458 gtk_paned_add1(GTK_PANED(vpane), outputframe);
1459 gtk_paned_add2(GTK_PANED(vpane), inputframe);
1460
1461 gtk_box_pack_start(GTK_BOX(vbox), vpane, 1, 1, 0);
1462
1463 hbox = gtk_hbox_new(0, 0);
1464 gtk_widget_set_usize(hbox, (wg->width<<6)/82, (wg->height<<6)/100);
1465 gtk_container_add(GTK_CONTAINER(outputframe), hbox);
1466 gtk_widget_set_usize(outputframe, (wg->width<<6)/82, (wg->height<<6)/100);
1467
1468 if (gchat)
1469 gchat->chat_out_hbox = hbox;
1470 gtk_box_pack_start(GTK_BOX(hbox), outtext, 1, 1, 0);
1471 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, 0, 0, 0);
1472
1473 hbox = gtk_hbox_new(0, 0);
1474 gtk_widget_set_usize(hbox, (wg->width<<6)/100, 50);
1475 gtk_container_add(GTK_CONTAINER(inputframe), hbox);
1476 gtk_box_pack_start(GTK_BOX(hbox), intext, 1, 1, 0);
1477 gchat->chat_in_hbox = hbox;
1478
1479 gtk_widget_set_usize(vbox, wg->width-4, wg->height-4);
1480 if (gchat && gchat->chat && gchat->chat->cid) {
1481 create_users_window(ghtlc, gchat);
1482 gtk_widget_set_usize(gchat->users_vbox, 200, wg->height-4);
1483 hpane = gtk_hpaned_new();
1484 gtk_paned_add1(GTK_PANED(hpane), vbox);
1485 gtk_paned_add2(GTK_PANED(hpane), gchat->users_vbox);
1486 return hpane;
1487 } else {
1488 return vbox;
1489 }
1490 }
1491
1492 static void
create_chat_window(struct ghtlc_conn * ghtlc,struct hx_chat * chat)1493 create_chat_window (struct ghtlc_conn *ghtlc, struct hx_chat *chat)
1494 {
1495 struct gchat *gchat;
1496 struct ghx_window *gwin;
1497 struct window_geometry *wg;
1498 GtkWidget *container;
1499 GtkWidget *window;
1500 char title[32];
1501
1502 gchat = gchat_with_chat(ghtlc, chat);
1503 if (gchat && gchat->gwin)
1504 return;
1505 gwin = window_create(ghtlc, WG_CHAT);
1506 wg = gwin->wg;
1507 window = gwin->widget;
1508 gtk_container_set_border_width(GTK_CONTAINER(window), 0);
1509 if (chat && chat->cid)
1510 gtk_widget_set_usize(window, wg->width+200, wg->height);
1511 else
1512 gtk_widget_set_usize(window, wg->width, wg->height);
1513 if (!gchat)
1514 gchat = gchat_new(ghtlc, chat);
1515 gchat->gwin = gwin;
1516 gtk_signal_connect_object(GTK_OBJECT(window), "delete_event",
1517 GTK_SIGNAL_FUNC(chat_delete_event), (gpointer)gchat);
1518
1519 if (chat && chat->cid)
1520 sprintf(title, "Chat 0x%x", chat->cid);
1521 else
1522 strcpy(title, "Chat");
1523 changetitle(ghtlc, window, title);
1524
1525 container = create_chat_widget(ghtlc, gchat, wg);
1526 gtk_container_add(GTK_CONTAINER(window), container);
1527 gtk_widget_show_all(window);
1528 }
1529
1530 static void
chat_subject(struct htlc_conn * htlc,u_int32_t cid,const char * subject)1531 chat_subject (struct htlc_conn *htlc, u_int32_t cid, const char *subject)
1532 {
1533 struct ghtlc_conn *ghtlc;
1534 struct gchat *gchat;
1535
1536 ghtlc = ghtlc_conn_with_htlc(htlc);
1537 gchat = gchat_with_cid(ghtlc, cid);
1538 if (gchat)
1539 gtk_entry_set_text(GTK_ENTRY(gchat->subject_entry), subject);
1540 }
1541
1542 static void
chat_password(struct htlc_conn * htlc,u_int32_t cid,const u_int8_t * pass)1543 chat_password (struct htlc_conn *htlc, u_int32_t cid, const u_int8_t *pass)
1544 {
1545 struct hx_chat *chat;
1546
1547 chat = hx_chat_with_cid(htlc, cid);
1548 hx_printf_prefix(htlc, chat, INFOPREFIX, "chat 0x%x password: %s\n", cid, pass);
1549 }
1550
1551 static void
join_chat(GtkWidget * widget,gpointer data)1552 join_chat (GtkWidget *widget, gpointer data)
1553 {
1554 struct htlc_conn *htlc = (struct htlc_conn *)data;
1555 u_int32_t cid = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(widget), "cid"));
1556 GtkWidget *window = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "dialog");
1557
1558 gtk_widget_destroy(window);
1559 hx_chat_join(htlc, cid, 0, 0);
1560 }
1561
1562 static void
chat_invite(struct htlc_conn * htlc,u_int32_t cid,u_int32_t uid,const char * name)1563 chat_invite (struct htlc_conn *htlc, u_int32_t cid, u_int32_t uid, const char *name)
1564 {
1565 GtkWidget *dialog;
1566 GtkWidget *join;
1567 GtkWidget *cancel;
1568 GtkWidget *hbox;
1569 GtkWidget *label;
1570 char message[64];
1571
1572 dialog = gtk_dialog_new();
1573 gtk_window_set_title(GTK_WINDOW(dialog), "Chat Invitation");
1574 gtk_container_border_width(GTK_CONTAINER(dialog), 4);
1575 snprintf(message, 64, "Invitation to chat 0x%x from %s (%u)", cid, name, uid);
1576
1577 label = gtk_label_new(message);
1578 join = gtk_button_new_with_label("Join");
1579 gtk_object_set_data(GTK_OBJECT(join), "dialog", dialog);
1580 gtk_object_set_data(GTK_OBJECT(join), "cid", GINT_TO_POINTER(cid));
1581 gtk_signal_connect(GTK_OBJECT(join), "clicked",
1582 GTK_SIGNAL_FUNC(join_chat), htlc);
1583
1584 cancel = gtk_button_new_with_label("Decline");
1585 gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked",
1586 GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog));
1587
1588 GTK_WIDGET_SET_FLAGS(join, GTK_CAN_DEFAULT);
1589 GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
1590
1591 hbox = gtk_hbox_new(0,0);
1592
1593 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, 0, 0, 0);
1594 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), hbox, 0, 0, 0);
1595 gtk_box_pack_start(GTK_BOX(hbox), join, 0, 0, 0);
1596 gtk_box_pack_start(GTK_BOX(hbox), cancel, 0, 0, 0);
1597 gtk_widget_grab_default(join);
1598
1599 gtk_widget_show_all(dialog);
1600 }
1601
1602 static void
chat_delete(struct htlc_conn * htlc,struct hx_chat * chat)1603 chat_delete (struct htlc_conn *htlc, struct hx_chat *chat)
1604 {
1605 struct ghtlc_conn *ghtlc;
1606 struct gchat *gchat;
1607
1608 ghtlc = ghtlc_conn_with_htlc(htlc);
1609 gchat = gchat_with_chat(ghtlc, chat);
1610 if (!gchat)
1611 return;
1612 if (chat->cid == 0)
1613 gchat->chat = 0;
1614 else
1615 gchat_delete(ghtlc, gchat);
1616 }
1617
1618 static void
open_chat(gpointer data)1619 open_chat (gpointer data)
1620 {
1621 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
1622 struct hx_chat *chat;
1623
1624 for (chat = ghtlc->htlc->chat_list; chat; chat = chat->prev)
1625 if (!chat->prev)
1626 break;
1627
1628 create_chat_window(ghtlc, chat);
1629 }
1630
1631 static void
post_news(GtkWidget * widget,gpointer data)1632 post_news (GtkWidget *widget, gpointer data)
1633 {
1634 struct ghx_window *gwin = (struct ghx_window *)data;
1635 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)gtk_object_get_data(GTK_OBJECT(widget), "ghtlc");
1636 GtkWidget *posttext = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "posttext");
1637 char *postchars;
1638
1639 postchars = gtk_editable_get_chars(GTK_EDITABLE(posttext), 0, -1);
1640
1641 hx_post_news(ghtlc->htlc, postchars, strlen(postchars));
1642
1643 g_free(postchars);
1644
1645 gtk_widget_destroy(gwin->widget);
1646 }
1647
1648 static void
create_post_window(struct ghtlc_conn * ghtlc)1649 create_post_window (struct ghtlc_conn *ghtlc)
1650 {
1651 struct ghx_window *gwin;
1652 struct window_geometry *wg;
1653 GtkWidget *okbut;
1654 GtkWidget *cancbut;
1655 GtkWidget *vbox, *hbox;
1656 GtkWidget *posttext;
1657 GtkWidget *window;
1658
1659 gwin = window_create(ghtlc, WG_POST);
1660 wg = gwin->wg;
1661 window = gwin->widget;
1662
1663 changetitle(ghtlc, window, "Post News");
1664
1665 posttext = gtk_text_new(0, 0);
1666 gtk_text_set_editable(GTK_TEXT(posttext), 1);
1667 gtk_widget_set_usize(posttext, 0, wg->height - 40);
1668
1669 vbox = gtk_vbox_new(0, 0);
1670 gtk_container_add(GTK_CONTAINER(window), vbox);
1671 gtk_box_pack_start(GTK_BOX(vbox), posttext, 1, 1, 0);
1672
1673 hbox = gtk_hbox_new(0, 0);
1674 gtk_box_pack_start(GTK_BOX(vbox), hbox, 0, 0, 0);
1675
1676 okbut = gtk_button_new_with_label("OK");
1677 gtk_object_set_data(GTK_OBJECT(okbut), "ghtlc", ghtlc);
1678 gtk_object_set_data(GTK_OBJECT(okbut), "posttext", posttext);
1679 gtk_signal_connect(GTK_OBJECT(okbut), "clicked",
1680 GTK_SIGNAL_FUNC(post_news), gwin);
1681 cancbut = gtk_button_new_with_label("Cancel");
1682 gtk_signal_connect_object(GTK_OBJECT(cancbut), "clicked",
1683 GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer)window);
1684
1685 gtk_box_pack_start(GTK_BOX(hbox), okbut, 0, 0, 0);
1686 gtk_box_pack_start(GTK_BOX(hbox), cancbut, 0, 0, 0);
1687
1688 gtk_widget_show_all(window);
1689 }
1690
1691 static void
open_post(gpointer data)1692 open_post (gpointer data)
1693 {
1694 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
1695
1696 create_post_window(ghtlc);
1697 }
1698
1699 static void
reload_news(gpointer data)1700 reload_news (gpointer data)
1701 {
1702 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
1703
1704 hx_get_news(ghtlc->htlc);
1705 }
1706
1707 static void
news_destroy(gpointer data)1708 news_destroy (gpointer data)
1709 {
1710 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
1711
1712 ghtlc->news_postbtn = 0;
1713 ghtlc->news_reloadbtn = 0;
1714 }
1715
1716 static void
create_news_window(struct ghtlc_conn * ghtlc)1717 create_news_window (struct ghtlc_conn *ghtlc)
1718 {
1719 struct ghx_window *gwin;
1720 struct window_geometry *wg;
1721 GtkWidget *window;
1722 GtkWidget *vscrollbar;
1723 GtkWidget *hbox, *vbox;
1724 GtkStyle *style;
1725 GtkWidget *posthbox;
1726 GtkWidget *text;
1727 GtkWidget *postbtn, *reloadbtn;
1728 GtkTooltips *tooltips;
1729
1730 if ((gwin = ghx_window_with_wgi(ghtlc, WG_NEWS))) {
1731 gdk_window_show(gwin->widget->window);
1732 return;
1733 }
1734
1735 gwin = window_create(ghtlc, WG_NEWS);
1736 wg = gwin->wg;
1737 window = gwin->widget;
1738
1739 gtk_signal_connect_object(GTK_OBJECT(window), "destroy",
1740 GTK_SIGNAL_FUNC(news_destroy), (gpointer)ghtlc);
1741
1742 changetitle(ghtlc, window, "News");
1743
1744 tooltips = gtk_tooltips_new();
1745 postbtn = icon_button_new(ICON_NEWS, "Post News", window, tooltips);
1746 gtk_signal_connect_object(GTK_OBJECT(postbtn), "clicked",
1747 GTK_SIGNAL_FUNC(open_post), (gpointer)ghtlc);
1748 reloadbtn = icon_button_new(ICON_RELOAD, "Reload News", window, tooltips);
1749 gtk_signal_connect_object(GTK_OBJECT(reloadbtn), "clicked",
1750 GTK_SIGNAL_FUNC(reload_news), (gpointer)ghtlc);
1751
1752 ghtlc->news_postbtn = postbtn;
1753 ghtlc->news_reloadbtn = reloadbtn;
1754
1755 text = gtk_text_new(0, 0);
1756 gtk_text_set_editable(GTK_TEXT(text), 0);
1757 gtk_text_set_word_wrap(GTK_TEXT(text), 1);
1758 if (ghtlc->gchat_list) {
1759 style = gtk_widget_get_style(ghtlc->gchat_list->chat_output_text);
1760 gtk_widget_set_style(text, style);
1761 }
1762 ghtlc->news_text = text;
1763
1764 vscrollbar = gtk_vscrollbar_new(GTK_TEXT(text)->vadj);
1765
1766 vbox = gtk_vbox_new(0, 0);
1767 hbox = gtk_hbox_new(0, 0);
1768 posthbox = gtk_hbox_new(0, 0);
1769 gtk_box_pack_start(GTK_BOX(posthbox), reloadbtn, 0, 0, 0);
1770 gtk_box_pack_start(GTK_BOX(posthbox), postbtn, 0, 0, 0);
1771 gtk_box_pack_start(GTK_BOX(vbox), posthbox, 0, 0, 0);
1772 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(text), 1, 1, 0);
1773 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, 0, 0, 0);
1774 gtk_box_pack_start(GTK_BOX(vbox), hbox, 1, 1, 0);
1775 gtk_container_add(GTK_CONTAINER(window), vbox);
1776
1777 gtk_widget_show_all(window);
1778
1779 gtk_widget_set_sensitive(postbtn, ghtlc->connected);
1780 gtk_widget_set_sensitive(reloadbtn, ghtlc->connected);
1781 }
1782
1783 static void
open_news(gpointer data)1784 open_news (gpointer data)
1785 {
1786 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
1787 struct ghx_window *gwin;
1788
1789 if ((gwin = ghx_window_with_wgi(ghtlc, WG_NEWS))) {
1790 gdk_window_show(gwin->widget->window);
1791 return;
1792 }
1793
1794 create_news_window(ghtlc);
1795 if (!ghtlc->htlc->news_len)
1796 hx_get_news(ghtlc->htlc);
1797 else
1798 hx_output.news_file(ghtlc->htlc, ghtlc->htlc->news_buf, ghtlc->htlc->news_len);
1799 }
1800
1801 char *
colorstr(u_int16_t color)1802 colorstr (u_int16_t color)
1803 {
1804 char *col;
1805
1806 col = g_user_colors[color % 4];
1807
1808 return col;
1809 }
1810
1811 struct connect_context {
1812 struct ghtlc_conn *ghtlc;
1813 GtkWidget *connect_window;
1814 GtkWidget *address_entry;
1815 GtkWidget *login_entry;
1816 GtkWidget *password_entry;
1817 GtkWidget *cipher_entry;
1818 GtkWidget *secure_toggle;
1819 };
1820
1821 static void
connect_set_entries(struct connect_context * cc,const char * address,const char * login,const char * password)1822 connect_set_entries (struct connect_context *cc, const char *address, const char *login, const char *password)
1823 {
1824 if (address)
1825 gtk_entry_set_text(GTK_ENTRY(cc->address_entry), address);
1826 if (login)
1827 gtk_entry_set_text(GTK_ENTRY(cc->login_entry), login);
1828 if (password)
1829 gtk_entry_set_text(GTK_ENTRY(cc->password_entry), password);
1830 }
1831
1832 static void
server_connect(gpointer data)1833 server_connect (gpointer data)
1834 {
1835 struct connect_context *cc = (struct connect_context *)data;
1836 struct ghtlc_conn *ghtlc = cc->ghtlc;
1837 char *server;
1838 char *login;
1839 char *pass;
1840 char *serverstr, *p;
1841 char *cipher;
1842 int secure;
1843 u_int16_t clen;
1844 u_int16_t port = 5500;
1845 struct htlc_conn *htlc;
1846
1847 if (clen) {} /* removes compiler warning */
1848 server = gtk_entry_get_text(GTK_ENTRY(cc->address_entry));
1849 login = gtk_entry_get_text(GTK_ENTRY(cc->login_entry));
1850 pass = gtk_entry_get_text(GTK_ENTRY(cc->password_entry));
1851 cipher = gtk_entry_get_text(GTK_ENTRY(cc->cipher_entry));
1852 secure = GTK_TOGGLE_BUTTON(cc->secure_toggle)->active;
1853
1854 serverstr = g_strdup(server);
1855 #ifndef CONFIG_IPV6
1856 p = strchr(serverstr, ':');
1857 if (p) {
1858 *p++ = 0;
1859 if (*p)
1860 port = strtoul(p, 0, 0);
1861 }
1862 #endif
1863
1864 htlc = xmalloc(sizeof(struct htlc_conn));
1865 memset(htlc, 0, sizeof(struct htlc_conn));
1866 strcpy(htlc->name, ghtlc->htlc->name);
1867 htlc->icon = ghtlc->htlc->icon;
1868 #ifdef CONFIG_CIPHER
1869 clen = strlen(cipher);
1870 if (clen >= sizeof(htlc->cipheralg))
1871 clen = sizeof(htlc->cipheralg)-1;
1872 memcpy(htlc->cipheralg, cipher, clen);
1873 htlc->cipheralg[clen] = 0;
1874 #endif
1875 ghtlc = ghtlc_conn_new(htlc);
1876 create_toolbar_window(ghtlc);
1877 create_chat_window(ghtlc, 0);
1878 hx_connect(htlc, serverstr, port, htlc->name, htlc->icon, login, pass, secure, 1);
1879 g_free(serverstr);
1880
1881 gtk_widget_destroy(cc->connect_window);
1882 xfree(cc);
1883 }
1884
1885 static void
open_bookmark(GtkWidget * widget,gpointer data)1886 open_bookmark (GtkWidget *widget, gpointer data)
1887 {
1888 struct connect_context *cc = (struct connect_context *)gtk_object_get_data(GTK_OBJECT(widget), "cc");
1889 char *file = (char *)data;
1890 FILE *fp;
1891 char line1[64];
1892 char line2[64];
1893 char line3[64];
1894 char path[MAXPATHLEN], buf[MAXPATHLEN];
1895
1896 snprintf(buf, sizeof(buf), "~/.hx/bookmarks/%s", file);
1897 expand_tilde(path, buf);
1898 xfree(file);
1899
1900 fp = fopen(path, "r");
1901 if (fp) {
1902 line1[0] = line2[0] = line3[0];
1903 fgets(line1, 64, fp);
1904 fgets(line2, 64, fp);
1905 fgets(line3, 64, fp);
1906 line1[strlen(line1)-1] = 0;
1907 if (strlen(line2))
1908 line2[strlen(line2)-1] = 0;
1909 if (strlen(line3))
1910 line3[strlen(line3)-1] = 0;
1911 connect_set_entries(cc, line1, line2, line3);
1912 fclose(fp);
1913 } else {
1914 g_message("No such file. Bummer!");
1915 }
1916 }
1917
1918 static void
list_bookmarks(GtkWidget * menu,struct connect_context * cc)1919 list_bookmarks (GtkWidget *menu, struct connect_context *cc)
1920 {
1921 struct dirent *de;
1922 char *file;
1923 char path[MAXPATHLEN];
1924 GtkWidget *item;
1925 DIR *dir;
1926
1927 expand_tilde(path, "~/.hx/bookmarks");
1928 dir = opendir(path);
1929 if (!dir)
1930 return;
1931 while ((de = readdir(dir))) {
1932 if (*de->d_name != '.') {
1933 file = xstrdup(de->d_name);
1934 item = gtk_menu_item_new_with_label(file);
1935 gtk_menu_append(GTK_MENU(menu), item);
1936 gtk_object_set_data(GTK_OBJECT(item), "cc", cc);
1937 gtk_signal_connect(GTK_OBJECT(item), "activate",
1938 GTK_SIGNAL_FUNC(open_bookmark), file);
1939 }
1940 }
1941 closedir(dir);
1942 }
1943
1944 static void
cancel_save(GtkWidget * widget,gpointer data)1945 cancel_save (GtkWidget *widget, gpointer data)
1946 {
1947 struct connect_context *cc = (struct connect_context *)data;
1948 GtkWidget *dialog = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "dialog");
1949
1950 if (cc) {} /* removes compiler warning */
1951 gtk_widget_destroy(dialog);
1952 }
1953
1954 static void
bookmark_save(GtkWidget * widget,gpointer data)1955 bookmark_save (GtkWidget *widget, gpointer data)
1956 {
1957 struct connect_context *cc = (struct connect_context *)data;
1958 GtkWidget *name_entry = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "name");
1959 GtkWidget *dialog = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "dialog");
1960 char *server = gtk_entry_get_text(GTK_ENTRY(cc->address_entry));
1961 char *login = gtk_entry_get_text(GTK_ENTRY(cc->login_entry));
1962 char *pass = gtk_entry_get_text(GTK_ENTRY(cc->password_entry));
1963 char *home = getenv("HOME");
1964 char *name = gtk_entry_get_text(GTK_ENTRY(name_entry));
1965 char *path = g_strdup_printf("%s/.hx/bookmarks/%s", home, name);
1966 char *dir = g_strdup_printf("%s/.hx/bookmarks/", home);
1967 FILE *fp;
1968
1969 fp = fopen(path, "w");
1970 if (!fp) {
1971 mkdir(dir, 0700);
1972 fp = fopen(path, "w");
1973 }
1974
1975 if (!fp) {
1976 char *basedir = g_strdup_printf("%s/.hx", home);
1977 mkdir(basedir, 0700);
1978 mkdir(dir, 0700);
1979 fp = fopen(path, "w");
1980 g_free (basedir);
1981 }
1982
1983 if (!fp) {
1984 /* Give up */
1985 return;
1986 }
1987
1988 fprintf(fp, "%s\n", server);
1989 fprintf(fp, "%s\n", login);
1990 fprintf(fp, "%s\n", pass);
1991 fclose(fp);
1992 g_free(path);
1993 g_free(dir);
1994
1995 gtk_widget_destroy(dialog);
1996 }
1997
1998 static void
save_dialog(gpointer data)1999 save_dialog (gpointer data)
2000 {
2001 struct connect_context *cc = (struct connect_context *)data;
2002 GtkWidget *dialog;
2003 GtkWidget *ok;
2004 GtkWidget *cancel;
2005 GtkWidget *name_entry;
2006 GtkWidget *label;
2007 GtkWidget *hbox;
2008
2009 dialog = gtk_dialog_new();
2010 ok = gtk_button_new_with_label("OK");
2011 GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
2012 cancel = gtk_button_new_with_label("Cancel");
2013 name_entry = gtk_entry_new();
2014 hbox = gtk_hbox_new(0,0);
2015 label = gtk_label_new("Name:");
2016
2017 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, 0, 0, 0);
2018 gtk_box_pack_start(GTK_BOX(hbox), label, 0, 0, 0);
2019 gtk_box_pack_start(GTK_BOX(hbox), name_entry, 0, 0, 0);
2020 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), ok, 0,0, 0);
2021 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), cancel, 0,0, 0);
2022 gtk_object_set_data(GTK_OBJECT(cancel), "dialog", dialog);
2023 gtk_signal_connect(GTK_OBJECT(cancel), "clicked",
2024 GTK_SIGNAL_FUNC(cancel_save), cc);
2025 gtk_object_set_data(GTK_OBJECT(ok), "name", name_entry);
2026 gtk_object_set_data(GTK_OBJECT(ok), "dialog", dialog);
2027 gtk_signal_connect(GTK_OBJECT(ok), "clicked",
2028 GTK_SIGNAL_FUNC(bookmark_save), cc);
2029
2030 gtk_widget_grab_default(ok);
2031
2032 gtk_widget_show_all(dialog);
2033 }
2034
2035 static void
close_connect_window(gpointer data)2036 close_connect_window (gpointer data)
2037 {
2038 struct connect_context *cc = (struct connect_context *)data;
2039
2040 gtk_widget_destroy(cc->connect_window);
2041 xfree(cc);
2042 }
2043
2044 static struct connect_context *
create_connect_window(struct ghtlc_conn * ghtlc)2045 create_connect_window (struct ghtlc_conn *ghtlc)
2046 {
2047 struct ghx_window *gwin;
2048 GtkWidget *connect_window;
2049 GtkWidget *vbox1;
2050 GtkWidget *hbox;
2051 GtkWidget *cipher_label;
2052 GtkWidget *cipher_entry;
2053 GtkWidget *secure_toggle;
2054 GtkWidget *help_label;
2055 GtkWidget *frame1;
2056 GtkWidget *table1;
2057 GtkWidget *server_label;
2058 GtkWidget *login_label;
2059 GtkWidget *pass_label;
2060 GtkWidget *address_entry;
2061 GtkWidget *login_entry;
2062 GtkWidget *password_entry;
2063 GtkWidget *button_connect;
2064 GtkWidget *button_cancel;
2065 GtkWidget *bookmarkmenu;
2066 GtkWidget *bookmarkmenu_menu;
2067 GtkWidget *hbuttonbox1;
2068 GtkWidget *save_button;
2069 struct connect_context *cc;
2070
2071 gwin = window_create(ghtlc, WG_CONNECT);
2072 connect_window = gwin->widget;
2073
2074 gtk_window_set_title(GTK_WINDOW(connect_window), "Connect");
2075 gtk_window_set_position(GTK_WINDOW(connect_window), GTK_WIN_POS_CENTER);
2076
2077 vbox1 = gtk_vbox_new(0, 10);
2078 gtk_container_add(GTK_CONTAINER(connect_window), vbox1);
2079 gtk_container_set_border_width(GTK_CONTAINER(vbox1), 10);
2080
2081 help_label = gtk_label_new("Enter the server address, and if you have an account, your login and password. If not, leave the login and password blank.");
2082 gtk_box_pack_start(GTK_BOX(vbox1), help_label, 0, 1, 0);
2083 gtk_label_set_justify(GTK_LABEL(help_label), GTK_JUSTIFY_LEFT);
2084 gtk_label_set_line_wrap(GTK_LABEL(help_label), 1);
2085 gtk_misc_set_alignment(GTK_MISC(help_label), 0, 0.5);
2086
2087 frame1 = gtk_frame_new(0);
2088 gtk_box_pack_start(GTK_BOX(vbox1), frame1, 1, 1, 0);
2089 gtk_frame_set_shadow_type(GTK_FRAME(frame1), GTK_SHADOW_IN);
2090
2091 table1 = gtk_table_new(4, 3, 0);
2092 gtk_container_add(GTK_CONTAINER(frame1), table1);
2093 gtk_container_set_border_width(GTK_CONTAINER(table1), 10);
2094 gtk_table_set_row_spacings(GTK_TABLE(table1), 5);
2095 gtk_table_set_col_spacings(GTK_TABLE(table1), 5);
2096
2097 server_label = gtk_label_new("Server:");
2098 gtk_table_attach(GTK_TABLE(table1), server_label, 0, 1, 0, 1,
2099 (GtkAttachOptions)(GTK_FILL),
2100 (GtkAttachOptions)0, 0, 0);
2101 gtk_label_set_justify(GTK_LABEL(server_label), GTK_JUSTIFY_LEFT);
2102 gtk_misc_set_alignment(GTK_MISC(server_label), 0, 0.5);
2103
2104 login_label = gtk_label_new("Login:");
2105 gtk_table_attach(GTK_TABLE(table1), login_label, 0, 1, 1, 2,
2106 (GtkAttachOptions)(GTK_FILL),
2107 (GtkAttachOptions)0, 0, 0);
2108 gtk_label_set_justify(GTK_LABEL(login_label), GTK_JUSTIFY_LEFT);
2109 gtk_misc_set_alignment(GTK_MISC(login_label), 0, 0.5);
2110
2111 pass_label = gtk_label_new("Password:");
2112 gtk_table_attach(GTK_TABLE(table1), pass_label, 0, 1, 2, 3,
2113 (GtkAttachOptions)(GTK_FILL),
2114 (GtkAttachOptions)0, 0, 0);
2115 gtk_label_set_justify(GTK_LABEL(pass_label), GTK_JUSTIFY_LEFT);
2116 gtk_misc_set_alignment(GTK_MISC(pass_label), 0, 0.5);
2117
2118 address_entry = gtk_entry_new();
2119 gtk_table_attach(GTK_TABLE(table1), address_entry, 1, 2, 0, 1,
2120 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
2121 (GtkAttachOptions)0, 0, 0);
2122
2123 login_entry = gtk_entry_new();
2124 gtk_table_attach(GTK_TABLE(table1), login_entry, 1, 2, 1, 2,
2125 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
2126 (GtkAttachOptions)0, 0, 0);
2127 password_entry = gtk_entry_new();
2128 gtk_entry_set_visibility(GTK_ENTRY(password_entry), 0);
2129 gtk_table_attach(GTK_TABLE(table1), password_entry, 1, 2, 2, 3,
2130 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
2131 (GtkAttachOptions)0, 0, 0);
2132
2133 secure_toggle = gtk_check_button_new_with_label("Secure");
2134 #ifdef CONFIG_HOPE
2135 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(secure_toggle), 1);
2136 #else
2137 gtk_widget_set_sensitive(secure_toggle, 0);
2138 #endif
2139 cipher_label = gtk_label_new("Cipher:");
2140 cipher_entry = gtk_entry_new();
2141 #ifdef CONFIG_CIPHER
2142 gtk_entry_set_text(GTK_ENTRY(cipher_entry), ghtlc->htlc->cipheralg);
2143 #else
2144 gtk_widget_set_sensitive(cipher_entry, 0);
2145 #endif
2146 gtk_table_attach(GTK_TABLE(table1), secure_toggle, 0, 1, 3, 4,
2147 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
2148 (GtkAttachOptions)0, 0, 0);
2149 hbox = gtk_hbox_new(0, 0);
2150 gtk_box_pack_start(GTK_BOX(hbox), cipher_label, 0, 0, 2);
2151 gtk_box_pack_start(GTK_BOX(hbox), cipher_entry, 0, 0, 2);
2152 gtk_table_attach(GTK_TABLE(table1), hbox, 1, 2, 3, 4,
2153 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
2154 (GtkAttachOptions)0, 0, 0);
2155
2156 cc = xmalloc(sizeof(struct connect_context));
2157 cc->ghtlc = ghtlc;
2158 cc->connect_window = connect_window;
2159 cc->address_entry = address_entry;
2160 cc->login_entry = login_entry;
2161 cc->password_entry = password_entry;
2162 cc->cipher_entry = cipher_entry;
2163 cc->secure_toggle = secure_toggle;
2164
2165 bookmarkmenu = gtk_option_menu_new();
2166 gtk_table_attach(GTK_TABLE(table1), bookmarkmenu, 2, 3, 0, 1,
2167 (GtkAttachOptions)0,
2168 (GtkAttachOptions)0, 0, 0);
2169 bookmarkmenu_menu = gtk_menu_new();
2170 list_bookmarks(bookmarkmenu_menu, cc);
2171 gtk_option_menu_set_menu(GTK_OPTION_MENU(bookmarkmenu), bookmarkmenu_menu);
2172
2173 hbuttonbox1 = gtk_hbutton_box_new();
2174 gtk_box_pack_start(GTK_BOX(vbox1), hbuttonbox1, 1, 1, 0);
2175
2176 save_button = gtk_button_new_with_label("Save...");
2177 gtk_container_add(GTK_CONTAINER(hbuttonbox1), save_button);
2178 GTK_WIDGET_SET_FLAGS(save_button, GTK_CAN_DEFAULT);
2179 gtk_signal_connect_object(GTK_OBJECT(save_button), "clicked",
2180 GTK_SIGNAL_FUNC(save_dialog), (gpointer)cc);
2181
2182 button_cancel = gtk_button_new_with_label("Cancel");
2183 gtk_signal_connect_object(GTK_OBJECT(button_cancel), "clicked",
2184 GTK_SIGNAL_FUNC(close_connect_window), (gpointer)cc);
2185 gtk_container_add(GTK_CONTAINER(hbuttonbox1), button_cancel);
2186 GTK_WIDGET_SET_FLAGS(button_cancel, GTK_CAN_DEFAULT);
2187
2188 button_connect = gtk_button_new_with_label("Connect");
2189 gtk_signal_connect_object(GTK_OBJECT(button_connect), "clicked",
2190 GTK_SIGNAL_FUNC(server_connect), (gpointer)cc);
2191 gtk_container_add(GTK_CONTAINER (hbuttonbox1), button_connect);
2192 GTK_WIDGET_SET_FLAGS(button_connect, GTK_CAN_DEFAULT);
2193
2194 gtk_signal_connect_object(GTK_OBJECT(address_entry), "activate",
2195 GTK_SIGNAL_FUNC(server_connect), (gpointer)cc);
2196 gtk_signal_connect_object(GTK_OBJECT(login_entry), "activate",
2197 GTK_SIGNAL_FUNC(server_connect), (gpointer)cc);
2198 gtk_signal_connect_object(GTK_OBJECT(password_entry), "activate",
2199 GTK_SIGNAL_FUNC(server_connect), (gpointer)cc);
2200
2201 gtk_widget_show_all(connect_window);
2202
2203 return cc;
2204 }
2205
2206 static void
open_connect(gpointer data)2207 open_connect (gpointer data)
2208 {
2209 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
2210
2211 create_connect_window(ghtlc);
2212 }
2213
2214 struct tracker_server {
2215 void *next;
2216
2217 char *addrstr;
2218 char *name;
2219 char *desc;
2220 u_int16_t port;
2221 u_int16_t nusers;
2222 };
2223
2224 struct generic_list {
2225 void *next;
2226 };
2227
2228 static void
list_free(void * listp)2229 list_free (void *listp)
2230 {
2231 struct generic_list *lp, *next;
2232
2233 for (lp = (struct generic_list *)listp; lp; lp = next) {
2234 next = lp->next;
2235 xfree(lp);
2236 }
2237 }
2238
2239 static void
tracker_destroy(gpointer data)2240 tracker_destroy (gpointer data)
2241 {
2242 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
2243
2244 ghtlc->tracker_list = 0;
2245 if (ghtlc->tracker_server_list) {
2246 list_free(ghtlc->tracker_server_list);
2247 ghtlc->tracker_server_list = 0;
2248 }
2249 }
2250
2251 static void
tracker_getlist(GtkWidget * widget,gpointer data)2252 tracker_getlist (GtkWidget *widget, gpointer data)
2253 {
2254 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
2255 GtkWidget *hostentry = gtk_object_get_data(GTK_OBJECT(widget), "hostentry");
2256 char *host;
2257
2258 gtk_hlist_clear(GTK_HLIST(ghtlc->tracker_list));
2259 if (ghtlc->tracker_server_list) {
2260 list_free(ghtlc->tracker_server_list);
2261 ghtlc->tracker_server_list = 0;
2262 }
2263 host = gtk_entry_get_text(GTK_ENTRY(hostentry));
2264 hx_tracker_list(ghtlc->htlc, 0, host, HTRK_TCPPORT);
2265 }
2266
2267 static void
tracker_search(GtkWidget * widget,gpointer data)2268 tracker_search (GtkWidget *widget, gpointer data)
2269 {
2270 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
2271 GtkWidget *tracker_list = ghtlc->tracker_list;
2272 char *str;
2273 struct tracker_server *server;
2274 gint row;
2275 gchar *text[5];
2276 char nusersstr[8], portstr[8];
2277
2278 str = gtk_entry_get_text(GTK_ENTRY(widget));
2279 if (!str || !*str)
2280 return;
2281 str = g_strdup_printf("*%s*", str);
2282 gtk_hlist_freeze(GTK_HLIST(tracker_list));
2283 gtk_hlist_clear(GTK_HLIST(tracker_list));
2284 for (server = ghtlc->tracker_server_list; server; server = server->next) {
2285 if (!fnmatch(str, server->desc, FNM_NOESCAPE)
2286 || !fnmatch(str, server->name, FNM_NOESCAPE)) {
2287 snprintf(nusersstr, sizeof(nusersstr), "%u", server->nusers);
2288 snprintf(portstr, sizeof(portstr), "%u", server->port);
2289 text[0] = server->name;
2290 text[1] = nusersstr;
2291 text[2] = server->addrstr;
2292 text[3] = portstr;
2293 text[4] = server->desc;
2294 row = gtk_hlist_append(GTK_HLIST(tracker_list), text);
2295 gtk_hlist_set_row_data(GTK_HLIST(tracker_list), row, server);
2296 }
2297 }
2298 gtk_hlist_thaw(GTK_HLIST(tracker_list));
2299 g_free(str);
2300 }
2301
2302 static void
tracker_server_create(struct htlc_conn * htlc,const char * addrstr,u_int16_t port,u_int16_t nusers,const char * nam,const char * desc)2303 tracker_server_create (struct htlc_conn *htlc,
2304 const char *addrstr, u_int16_t port, u_int16_t nusers,
2305 const char *nam, const char *desc)
2306 {
2307 struct ghtlc_conn *ghtlc;
2308 GtkWidget *tracker_list;
2309 gint row;
2310 struct tracker_server *server;
2311 char nusersstr[8], portstr[8];
2312 gchar *text[5];
2313
2314 ghtlc = ghtlc_conn_with_htlc(htlc);
2315 tracker_list = ghtlc->tracker_list;
2316 if (!tracker_list)
2317 return;
2318
2319 server = xmalloc(sizeof(struct tracker_server));
2320 server->next = 0;
2321 if (!ghtlc->tracker_server_list) {
2322 ghtlc->tracker_server_list = server;
2323 ghtlc->tracker_server_tail = server;
2324 } else {
2325 ghtlc->tracker_server_tail->next = server;
2326 ghtlc->tracker_server_tail = server;
2327 }
2328
2329 server->addrstr = xstrdup(addrstr);
2330 server->port = port;
2331 server->nusers = nusers;
2332 server->name = xstrdup(nam);
2333 server->desc = xstrdup(desc);
2334
2335 snprintf(nusersstr, sizeof(nusersstr), "%u", server->nusers);
2336 snprintf(portstr, sizeof(portstr), "%u", server->port);
2337 text[0] = server->name;
2338 text[1] = nusersstr;
2339 text[2] = server->addrstr;
2340 text[3] = portstr;
2341 text[4] = server->desc;
2342 row = gtk_hlist_append(GTK_HLIST(tracker_list), text);
2343 gtk_hlist_set_row_data(GTK_HLIST(tracker_list), row, server);
2344 }
2345
2346 static int tracker_storow;
2347 static int tracker_stocol;
2348
2349 static gint
tracker_click(GtkWidget * widget,GdkEventButton * event,gpointer data)2350 tracker_click (GtkWidget *widget, GdkEventButton *event, gpointer data)
2351 {
2352 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
2353 GtkWidget *tracker_list = ghtlc->tracker_list;
2354 struct htlc_conn *htlc;
2355
2356 gtk_hlist_get_selection_info(GTK_HLIST(widget), event->x, event->y,
2357 &tracker_storow, &tracker_stocol);
2358 if (event->type == GDK_2BUTTON_PRESS) {
2359 struct tracker_server *server;
2360
2361 htlc = xmalloc(sizeof(struct htlc_conn));
2362 memset(htlc, 0, sizeof(struct htlc_conn));
2363 strcpy(htlc->name, ghtlc->htlc->name);
2364 htlc->icon = ghtlc->htlc->icon;
2365 ghtlc = ghtlc_conn_new(htlc);
2366 create_toolbar_window(ghtlc);
2367 create_chat_window(ghtlc, 0);
2368
2369 server = gtk_hlist_get_row_data(GTK_HLIST(tracker_list), tracker_storow);
2370 hx_connect(htlc, server->addrstr, server->port, htlc->name, htlc->icon, 0, 0, 0, 1);
2371 return 1;
2372 }
2373
2374 return 0;
2375 }
2376
2377 static void
tracker_connect(gpointer data)2378 tracker_connect (gpointer data)
2379 {
2380 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
2381 struct tracker_server *server;
2382
2383 server = gtk_hlist_get_row_data(GTK_HLIST(ghtlc->tracker_list), tracker_storow);
2384 if (server) {
2385 char addrstr[32];
2386 struct connect_context *cc;
2387
2388 cc = create_connect_window(ghtlc);
2389 snprintf(addrstr, sizeof(addrstr), "%s:%u", server->addrstr, server->port);
2390 connect_set_entries(cc, addrstr, 0, 0);
2391 }
2392 }
2393
2394 static void
create_tracker_window(struct ghtlc_conn * ghtlc)2395 create_tracker_window (struct ghtlc_conn *ghtlc)
2396 {
2397 struct ghx_window *gwin;
2398 struct window_geometry *wg;
2399 GtkWidget *tracker_window;
2400 GtkWidget *tracker_list;
2401 GtkWidget *vbox;
2402 GtkWidget *hbox;
2403 GtkWidget *hostentry;
2404 GtkWidget *searchhbox;
2405 GtkWidget *searchentry;
2406 GtkWidget *tracker_window_scroll;
2407 GtkWidget *refreshbtn;
2408 GtkWidget *connbtn;
2409 GtkWidget *optionsbtn;
2410 static gchar *titles[] = {"Name", "Users", "Address", "Port", "Description"};
2411
2412 if (ghtlc->tracker_list)
2413 return;
2414
2415 gwin = window_create(ghtlc, WG_TRACKER);
2416 wg = gwin->wg;
2417 tracker_window = gwin->widget;
2418
2419 gtk_window_set_title(GTK_WINDOW(tracker_window), "Tracker");
2420 gtk_signal_connect_object(GTK_OBJECT(tracker_window), "destroy",
2421 GTK_SIGNAL_FUNC(tracker_destroy), (gpointer)ghtlc);
2422
2423 tracker_list = gtk_hlist_new_with_titles(5, titles);
2424 ghtlc->tracker_list = tracker_list;
2425 gtk_widget_set_usize(tracker_list, wg->width, wg->height-60);
2426 gtk_hlist_set_column_width(GTK_HLIST(tracker_list), 0, 160);
2427 gtk_hlist_set_column_width(GTK_HLIST(tracker_list), 1, 40);
2428 gtk_hlist_set_column_justification(GTK_HLIST(tracker_list), 1, GTK_JUSTIFY_CENTER);
2429 gtk_hlist_set_column_width(GTK_HLIST(tracker_list), 2, 96);
2430 gtk_hlist_set_column_width(GTK_HLIST(tracker_list), 3, 40);
2431 gtk_hlist_set_column_width(GTK_HLIST(tracker_list), 4, 256);
2432 gtk_signal_connect(GTK_OBJECT(tracker_list), "button_press_event",
2433 GTK_SIGNAL_FUNC(tracker_click), ghtlc);
2434
2435 hostentry = gtk_entry_new();
2436 gtk_object_set_data(GTK_OBJECT(hostentry), "hostentry", hostentry);
2437 gtk_signal_connect(GTK_OBJECT(hostentry), "activate",
2438 GTK_SIGNAL_FUNC(tracker_getlist), ghtlc);
2439 searchentry = gtk_entry_new();
2440 gtk_signal_connect(GTK_OBJECT(searchentry), "activate",
2441 GTK_SIGNAL_FUNC(tracker_search), ghtlc);
2442
2443 refreshbtn = gtk_button_new_with_label("Refresh");
2444 gtk_object_set_data(GTK_OBJECT(refreshbtn), "hostentry", hostentry);
2445 gtk_signal_connect(GTK_OBJECT(refreshbtn), "clicked",
2446 GTK_SIGNAL_FUNC(tracker_getlist), ghtlc);
2447 connbtn = gtk_button_new_with_label("Connect");
2448 gtk_signal_connect_object(GTK_OBJECT(connbtn), "clicked",
2449 GTK_SIGNAL_FUNC(tracker_connect), (gpointer)ghtlc);
2450 optionsbtn = gtk_button_new_with_label("Options");
2451
2452 tracker_window_scroll = gtk_scrolled_window_new(0, 0);
2453 SCROLLBAR_SPACING(tracker_window_scroll) = 0;
2454 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tracker_window_scroll),
2455 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2456 gtk_widget_set_usize(tracker_window_scroll, wg->width, wg->height-50);
2457 gtk_container_add(GTK_CONTAINER(tracker_window_scroll), tracker_list);
2458
2459 vbox = gtk_vbox_new(0, 0);
2460 gtk_widget_set_usize(vbox, wg->height, wg->width);
2461 hbox = gtk_hbox_new(0, 0);
2462 searchhbox = gtk_hbox_new(0, 0);
2463 gtk_box_pack_start(GTK_BOX(hbox), refreshbtn, 0, 0, 0);
2464 gtk_box_pack_start(GTK_BOX(hbox), connbtn, 0, 0, 0);
2465 gtk_box_pack_start(GTK_BOX(hbox), optionsbtn, 0, 0, 0);
2466 gtk_box_pack_start(GTK_BOX(hbox), hostentry, 1, 1, 0);
2467 gtk_box_pack_start(GTK_BOX(vbox), hbox, 0, 0, 0);
2468 gtk_box_pack_start(GTK_BOX(searchhbox), searchentry, 1, 1, 0);
2469 gtk_box_pack_start(GTK_BOX(vbox), searchhbox, 0, 0, 0);
2470 gtk_box_pack_start(GTK_BOX(vbox), tracker_window_scroll, 1, 1, 0);
2471 gtk_container_add(GTK_CONTAINER(tracker_window), vbox);
2472
2473 gtk_widget_show_all(tracker_window);
2474 }
2475
2476 static void
open_tracker(gpointer data)2477 open_tracker (gpointer data)
2478 {
2479 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
2480
2481 create_tracker_window(ghtlc);
2482 }
2483
2484 struct options_context {
2485 struct ghtlc_conn *ghtlc;
2486 struct ghx_window *gwin;
2487 GtkWidget *showjoin_btn;
2488 GtkWidget *showpart_btn;
2489 GtkWidget *showchange_btn;
2490 GtkWidget *font_entry;
2491 GtkWidget *nick_entry;
2492 GtkWidget *icon_entry;
2493 GtkWidget *icon_list;
2494 u_int32_t nfound;
2495 u_int32_t icon_high;
2496 };
2497
2498 static void chat_output (struct gchat *gchat, const char *buf, size_t len);
2499
2500 static void
change_font(struct ghtlc_conn * ghtlc,GdkFont * font)2501 change_font (struct ghtlc_conn *ghtlc, GdkFont *font)
2502 {
2503 struct gchat *gchat;
2504 GtkStyle *style;
2505 char *in_chars, *out_chars, *subj_text;
2506 guint in_len, out_len;
2507
2508 ghtlc->chat_font = font;
2509 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
2510 style = gtk_widget_get_style(gchat->chat_output_text);
2511 gdk_font_ref(font);
2512 style->font = font;
2513 in_len = gtk_text_get_length(GTK_TEXT(gchat->chat_input_text));
2514 out_len = gtk_text_get_length(GTK_TEXT(gchat->chat_output_text));
2515 in_chars = gtk_editable_get_chars(GTK_EDITABLE(gchat->chat_input_text), 0, in_len);
2516 out_chars = gtk_editable_get_chars(GTK_EDITABLE(gchat->chat_output_text), 0, out_len);
2517 subj_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(gchat->subject_entry)));
2518 gtk_widget_destroy(gchat->chat_input_text);
2519 gtk_widget_destroy(gchat->chat_output_text);
2520 gtk_widget_destroy(gchat->chat_vscrollbar);
2521 gtk_widget_destroy(gchat->subject_entry);
2522 gchat_create_chat_text(gchat, 0);
2523 if (gchat->chat_in_hbox) {
2524 gtk_box_pack_start(GTK_BOX(gchat->chat_in_hbox),
2525 gchat->chat_input_text, 1, 1, 0);
2526 gtk_box_pack_start(GTK_BOX(gchat->chat_out_hbox),
2527 gchat->chat_output_text, 1, 1, 0);
2528 gtk_box_pack_start(GTK_BOX(gchat->chat_out_hbox),
2529 gchat->chat_vscrollbar, 0, 0, 0);
2530 gtk_box_pack_start(GTK_BOX(gchat->subject_hbox),
2531 gchat->subject_entry, 1, 1, 0);
2532 }
2533 gtk_text_insert(GTK_TEXT(gchat->chat_input_text), 0, 0, 0, in_chars, in_len);
2534 gtk_text_insert(GTK_TEXT(gchat->chat_output_text), 0, 0, 0, out_chars, out_len);
2535 gtk_entry_set_text(GTK_ENTRY(gchat->subject_entry), subj_text);
2536 gtk_widget_show(gchat->chat_input_text);
2537 gtk_widget_show(gchat->chat_output_text);
2538 gtk_widget_show(gchat->chat_vscrollbar);
2539 gtk_widget_show(gchat->subject_entry);
2540 g_free(in_chars);
2541 g_free(out_chars);
2542 g_free(subj_text);
2543 }
2544 }
2545
2546 static void
options_change(gpointer data)2547 options_change (gpointer data)
2548 {
2549 struct options_context *oc = (struct options_context *)data;
2550 struct ghtlc_conn *ghtlc = oc->ghtlc;
2551 char *fontstr;
2552 char *nicknam;
2553 char *iconstr;
2554 u_int16_t icon;
2555
2556 fontstr = gtk_entry_get_text(GTK_ENTRY(oc->font_entry));
2557 if (fontstr && *fontstr)
2558 variable_set(ghtlc->htlc, 0, "chat_font[0][0]", fontstr);
2559 variable_set(ghtlc->htlc, 0, "tty_show_user_joins",
2560 GTK_TOGGLE_BUTTON(oc->showjoin_btn)->active ? "1" : "0");
2561 variable_set(ghtlc->htlc, 0, "tty_show_user_parts",
2562 GTK_TOGGLE_BUTTON(oc->showpart_btn)->active ? "1" : "0");
2563 variable_set(ghtlc->htlc, 0, "tty_show_user_changes",
2564 GTK_TOGGLE_BUTTON(oc->showchange_btn)->active ? "1" : "0");
2565 iconstr = gtk_entry_get_text(GTK_ENTRY(oc->icon_entry));
2566 nicknam = gtk_entry_get_text(GTK_ENTRY(oc->nick_entry));
2567 icon = strtoul(iconstr, 0, 0);
2568
2569 hx_change_name_icon(ghtlc->htlc, nicknam, icon);
2570
2571 gtk_widget_destroy(oc->gwin->widget);
2572 }
2573
2574 static void
adjust_icon_list(struct options_context * oc,unsigned int height)2575 adjust_icon_list (struct options_context *oc, unsigned int height)
2576 {
2577 GtkWidget *icon_list = oc->icon_list;
2578 struct pixmap_cache *pixc;
2579 GdkPixmap *pixmap;
2580 GdkBitmap *mask;
2581 char *nam = "";
2582 gint row;
2583 gchar *text[2] = {0, 0};
2584 u_int32_t icon;
2585 unsigned int nfound = 0;
2586 char buf[16];
2587
2588 text[1] = buf;
2589 height = height/18;
2590 for (icon = oc->icon_high; icon < 0x10000; icon++) {
2591 if (nfound >= height)
2592 break;
2593 pixc = load_icon(icon_list, icon, &user_icon_files, 1, 0);
2594 if (!pixc)
2595 continue;
2596 nfound++;
2597 pixmap = pixc->pixmap;
2598 mask = pixc->mask;
2599 sprintf(buf, "%u", icon);
2600 row = gtk_hlist_append(GTK_HLIST(icon_list), text);
2601 gtk_hlist_set_row_data(GTK_HLIST(icon_list), row, (gpointer)icon);
2602 gtk_hlist_set_pixtext(GTK_HLIST(icon_list), row, 0, nam, 34, pixmap, mask);
2603 }
2604 oc->icon_high = icon;
2605 oc->nfound += nfound;
2606 }
2607
2608 static void
icon_list_scrolled(GtkAdjustment * adj,gpointer data)2609 icon_list_scrolled (GtkAdjustment *adj, gpointer data)
2610 {
2611 struct options_context *oc = (struct options_context *)data;
2612
2613 adjust_icon_list(oc, (unsigned int)adj->page_size);
2614 }
2615
2616 static void
icon_row_selected(GtkWidget * widget,gint row,gint column,GdkEventButton * event,gpointer data)2617 icon_row_selected (GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data)
2618 {
2619 struct options_context *oc = (struct options_context *)data;
2620 u_int16_t icon;
2621 char buf[16];
2622
2623 if (column || event) {} /* removes compiler warning */
2624 icon = GPOINTER_TO_INT(gtk_hlist_get_row_data(GTK_HLIST(widget), row));
2625 sprintf(buf, "%u", icon);
2626 gtk_entry_set_text(GTK_ENTRY(oc->icon_entry), buf);
2627 }
2628
2629 static void
fontsel_ok(GtkWidget * widget,gpointer data)2630 fontsel_ok (GtkWidget *widget, gpointer data)
2631 {
2632 struct options_context *oc = (struct options_context *)data;
2633 GtkWidget *fontseldlg = gtk_object_get_data(GTK_OBJECT(widget), "fontseldlg");
2634 char *fontstr;
2635
2636 fontstr = gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(fontseldlg));
2637 if (fontstr)
2638 gtk_entry_set_text(GTK_ENTRY(oc->font_entry), fontstr);
2639 gtk_widget_destroy(fontseldlg);
2640 }
2641
2642 static void
open_fontsel(gpointer data)2643 open_fontsel (gpointer data)
2644 {
2645 struct options_context *oc = (struct options_context *)data;
2646 GtkWidget *fontseldlg;
2647
2648 fontseldlg = gtk_font_selection_dialog_new("Font");
2649 gtk_object_set_data(GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontseldlg)->ok_button), "fontseldlg", fontseldlg);
2650 gtk_signal_connect(GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontseldlg)->ok_button), "clicked",
2651 GTK_SIGNAL_FUNC(fontsel_ok), oc);
2652 gtk_signal_connect_object(GTK_OBJECT(GTK_FONT_SELECTION_DIALOG(fontseldlg)->cancel_button),
2653 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(fontseldlg));
2654 gtk_widget_show_all(fontseldlg);
2655 }
2656
2657 static void
create_options_window(struct ghtlc_conn * ghtlc)2658 create_options_window (struct ghtlc_conn *ghtlc)
2659 {
2660 struct ghx_window *gwin;
2661 GtkWidget *window;
2662 GtkWidget *mainbox;
2663 GtkWidget *maintab;
2664 GtkWidget *generalbox;
2665 GtkWidget *optiontable1;
2666 GtkWidget *tracker_entry;
2667 GtkWidget *name;
2668 GtkWidget *tracker;
2669 GtkWidget *optiontable2;
2670 GtkWidget *showjoin;
2671 GtkWidget *showpart;
2672 GtkWidget *showchange;
2673 GtkWidget *optiontable3;
2674 GtkWidget *chatcolorframe;
2675 GtkWidget *chatcolorpreview;
2676 GtkWidget *chatbgcolorframe;
2677 GtkWidget *chatbgcolorpreview;
2678 GtkWidget *chatcolorlabel;
2679 GtkWidget *chatbgcolorlabel;
2680 GtkWidget *fontbtn;
2681 GtkWidget *font_entry;
2682 GtkWidget *general;
2683 GtkWidget *table4;
2684 GtkWidget *iconlabel;
2685 GtkWidget *icon;
2686 GtkWidget *empty_notebook_page;
2687 GtkWidget *sound;
2688 GtkWidget *advanced;
2689 GtkWidget *savebutton;
2690 GtkWidget *cancelbutton;
2691 GtkWidget *hbuttonbox1;
2692 GtkWidget *nick_entry;
2693 GtkWidget *icon_entry;
2694 GtkWidget *icon_list;
2695 GtkWidget *scroll;
2696 GtkWidget *vadj;
2697 struct options_context *oc;
2698 char iconstr[16];
2699
2700 if ((gwin = ghx_window_with_wgi(ghtlc, WG_OPTIONS))) {
2701 gdk_window_show(gwin->widget->window);
2702 return;
2703 }
2704
2705 gwin = window_create(ghtlc, WG_OPTIONS);
2706 window = gwin->widget;
2707
2708 changetitle(ghtlc, window, "Options");
2709 gtk_window_set_policy(GTK_WINDOW(window), 1, 1, 0);
2710 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
2711
2712 mainbox = gtk_vbox_new(0, 10);
2713 gtk_container_add(GTK_CONTAINER(window), mainbox);
2714 gtk_container_set_border_width(GTK_CONTAINER(mainbox), 10);
2715
2716 maintab = gtk_notebook_new();
2717 gtk_box_pack_start(GTK_BOX(mainbox), maintab, 1, 1, 0);
2718
2719 generalbox = gtk_vbox_new(0, 10);
2720 gtk_container_add(GTK_CONTAINER(maintab), generalbox);
2721 gtk_container_set_border_width(GTK_CONTAINER(generalbox), 10);
2722
2723 optiontable1 = gtk_table_new(2, 2, 0);
2724 gtk_box_pack_start(GTK_BOX(generalbox), optiontable1, 0, 1, 0);
2725 gtk_table_set_row_spacings(GTK_TABLE(optiontable1), 10);
2726 gtk_table_set_col_spacings(GTK_TABLE(optiontable1), 5);
2727
2728 nick_entry = gtk_entry_new();
2729 gtk_table_attach(GTK_TABLE(optiontable1), nick_entry, 1, 2, 0, 1,
2730 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
2731 (GtkAttachOptions)0, 0, 0);
2732 gtk_entry_set_text(GTK_ENTRY(nick_entry), ghtlc->htlc->name);
2733
2734 tracker_entry = gtk_entry_new();
2735 gtk_table_attach(GTK_TABLE(optiontable1), tracker_entry, 1, 2, 1, 2,
2736 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
2737 (GtkAttachOptions)0, 0, 0);
2738
2739 name = gtk_label_new("Your Name:");
2740 gtk_table_attach(GTK_TABLE(optiontable1), name, 0, 1, 0, 1,
2741 (GtkAttachOptions)(GTK_FILL),
2742 (GtkAttachOptions)(GTK_FILL), 0, 0);
2743 gtk_label_set_justify(GTK_LABEL(name), GTK_JUSTIFY_LEFT);
2744 gtk_misc_set_alignment(GTK_MISC(name), 0, 0.5);
2745
2746 tracker = gtk_label_new("Tracker:");
2747 gtk_table_attach(GTK_TABLE(optiontable1), tracker, 0, 1, 1, 2,
2748 (GtkAttachOptions)(GTK_FILL),
2749 (GtkAttachOptions)(GTK_FILL), 0, 0);
2750 gtk_label_set_justify(GTK_LABEL(tracker), GTK_JUSTIFY_LEFT);
2751 gtk_misc_set_alignment(GTK_MISC(tracker), 0, 0.5);
2752
2753 optiontable2 = gtk_table_new(3, 1, 0);
2754 gtk_box_pack_start(GTK_BOX(generalbox), optiontable2, 0, 0, 0);
2755
2756 showjoin = gtk_check_button_new_with_label("Show Joins in Chat");
2757 gtk_table_attach(GTK_TABLE(optiontable2), showjoin, 0, 1, 0, 1,
2758 (GtkAttachOptions)(GTK_FILL),
2759 (GtkAttachOptions)(GTK_FILL), 0, 0);
2760 showpart = gtk_check_button_new_with_label("Show Parts in Chat");
2761 gtk_table_attach(GTK_TABLE(optiontable2), showpart, 0, 1, 1, 2,
2762 (GtkAttachOptions)(GTK_FILL),
2763 (GtkAttachOptions)(GTK_FILL), 0, 0);
2764 showchange = gtk_check_button_new_with_label("Show Changes in Chat");
2765 gtk_table_attach(GTK_TABLE(optiontable2), showchange, 0, 1, 2, 3,
2766 (GtkAttachOptions)(GTK_FILL),
2767 (GtkAttachOptions)(GTK_FILL), 0, 0);
2768 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(showjoin), tty_show_user_joins);
2769 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(showpart), tty_show_user_parts);
2770 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(showchange), tty_show_user_changes);
2771
2772 optiontable3 = gtk_table_new(3, 2, 0);
2773 gtk_box_pack_start(GTK_BOX(generalbox), optiontable3, 1, 1, 0);
2774 gtk_table_set_row_spacings(GTK_TABLE(optiontable3), 10);
2775 gtk_table_set_col_spacings(GTK_TABLE(optiontable3), 5);
2776
2777 chatcolorframe = gtk_frame_new(0);
2778 gtk_table_attach(GTK_TABLE(optiontable3), chatcolorframe, 1, 2, 1, 2,
2779 (GtkAttachOptions)0,
2780 (GtkAttachOptions)0, 0, 0);
2781 gtk_widget_set_usize(chatcolorframe, 50, 20);
2782 gtk_frame_set_shadow_type(GTK_FRAME(chatcolorframe), GTK_SHADOW_IN);
2783
2784 chatcolorpreview = gtk_preview_new(GTK_PREVIEW_COLOR);
2785 gtk_container_add(GTK_CONTAINER(chatcolorframe), chatcolorpreview);
2786
2787 chatbgcolorframe = gtk_frame_new(0);
2788 gtk_table_attach(GTK_TABLE(optiontable3), chatbgcolorframe, 1, 2, 2, 3,
2789 (GtkAttachOptions)0,
2790 (GtkAttachOptions)0, 0, 0);
2791 gtk_widget_set_usize(chatbgcolorframe, 50, 20);
2792 gtk_frame_set_shadow_type(GTK_FRAME(chatbgcolorframe), GTK_SHADOW_IN);
2793
2794 chatbgcolorpreview = gtk_preview_new(GTK_PREVIEW_COLOR);
2795 gtk_container_add(GTK_CONTAINER(chatbgcolorframe), chatbgcolorpreview);
2796
2797 font_entry = gtk_entry_new();
2798 gtk_table_attach(GTK_TABLE(optiontable3), font_entry, 1, 2, 0, 1,
2799 (GtkAttachOptions)(GTK_FILL|GTK_EXPAND),
2800 (GtkAttachOptions)0, 0, 0);
2801 if (default_font)
2802 gtk_entry_set_text(GTK_ENTRY(font_entry), default_font);
2803
2804 fontbtn = gtk_button_new_with_label("Font");
2805 gtk_table_attach(GTK_TABLE(optiontable3), fontbtn, 0, 1, 0, 1,
2806 (GtkAttachOptions)(GTK_FILL),
2807 (GtkAttachOptions)(GTK_FILL), 0, 0);
2808
2809 chatcolorlabel = gtk_label_new("Chat Text Color:");
2810 gtk_table_attach(GTK_TABLE(optiontable3), chatcolorlabel, 0, 1, 1, 2,
2811 (GtkAttachOptions)(GTK_FILL),
2812 (GtkAttachOptions)(GTK_FILL), 0, 0);
2813 gtk_label_set_justify(GTK_LABEL(chatcolorlabel), GTK_JUSTIFY_LEFT);
2814 gtk_misc_set_alignment(GTK_MISC(chatcolorlabel), 0, 0.5);
2815
2816 chatbgcolorlabel = gtk_label_new("Chat Background Color:");
2817 gtk_table_attach(GTK_TABLE(optiontable3), chatbgcolorlabel, 0, 1, 2, 3,
2818 (GtkAttachOptions)(GTK_FILL),
2819 (GtkAttachOptions)(GTK_FILL), 0, 0);
2820 gtk_label_set_justify(GTK_LABEL(chatbgcolorlabel), GTK_JUSTIFY_LEFT);
2821 gtk_misc_set_alignment(GTK_MISC(chatbgcolorlabel), 0, 0.5);
2822
2823 general = gtk_label_new("General");
2824 gtk_notebook_set_tab_label(GTK_NOTEBOOK(maintab), gtk_notebook_get_nth_page(GTK_NOTEBOOK (maintab), 0), general);
2825
2826 table4 = gtk_table_new(2, 2, 0);
2827 gtk_container_add(GTK_CONTAINER(maintab), table4);
2828 gtk_container_set_border_width(GTK_CONTAINER(table4), 4);
2829 gtk_table_set_col_spacings(GTK_TABLE(table4), 4);
2830
2831 iconlabel = gtk_label_new("Icon:");
2832 gtk_table_attach(GTK_TABLE(table4), iconlabel, 0, 1, 0, 1,
2833 (GtkAttachOptions)0,
2834 (GtkAttachOptions)0, 0, 0);
2835
2836 icon_entry = gtk_entry_new();
2837 gtk_table_attach(GTK_TABLE(table4), icon_entry, 1, 2, 0, 1,
2838 (GtkAttachOptions)0,
2839 (GtkAttachOptions)0, 0, 0);
2840 sprintf(iconstr, "%u", ghtlc->htlc->icon);
2841 gtk_entry_set_text(GTK_ENTRY(icon_entry), iconstr);
2842
2843 icon_list = gtk_hlist_new(2);
2844 GTK_HLIST(icon_list)->want_stipple = 1;
2845 gtk_hlist_set_selection_mode(GTK_HLIST(icon_list), GTK_SELECTION_EXTENDED);
2846 gtk_hlist_set_column_width(GTK_HLIST(icon_list), 0, 240);
2847 gtk_hlist_set_column_width(GTK_HLIST(icon_list), 1, 32);
2848 gtk_hlist_set_row_height(GTK_HLIST(icon_list), 18);
2849 scroll = gtk_scrolled_window_new(0, 0);
2850 SCROLLBAR_SPACING(scroll) = 0;
2851 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
2852 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
2853 gtk_widget_set_usize(scroll, 232, 256);
2854 gtk_container_add(GTK_CONTAINER(scroll), icon_list);
2855 gtk_table_attach(GTK_TABLE(table4), scroll, 0, 2, 1, 2,
2856 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
2857 (GtkAttachOptions)0, 0, 0);
2858
2859 oc = xmalloc(sizeof(struct options_context));
2860 oc->ghtlc = ghtlc;
2861 oc->gwin = gwin;
2862 oc->showjoin_btn = showjoin;
2863 oc->showpart_btn = showpart;
2864 oc->showchange_btn = showchange;
2865 oc->font_entry = font_entry;
2866 oc->nick_entry = nick_entry;
2867 oc->icon_entry = icon_entry;
2868 oc->icon_list = icon_list;
2869 oc->nfound = 0;
2870 oc->icon_high = 0;
2871
2872 gtk_signal_connect_object(GTK_OBJECT(fontbtn), "clicked",
2873 GTK_SIGNAL_FUNC(open_fontsel), (gpointer)oc);
2874
2875 vadj = (GtkWidget *)gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scroll));
2876 gtk_signal_connect(GTK_OBJECT(vadj), "value_changed",
2877 GTK_SIGNAL_FUNC(icon_list_scrolled), oc);
2878 gtk_signal_connect(GTK_OBJECT(icon_list), "select_row",
2879 GTK_SIGNAL_FUNC(icon_row_selected), oc);
2880
2881 icon = gtk_label_new("Icon");
2882 gtk_notebook_set_tab_label(GTK_NOTEBOOK(maintab), gtk_notebook_get_nth_page(GTK_NOTEBOOK(maintab), 1), icon);
2883
2884 empty_notebook_page = gtk_vbox_new(0, 0);
2885 gtk_container_add(GTK_CONTAINER(maintab), empty_notebook_page);
2886
2887 sound = gtk_label_new("Sound");
2888 gtk_notebook_set_tab_label(GTK_NOTEBOOK(maintab), gtk_notebook_get_nth_page(GTK_NOTEBOOK(maintab), 2), sound);
2889
2890 empty_notebook_page = gtk_vbox_new(0, 0);
2891 gtk_container_add(GTK_CONTAINER(maintab), empty_notebook_page);
2892
2893 advanced = gtk_label_new("Advanced");
2894 gtk_notebook_set_tab_label(GTK_NOTEBOOK(maintab), gtk_notebook_get_nth_page(GTK_NOTEBOOK(maintab), 3), advanced);
2895
2896 hbuttonbox1 = gtk_hbutton_box_new();
2897 gtk_box_pack_start(GTK_BOX(mainbox), hbuttonbox1, 0, 0, 0);
2898 gtk_button_box_set_child_size(GTK_BUTTON_BOX(hbuttonbox1), 0, 22);
2899
2900 savebutton = gtk_button_new_with_label("Save");
2901 cancelbutton = gtk_button_new_with_label("Cancel");
2902 gtk_signal_connect_object(GTK_OBJECT(savebutton), "clicked",
2903 GTK_SIGNAL_FUNC(options_change), (gpointer)oc);
2904 gtk_signal_connect_object(GTK_OBJECT(cancelbutton), "clicked",
2905 GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer)window);
2906
2907 gtk_container_add(GTK_CONTAINER(hbuttonbox1), cancelbutton);
2908 gtk_container_add(GTK_CONTAINER(hbuttonbox1), savebutton);
2909
2910 gtk_widget_show_all(window);
2911 }
2912
2913 static void
open_options(gpointer data)2914 open_options (gpointer data)
2915 {
2916 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
2917
2918 create_options_window(ghtlc);
2919 }
2920
2921 struct msgchat {
2922 struct msgchat *next, *prev;
2923 struct ghtlc_conn *ghtlc;
2924 GtkWidget *from_text;
2925 GtkWidget *to_text;
2926 GtkWidget *from_hbox;
2927 GtkWidget *to_hbox;
2928 GtkWidget *win;
2929 GtkWidget *vpane;
2930 GtkWidget *chat_chk;
2931 u_int32_t uid;
2932 unsigned int chat;
2933 u_int8_t name[32];
2934 };
2935
2936 static struct msgchat *
msgchat_new(struct ghtlc_conn * ghtlc,u_int32_t uid)2937 msgchat_new (struct ghtlc_conn *ghtlc, u_int32_t uid)
2938 {
2939 struct msgchat *msgchat;
2940
2941 msgchat = xmalloc(sizeof(struct msgchat));
2942 memset(msgchat, 0, sizeof(struct msgchat));
2943 msgchat->next = 0;
2944 msgchat->prev = ghtlc->msgchat_list;
2945 if (ghtlc->msgchat_list)
2946 ghtlc->msgchat_list->next = msgchat;
2947 ghtlc->msgchat_list = msgchat;
2948 msgchat->ghtlc = ghtlc;
2949 msgchat->uid = uid;
2950
2951 return msgchat;
2952 }
2953
2954 static void
msgchat_delete(struct ghtlc_conn * ghtlc,struct msgchat * msgchat)2955 msgchat_delete (struct ghtlc_conn *ghtlc, struct msgchat *msgchat)
2956 {
2957 if (msgchat->next)
2958 msgchat->next->prev = msgchat->prev;
2959 if (msgchat->prev)
2960 msgchat->prev->next = msgchat->next;
2961 if (msgchat == ghtlc->msgchat_list)
2962 ghtlc->msgchat_list = msgchat->prev;
2963 xfree(msgchat);
2964 }
2965
2966 static struct msgchat *
msgchat_with_uid(struct ghtlc_conn * ghtlc,u_int32_t uid)2967 msgchat_with_uid (struct ghtlc_conn *ghtlc, u_int32_t uid)
2968 {
2969 struct msgchat *msgchat;
2970
2971 for (msgchat = ghtlc->msgchat_list; msgchat; msgchat = msgchat->prev) {
2972 if (msgchat->uid == uid)
2973 return msgchat;
2974 }
2975
2976 return 0;
2977 }
2978
2979 static void
destroy_msgchat(gpointer data)2980 destroy_msgchat (gpointer data)
2981 {
2982 struct msgchat *mc = (struct msgchat *)data;
2983
2984 msgchat_delete(mc->ghtlc, mc);
2985 }
2986
2987 static void
users_send_message(gpointer data)2988 users_send_message (gpointer data)
2989 {
2990 struct msgchat *mc = (struct msgchat *)data;
2991 struct ghtlc_conn *ghtlc = mc->ghtlc;
2992 GtkWidget *msgtext = mc->to_text;
2993 GtkWidget *win = mc->win;
2994 u_int32_t uid = mc->uid;
2995 char *msgbuf;
2996
2997 msgbuf = gtk_editable_get_chars(GTK_EDITABLE(msgtext), 0, -1);
2998 hx_send_msg(ghtlc->htlc, uid, msgbuf, strlen(msgbuf), 0);
2999 g_free(msgbuf);
3000
3001 gtk_widget_destroy(win);
3002 }
3003
3004 static GtkWidget *
user_pixmap(GtkWidget * widget,GdkFont * font,GdkColor * color,u_int16_t icon,const char * nam)3005 user_pixmap (GtkWidget *widget, GdkFont *font, GdkColor *color,
3006 u_int16_t icon, const char *nam)
3007 {
3008 struct pixmap_cache *pixc;
3009 GdkPixmap *pixmap;
3010 GtkWidget *gtkpixmap;
3011
3012 pixc = load_icon(widget, icon, &user_icon_files, 0, 0);
3013 if (!pixc)
3014 return 0;
3015 pixmap = gdk_pixmap_new(widget->window, 232, 18, pixc->depth);
3016 gdk_window_copy_area(pixmap, users_gc, 0, 0, pixc->pixmap,
3017 0, 0, pixc->width, pixc->height);
3018 gdk_gc_set_foreground(users_gc, color);
3019 gdk_draw_string(pixmap, font, users_gc, 34, 13, nam);
3020
3021 gtkpixmap = gtk_pixmap_new(pixmap, 0);
3022
3023 return gtkpixmap;
3024 }
3025
3026 static void
msgchat_input_activate(GtkWidget * widget,gpointer data)3027 msgchat_input_activate (GtkWidget *widget, gpointer data)
3028 {
3029 struct msgchat *mc = (struct msgchat *)data;
3030 GtkText *text;
3031 guint point, len;
3032 gchar *chars;
3033
3034 text = GTK_TEXT(widget);
3035 point = gtk_text_get_point(text);
3036 len = gtk_text_get_length(text);
3037 chars = gtk_editable_get_chars(GTK_EDITABLE(text), 0, -1);
3038 hx_send_msg(mc->ghtlc->htlc, mc->uid, chars, len, 0);
3039
3040 gtk_text_set_point(text, 0);
3041 gtk_text_forward_delete(text, len);
3042 gtk_text_set_editable(text, 1);
3043
3044 text = GTK_TEXT(mc->from_text);
3045 point = gtk_text_get_length(text);
3046 gtk_text_set_point(text, point);
3047 if (point)
3048 gtk_text_insert(text, 0, MSG_FROM_COLOR, 0, "\n", 1);
3049 gtk_text_insert(text, 0, MSG_TO_COLOR, 0, chars, len);
3050 g_free(chars);
3051 }
3052
3053 static gint
msgchat_input_key_press(GtkWidget * widget,GdkEventKey * event,gpointer data)3054 msgchat_input_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
3055 {
3056 struct msgchat *mc = (struct msgchat *)data;
3057 GtkText *text;
3058 guint point, len;
3059 guint k;
3060
3061 if (!mc->chat)
3062 return 0;
3063
3064 k = event->keyval;
3065 if (k == GDK_Return) {
3066 text = GTK_TEXT(widget);
3067 point = gtk_editable_get_position(GTK_EDITABLE(text));
3068 len = gtk_text_get_length(text);
3069 if (len == point)
3070 gtk_text_set_editable(text, 0);
3071 return 1;
3072 }
3073
3074 return 0;
3075 }
3076
3077 static void
chat_chk_activate(GtkWidget * widget,gpointer data)3078 chat_chk_activate (GtkWidget *widget, gpointer data)
3079 {
3080 struct msgchat *mc = (struct msgchat *)data;
3081 GtkWidget *msgtext = mc->to_text;
3082
3083 if (mc->chat == GTK_TOGGLE_BUTTON(widget)->active)
3084 return;
3085 mc->chat = GTK_TOGGLE_BUTTON(widget)->active;
3086 if (!msgtext)
3087 return;
3088 if (mc->chat) {
3089 gtk_signal_connect(GTK_OBJECT(msgtext), "key_press_event",
3090 GTK_SIGNAL_FUNC(msgchat_input_key_press), mc);
3091 gtk_signal_connect(GTK_OBJECT(msgtext), "activate",
3092 GTK_SIGNAL_FUNC(msgchat_input_activate), mc);
3093 gtk_widget_set_usize(mc->from_hbox, 300, 180);
3094 gtk_widget_set_usize(mc->to_hbox, 300, 40);
3095 } else {
3096 gtk_signal_disconnect_by_func(GTK_OBJECT(msgtext),
3097 GTK_SIGNAL_FUNC(msgchat_input_activate), mc);
3098 gtk_widget_set_usize(mc->from_hbox, 300, 100);
3099 gtk_widget_set_usize(mc->to_hbox, 300, 120);
3100 }
3101 }
3102
3103 static void
msgwin_chat(gpointer data)3104 msgwin_chat (gpointer data)
3105 {
3106 struct msgchat *mc = (struct msgchat *)data;
3107 struct ghtlc_conn *ghtlc = mc->ghtlc;
3108 u_int32_t uid = mc->uid;
3109
3110 hx_chat_user(ghtlc->htlc, uid);
3111 }
3112
3113 static void
msgwin_get_info(gpointer data)3114 msgwin_get_info (gpointer data)
3115 {
3116 struct msgchat *mc = (struct msgchat *)data;
3117 struct ghtlc_conn *ghtlc = mc->ghtlc;
3118 u_int32_t uid = mc->uid;
3119
3120 hx_get_user_info(ghtlc->htlc, uid, 0);
3121 }
3122
3123 static void
users_open_message(struct ghtlc_conn * ghtlc,u_int32_t uid,const char * nam)3124 users_open_message (struct ghtlc_conn *ghtlc, u_int32_t uid, const char *nam)
3125 {
3126 GtkWidget *msgwin;
3127 GtkWidget *thbox1;
3128 GtkWidget *thbox2;
3129 GtkWidget *vbox1;
3130 GtkWidget *hbox2;
3131 GtkWidget *infobtn;
3132 GtkWidget *chatbtn;
3133 GtkWidget *msgtext;
3134 GtkWidget *vscrollbar;
3135 GtkWidget *hbox1;
3136 GtkWidget *chat_btn;
3137 GtkWidget *sendbtn;
3138 GtkWidget *okbtn;
3139 GtkWidget *pixmap;
3140 GtkWidget *vpane;
3141 GtkTooltips *tooltips;
3142 char title[64];
3143 struct gchat *gchat;
3144 struct hx_user *user;
3145 u_int16_t icon;
3146 struct msgchat *mc;
3147
3148 mc = msgchat_with_uid(ghtlc, uid);
3149 if (mc) {
3150 gdk_window_show(mc->win->window);
3151 return;
3152 }
3153
3154 snprintf(title, sizeof(title), "To: %s (%u)", nam, uid);
3155
3156 msgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3157 gtk_window_set_policy(GTK_WINDOW(msgwin), 1, 1, 0);
3158 gtk_window_set_title(GTK_WINDOW(msgwin), "msgwin");
3159 gtk_window_set_default_size(GTK_WINDOW(msgwin), 300, 300);
3160 gtk_window_set_title(GTK_WINDOW(msgwin), title);
3161
3162 mc = msgchat_new(ghtlc, uid);
3163 mc->ghtlc = ghtlc;
3164 mc->win = msgwin;
3165 strcpy(mc->name, nam);
3166 gtk_signal_connect_object(GTK_OBJECT(msgwin), "destroy",
3167 GTK_SIGNAL_FUNC(destroy_msgchat), (gpointer)mc);
3168
3169 vbox1 = gtk_vbox_new(0, 0);
3170 gtk_container_add(GTK_CONTAINER(msgwin), vbox1);
3171
3172 hbox2 = gtk_hbox_new(0, 5);
3173 gtk_box_pack_start(GTK_BOX(vbox1), hbox2, 0, 0, 0);
3174 gtk_container_set_border_width(GTK_CONTAINER(hbox2), 5);
3175
3176 tooltips = gtk_tooltips_new();
3177
3178 infobtn = icon_button_new(ICON_INFO, "Get Info", msgwin, tooltips);
3179 gtk_signal_connect_object(GTK_OBJECT(infobtn), "clicked",
3180 GTK_SIGNAL_FUNC(msgwin_get_info), (gpointer)mc);
3181 gtk_box_pack_start(GTK_BOX(hbox2), infobtn, 0, 0, 0);
3182
3183 chatbtn = icon_button_new(ICON_CHAT, "Chat", msgwin, tooltips);
3184 gtk_signal_connect_object(GTK_OBJECT(chatbtn), "clicked",
3185 GTK_SIGNAL_FUNC(msgwin_chat), (gpointer)mc);
3186
3187 gtk_box_pack_start(GTK_BOX(hbox2), chatbtn, 0, 0, 0);
3188
3189 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev)
3190 if (!gchat->prev)
3191 break;
3192
3193 if (gchat && gchat->chat) {
3194 user = hx_user_with_uid(gchat->chat->user_list, uid);
3195 if (user) {
3196 icon = user->icon;
3197 gtk_widget_realize(msgwin);
3198 pixmap = user_pixmap(msgwin, ghtlc->users_font, colorgdk(user->color), icon, nam);
3199 if (pixmap)
3200 gtk_box_pack_start(GTK_BOX(hbox2), pixmap, 0, 1, 0);
3201 }
3202 }
3203
3204 msgtext = gtk_text_new(0, 0);
3205 gtk_text_set_editable(GTK_TEXT(msgtext), 0);
3206 mc->from_text = msgtext;
3207 vscrollbar = gtk_vscrollbar_new(GTK_TEXT(msgtext)->vadj);
3208 thbox1 = gtk_hbox_new(0, 0);
3209 gtk_box_pack_start(GTK_BOX(thbox1), msgtext, 1, 1, 0);
3210 gtk_box_pack_start(GTK_BOX(thbox1), vscrollbar, 0, 0, 0);
3211
3212 msgtext = gtk_text_new(0, 0);
3213 gtk_text_set_editable(GTK_TEXT(msgtext), 1);
3214 mc->to_text = msgtext;
3215 vscrollbar = gtk_vscrollbar_new(GTK_TEXT(msgtext)->vadj);
3216 thbox2 = gtk_hbox_new(0, 0);
3217 gtk_box_pack_start(GTK_BOX(thbox2), msgtext, 1, 1, 0);
3218 gtk_box_pack_start(GTK_BOX(thbox2), vscrollbar, 0, 0, 0);
3219
3220 mc->from_hbox = thbox1;
3221 mc->to_hbox = thbox2;
3222 gtk_widget_set_usize(mc->from_hbox, 300, 40);
3223 gtk_widget_set_usize(mc->to_hbox, 300, 260);
3224
3225 vpane = gtk_vpaned_new();
3226 gtk_paned_add1(GTK_PANED(vpane), thbox1);
3227 gtk_paned_add2(GTK_PANED(vpane), thbox2);
3228 gtk_box_pack_start(GTK_BOX(vbox1), vpane, 1, 1, 0);
3229 mc->vpane = vpane;
3230
3231 hbox1 = gtk_hbox_new(0, 5);
3232 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, 0, 0, 0);
3233 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 5);
3234
3235 chat_btn = gtk_check_button_new_with_label("Chat");
3236 gtk_signal_connect(GTK_OBJECT(chat_btn), "clicked",
3237 GTK_SIGNAL_FUNC(chat_chk_activate), mc);
3238 gtk_widget_set_usize(chat_btn, 55, -2);
3239
3240 sendbtn = gtk_button_new_with_label("Send and Close");
3241 gtk_signal_connect_object(GTK_OBJECT(sendbtn), "clicked",
3242 GTK_SIGNAL_FUNC(users_send_message), (gpointer)mc);
3243 gtk_widget_set_usize(sendbtn, 110, -2);
3244
3245 okbtn = gtk_button_new_with_label("Dismiss");
3246 gtk_widget_set_usize(okbtn, 55, -2);
3247 gtk_signal_connect_object(GTK_OBJECT(okbtn), "clicked",
3248 GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(msgwin));
3249
3250 gtk_box_pack_start(GTK_BOX(hbox1), chat_btn, 0, 0, 0);
3251 gtk_box_pack_end(GTK_BOX(hbox1), sendbtn, 0, 0, 0);
3252 gtk_box_pack_end(GTK_BOX(hbox1), okbtn, 0, 0, 0);
3253
3254 gtk_widget_show_all(msgwin);
3255
3256 keyaccel_attach(ghtlc, msgwin);
3257 }
3258
3259 #define CM_NENTRIES(cme) (sizeof(cme)/sizeof(struct context_menu_entry))
3260
3261 struct context_menu_entry {
3262 char *name;
3263 GtkSignalFunc signal_func;
3264 gpointer data;
3265 GtkWidget *menuitem;
3266 struct context_menu *submenu;
3267 guint hid;
3268 };
3269
3270 struct context_menu {
3271 GtkWidget *menu;
3272 guint nentries;
3273 struct context_menu_entry entries[1];
3274 };
3275
3276 static void
context_menu_delete(struct context_menu * cmenu)3277 context_menu_delete (struct context_menu *cmenu)
3278 {
3279 struct context_menu_entry *cme = cmenu->entries, *cmeend = cme + cmenu->nentries;
3280
3281 for (cme = cmenu->entries; cme < cmeend; cme++)
3282 xfree(cme->name);
3283 gtk_widget_destroy(cmenu->menu);
3284 xfree(cmenu);
3285 }
3286
3287 static struct context_menu *
context_menu_new(struct context_menu_entry * incme,guint nentries)3288 context_menu_new (struct context_menu_entry *incme, guint nentries)
3289 {
3290 struct context_menu_entry *cme, *incmeend = incme + nentries;
3291 struct context_menu *cmenu;
3292 GtkWidget *menu, *menuitem;
3293 guint hid;
3294
3295 cmenu = xmalloc(sizeof(struct context_menu) + nentries * sizeof(struct context_menu_entry));
3296 menu = gtk_menu_new();
3297 cmenu->menu = menu;
3298 cmenu->nentries = nentries;
3299 for (cme = cmenu->entries; incme < incmeend; incme++, cme++) {
3300 if (incme->name)
3301 cme->name = xstrdup(incme->name);
3302 else
3303 cme->name = 0;
3304 cme->signal_func = incme->signal_func;
3305 cme->data = incme->data;
3306 cme->submenu = incme->submenu;
3307 if (cme->name)
3308 menuitem = gtk_menu_item_new_with_label(cme->name);
3309 else
3310 menuitem = gtk_menu_item_new();
3311 if (cme->signal_func)
3312 hid = gtk_signal_connect_object(GTK_OBJECT(menuitem), "activate",
3313 cme->signal_func, cme->data);
3314 else
3315 hid = 0;
3316 if (cme->submenu)
3317 gtk_menu_item_set_submenu(GTK_MENU_ITEM(cme->menuitem), cme->submenu->menu);
3318 gtk_menu_append(GTK_MENU(menu), menuitem);
3319 if (!cme->signal_func)
3320 gtk_widget_set_sensitive(menuitem, 0);
3321 gtk_widget_show(menuitem);
3322 cme->menuitem = menuitem;
3323 cme->hid = hid;
3324 }
3325
3326 return cmenu;
3327 }
3328
3329 static void
context_menu_set_data(struct context_menu * cmenu,guint i,gpointer data)3330 context_menu_set_data (struct context_menu *cmenu, guint i, gpointer data)
3331 {
3332 struct context_menu_entry *cme = cmenu->entries + i;
3333 guint hid;
3334 GtkWidget *menuitem;
3335
3336 menuitem = cme->menuitem;
3337 hid = cme->hid;
3338 if (hid)
3339 gtk_signal_disconnect(GTK_OBJECT(menuitem), hid);
3340 if (cme->signal_func)
3341 hid = gtk_signal_connect_object(GTK_OBJECT(menuitem), "activate",
3342 cme->signal_func, data);
3343 cme->hid = hid;
3344 cme->data = data;
3345 }
3346
3347 static void
context_menu_set_submenu(struct context_menu * cmenu,guint i,struct context_menu * submenu)3348 context_menu_set_submenu (struct context_menu *cmenu, guint i, struct context_menu *submenu)
3349 {
3350 struct context_menu_entry *cme = cmenu->entries + i;
3351
3352 cme->submenu = submenu;
3353 if (submenu) {
3354 gtk_menu_item_set_submenu(GTK_MENU_ITEM(cme->menuitem), submenu->menu);
3355 gtk_widget_set_sensitive(cme->menuitem, 1);
3356 } else {
3357 gtk_menu_item_set_submenu(GTK_MENU_ITEM(cme->menuitem), 0);
3358 if (!cme->signal_func)
3359 gtk_widget_set_sensitive(cme->menuitem, 0);
3360 }
3361 }
3362
3363 static void
user_message_btn(gpointer data)3364 user_message_btn (gpointer data)
3365 {
3366 struct gchat *gchat = (struct gchat *)data;
3367 struct hx_user *user;
3368 GtkWidget *users_list;
3369 GList *lp;
3370 gint row;
3371
3372 users_list = gchat->users_list;
3373 if (!users_list)
3374 return;
3375 for (lp = GTK_HLIST(users_list)->selection; lp; lp = lp->next) {
3376 row = GPOINTER_TO_INT(lp->data);
3377 user = gtk_hlist_get_row_data(GTK_HLIST(users_list), row);
3378 if (!user)
3379 return;
3380 users_open_message(gchat->ghtlc, user->uid, user->name);
3381 }
3382 }
3383
3384 static void
user_info_btn(gpointer data)3385 user_info_btn (gpointer data)
3386 {
3387 struct gchat *gchat = (struct gchat *)data;
3388 struct hx_user *user;
3389 GtkWidget *users_list;
3390 GList *lp;
3391 gint row;
3392
3393 users_list = gchat->users_list;
3394 if (!users_list)
3395 return;
3396 for (lp = GTK_HLIST(users_list)->selection; lp; lp = lp->next) {
3397 row = GPOINTER_TO_INT(lp->data);
3398 user = gtk_hlist_get_row_data(GTK_HLIST(users_list), row);
3399 if (!user)
3400 return;
3401 hx_get_user_info(gchat->ghtlc->htlc, user->uid, 0);
3402 }
3403 }
3404
3405 static void
user_kick_btn(gpointer data)3406 user_kick_btn (gpointer data)
3407 {
3408 struct gchat *gchat = (struct gchat *)data;
3409 struct hx_user *user;
3410 GtkWidget *users_list;
3411 GList *lp;
3412 gint row;
3413
3414 users_list = gchat->users_list;
3415 if (!users_list)
3416 return;
3417 for (lp = GTK_HLIST(users_list)->selection; lp; lp = lp->next) {
3418 row = GPOINTER_TO_INT(lp->data);
3419 user = gtk_hlist_get_row_data(GTK_HLIST(users_list), row);
3420 if (!user)
3421 return;
3422 hx_kick_user(gchat->ghtlc->htlc, user->uid, 0);
3423 }
3424 }
3425
3426 static void
user_ban_btn(gpointer data)3427 user_ban_btn (gpointer data)
3428 {
3429 struct gchat *gchat = (struct gchat *)data;
3430 struct hx_user *user;
3431 GtkWidget *users_list;
3432 GList *lp;
3433 gint row;
3434
3435 users_list = gchat->users_list;
3436 if (!users_list)
3437 return;
3438 for (lp = GTK_HLIST(users_list)->selection; lp; lp = lp->next) {
3439 row = GPOINTER_TO_INT(lp->data);
3440 user = gtk_hlist_get_row_data(GTK_HLIST(users_list), row);
3441 if (!user)
3442 return;
3443 hx_kick_user(gchat->ghtlc->htlc, user->uid, 1);
3444 }
3445 }
3446
3447 static void
user_chat_btn(gpointer data)3448 user_chat_btn (gpointer data)
3449 {
3450 struct gchat *gchat = (struct gchat *)data;
3451 struct hx_user *user;
3452 GtkWidget *users_list;
3453 GList *lp;
3454 gint row;
3455
3456 users_list = gchat->users_list;
3457 if (!users_list)
3458 return;
3459 for (lp = GTK_HLIST(users_list)->selection; lp; lp = lp->next) {
3460 row = GPOINTER_TO_INT(lp->data);
3461 user = gtk_hlist_get_row_data(GTK_HLIST(users_list), row);
3462 if (!user)
3463 return;
3464 hx_chat_user(gchat->ghtlc->htlc, user->uid);
3465 }
3466 }
3467
3468 static void
user_invite_btn(gpointer data)3469 user_invite_btn (gpointer data)
3470 {
3471 struct gchat *gchat = (struct gchat *)data;
3472 struct gchat *bgchat;
3473 struct hx_user *user;
3474 GtkWidget *users_list;
3475 GList *lp;
3476 gint row;
3477
3478 bgchat = gchat_with_cid(gchat->ghtlc, 0);
3479 users_list = bgchat->users_list;
3480 if (!users_list)
3481 return;
3482 for (lp = GTK_HLIST(users_list)->selection; lp; lp = lp->next) {
3483 row = GPOINTER_TO_INT(lp->data);
3484 user = gtk_hlist_get_row_data(GTK_HLIST(users_list), row);
3485 if (!user)
3486 return;
3487 hx_chat_invite(gchat->ghtlc->htlc, gchat->chat->cid, user->uid);
3488 }
3489 }
3490
3491 static void create_useredit_window (struct ghtlc_conn *ghtlc);
3492
3493 static void
user_edit_btn(gpointer data)3494 user_edit_btn (gpointer data)
3495 {
3496 struct gchat *gchat = (struct gchat *)data;
3497 struct hx_user *user;
3498 GtkWidget *users_list;
3499 GList *lp;
3500 gint row;
3501
3502 users_list = gchat->users_list;
3503 if (!users_list)
3504 return;
3505 for (lp = GTK_HLIST(users_list)->selection; lp; lp = lp->next) {
3506 row = GPOINTER_TO_INT(lp->data);
3507 user = gtk_hlist_get_row_data(GTK_HLIST(users_list), row);
3508 if (!user)
3509 return;
3510 hx_get_user_info(gchat->ghtlc->htlc, user->uid, 0);
3511 create_useredit_window(gchat->ghtlc);
3512 }
3513 }
3514
3515 static struct context_menu_entry user_menu_entries[] = {
3516 { "get info", user_info_btn, 0, 0, 0, 0 },
3517 { "message", user_message_btn, 0, 0, 0, 0 },
3518 { "chat", user_chat_btn, 0, 0, 0, 0 },
3519 { "invite", 0, 0, 0, 0, 0 },
3520 { 0, 0, 0, 0, 0, 0 },
3521 { "kick", user_kick_btn, 0, 0, 0, 0 },
3522 { "ban", user_ban_btn, 0, 0, 0, 0 },
3523 { 0, 0, 0, 0, 0, 0 },
3524 { "edit account", user_edit_btn, 0, 0, 0, 0 },
3525 };
3526
3527 static struct context_menu *user_menu;
3528 static struct context_menu *invite_menu;
3529
3530 static struct context_menu *
invite_menu_new(struct ghtlc_conn * ghtlc)3531 invite_menu_new (struct ghtlc_conn *ghtlc)
3532 {
3533 struct context_menu *cmenu;
3534 struct context_menu_entry *cme, *cmep;
3535 struct gchat *gchat;
3536 unsigned int nchats = 0;
3537
3538 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
3539 if (gchat->chat && gchat->chat->cid)
3540 nchats++;
3541 }
3542 if (!nchats)
3543 return 0;
3544 cme = xmalloc(nchats * sizeof(struct context_menu_entry));
3545 cmep = cme;
3546 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
3547 if (!(gchat->chat && gchat->chat->cid))
3548 continue;
3549 cmep->name = g_strdup_printf("0x%x | %s", gchat->chat->cid, gchat->chat->subject);
3550 cmep->signal_func = user_invite_btn;
3551 cmep->data = gchat;
3552 cmep->submenu = 0;
3553 cmep->menuitem = 0;
3554 cmep->hid = 0;
3555 cmep++;
3556 }
3557 cmenu = context_menu_new(cme, nchats);
3558 cmep = cme;
3559 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
3560 if (!(gchat->chat && gchat->chat->cid))
3561 continue;
3562 g_free(cmep->name);
3563 cmep++;
3564 }
3565 xfree(cme);
3566
3567 return cmenu;
3568 }
3569
3570 static gint
user_clicked(GtkWidget * widget,GdkEventButton * event,gpointer data)3571 user_clicked (GtkWidget *widget, GdkEventButton *event, gpointer data)
3572 {
3573 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
3574 int row;
3575 int column;
3576
3577 gtk_hlist_get_selection_info(GTK_HLIST(widget),
3578 event->x, event->y, &row, &column);
3579 if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
3580 struct hx_user *user;
3581
3582 user = gtk_hlist_get_row_data(GTK_HLIST(widget), row);
3583 if (user)
3584 users_open_message(ghtlc, user->uid, user->name);
3585 return 1;
3586 } else if (event->button == 3) {
3587 struct gchat *gchat;
3588
3589 gchat = gchat_with_users_list(ghtlc, widget);
3590 if (!user_menu)
3591 user_menu = context_menu_new(user_menu_entries,
3592 CM_NENTRIES(user_menu_entries));
3593 if (!(gchat->chat && gchat->chat->cid)) {
3594 if (invite_menu)
3595 context_menu_delete(invite_menu);
3596 invite_menu = invite_menu_new(ghtlc);
3597 context_menu_set_submenu(user_menu, 3, invite_menu);
3598 } else {
3599 context_menu_set_submenu(user_menu, 3, 0);
3600 }
3601 if (user_menu->entries[0].data != gchat) {
3602 guint i;
3603 for (i = 0; i < user_menu->nentries; i++)
3604 context_menu_set_data(user_menu, i, gchat);
3605 }
3606 gtk_menu_popup(GTK_MENU(user_menu->menu), 0, 0, 0, 0,
3607 event->button, event->time);
3608 return 1;
3609 }
3610
3611 return 0;
3612 }
3613
3614 static void
users_list_destroy(gpointer data)3615 users_list_destroy (gpointer data)
3616 {
3617 struct gchat *gchat = (struct gchat *)data;
3618 struct ghtlc_conn *ghtlc = gchat->ghtlc;
3619
3620 if (!gchat->chat || !gchat->chat->cid) {
3621 ghtlc->user_msgbtn = 0;
3622 ghtlc->user_infobtn = 0;
3623 ghtlc->user_kickbtn = 0;
3624 ghtlc->user_banbtn = 0;
3625 ghtlc->user_chatbtn = 0;
3626 }
3627 gchat->users_list = 0;
3628 gchat->users_vbox = 0;
3629 }
3630
3631 static void
create_users_window(struct ghtlc_conn * ghtlc,struct gchat * gchat)3632 create_users_window (struct ghtlc_conn *ghtlc, struct gchat *gchat)
3633 {
3634 struct ghx_window *gwin;
3635 struct window_geometry *wg = 0;
3636 GtkWidget *window = 0;
3637 GtkWidget *users_window_scroll;
3638 GtkWidget *vbox;
3639 GtkWidget *hbuttonbox, *topframe;
3640 GtkWidget *msgbtn, *infobtn, *kickbtn, *banbtn, *chatbtn;
3641 GtkWidget *users_list;
3642 GtkTooltips *tooltips;
3643
3644 if (!gchat->chat || !gchat->chat->cid) {
3645 gwin = window_create(ghtlc, WG_USERS);
3646 wg = gwin->wg;
3647 window = gwin->widget;
3648 changetitle(ghtlc, window, "Users");
3649 }
3650
3651 users_list = gtk_hlist_new(1);
3652 GTK_HLIST(users_list)->want_stipple = 1;
3653 gtk_hlist_set_selection_mode(GTK_HLIST(users_list), GTK_SELECTION_EXTENDED);
3654 gtk_hlist_set_column_width(GTK_HLIST(users_list), 0, 240);
3655 gtk_hlist_set_row_height(GTK_HLIST(users_list), 18);
3656 gtk_hlist_set_shadow_type(GTK_HLIST(users_list), GTK_SHADOW_NONE);
3657 gtk_hlist_set_column_justification(GTK_HLIST(users_list), 0, GTK_JUSTIFY_LEFT);
3658 gtk_signal_connect(GTK_OBJECT(users_list), "button_press_event",
3659 GTK_SIGNAL_FUNC(user_clicked), ghtlc);
3660 gtk_signal_connect_object(GTK_OBJECT(users_list), "destroy",
3661 GTK_SIGNAL_FUNC(users_list_destroy), (gpointer)gchat);
3662
3663 if (!ghtlc->users_style) {
3664 if (!ghtlc->users_font)
3665 ghtlc->users_font = gdk_font_load(
3666 #if 0
3667 "-adobe-helvetica-bold-r-*-*-12-140-*-*-*-*-*-*"
3668 #else
3669 "-adobe-helvetica-bold-r-normal-*-12-*-*-*-p-*-iso8859-1"
3670 #endif
3671 );
3672 if (ghtlc->users_font) {
3673 ghtlc->users_style = gtk_style_copy(gtk_widget_get_style(users_list));
3674 ghtlc->users_style->font = ghtlc->users_font;
3675 }
3676 }
3677 if (ghtlc->users_style)
3678 gtk_widget_set_style(users_list, ghtlc->users_style);
3679
3680 users_window_scroll = gtk_scrolled_window_new(0, 0);
3681 SCROLLBAR_SPACING(users_window_scroll) = 0;
3682 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(users_window_scroll),
3683 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
3684 gtk_widget_set_usize(users_window_scroll, 232, 232);
3685 gtk_container_add(GTK_CONTAINER(users_window_scroll), users_list);
3686
3687 tooltips = gtk_tooltips_new();
3688 msgbtn = icon_button_new(ICON_MSG, "Message", users_list, tooltips);
3689 gtk_signal_connect_object(GTK_OBJECT(msgbtn), "clicked",
3690 GTK_SIGNAL_FUNC(user_message_btn), (gpointer)gchat);
3691 infobtn = icon_button_new(ICON_INFO, "Get Info", users_list, tooltips);
3692 gtk_signal_connect_object(GTK_OBJECT(infobtn), "clicked",
3693 GTK_SIGNAL_FUNC(user_info_btn), (gpointer)gchat);
3694 kickbtn = icon_button_new(ICON_KICK, "Kick", users_list, tooltips);
3695 gtk_signal_connect_object(GTK_OBJECT(kickbtn), "clicked",
3696 GTK_SIGNAL_FUNC(user_kick_btn), (gpointer)gchat);
3697 banbtn = icon_button_new(ICON_BAN, "Ban", users_list, tooltips);
3698 gtk_signal_connect_object(GTK_OBJECT(banbtn), "clicked",
3699 GTK_SIGNAL_FUNC(user_ban_btn), (gpointer)gchat);
3700 chatbtn = icon_button_new(ICON_CHAT, "Chat", users_list, tooltips);
3701 gtk_signal_connect_object(GTK_OBJECT(chatbtn), "clicked",
3702 GTK_SIGNAL_FUNC(user_chat_btn), (gpointer)gchat);
3703
3704 vbox = gtk_vbox_new(0, 0);
3705 if (!gchat->chat || !gchat->chat->cid)
3706 gtk_widget_set_usize(vbox, wg->width - 24, wg->height);
3707 else
3708 gtk_widget_set_usize(vbox, 258, 258);
3709
3710 topframe = gtk_frame_new(0);
3711 gtk_box_pack_start(GTK_BOX(vbox), topframe, 0, 0, 0);
3712 gtk_widget_set_usize(topframe, -2, 30);
3713 gtk_frame_set_shadow_type(GTK_FRAME(topframe), GTK_SHADOW_OUT);
3714
3715 hbuttonbox = gtk_hbox_new(0, 0);
3716 gtk_container_add(GTK_CONTAINER(topframe), hbuttonbox);
3717 gtk_box_pack_start(GTK_BOX(hbuttonbox), chatbtn, 0, 0, 2);
3718 gtk_box_pack_start(GTK_BOX(hbuttonbox), msgbtn, 0, 0, 2);
3719 gtk_box_pack_start(GTK_BOX(hbuttonbox), infobtn, 0, 0, 2);
3720 gtk_box_pack_start(GTK_BOX(hbuttonbox), kickbtn, 0, 0, 2);
3721 gtk_box_pack_start(GTK_BOX(hbuttonbox), banbtn, 0, 0, 2);
3722 gtk_box_pack_start(GTK_BOX(vbox), users_window_scroll, 1, 1, 0);
3723
3724 gchat->users_list = users_list;
3725 gchat->users_vbox = vbox;
3726 if (!gchat->chat || !gchat->chat->cid) {
3727 ghtlc->user_msgbtn = msgbtn;
3728 ghtlc->user_infobtn = infobtn;
3729 ghtlc->user_kickbtn = kickbtn;
3730 ghtlc->user_banbtn = banbtn;
3731 ghtlc->user_chatbtn = chatbtn;
3732
3733 gtk_container_add(GTK_CONTAINER(window), vbox);
3734 gtk_widget_show_all(window);
3735 }
3736
3737 gtk_widget_set_sensitive(msgbtn, ghtlc->connected);
3738 gtk_widget_set_sensitive(infobtn, ghtlc->connected);
3739 gtk_widget_set_sensitive(kickbtn, ghtlc->connected);
3740 gtk_widget_set_sensitive(banbtn, ghtlc->connected);
3741 gtk_widget_set_sensitive(chatbtn, ghtlc->connected);
3742 }
3743
3744 static void
user_list(struct htlc_conn * htlc,struct hx_chat * chat)3745 user_list (struct htlc_conn *htlc, struct hx_chat *chat)
3746 {
3747 struct ghtlc_conn *ghtlc;
3748 struct gchat *gchat;
3749 struct hx_user *user;
3750 GtkWidget *users_list;
3751
3752 ghtlc = ghtlc_conn_with_htlc(htlc);
3753 if (!chat->cid) {
3754 gchat = gchat_with_cid(ghtlc, 0);
3755 gchat->chat = chat;
3756 if (!gchat->users_list)
3757 open_users(ghtlc);
3758 } else {
3759 gchat = gchat_with_chat(ghtlc, chat);
3760 if (!gchat) {
3761 create_chat_window(ghtlc, chat);
3762 gchat = gchat_with_chat(ghtlc, chat);
3763 }
3764 }
3765 users_list = gchat->users_list;
3766 if (!users_list)
3767 return;
3768
3769 gtk_hlist_freeze(GTK_HLIST(users_list));
3770 gtk_hlist_clear(GTK_HLIST(users_list));
3771 for (user = chat->user_list->next; user; user = user->next)
3772 hx_output.user_create(htlc, chat, user, user->name, user->icon, user->color);
3773 gtk_hlist_thaw(GTK_HLIST(users_list));
3774 }
3775
3776 static void
open_users(gpointer data)3777 open_users (gpointer data)
3778 {
3779 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
3780 struct gchat *gchat;
3781
3782 gchat = gchat_with_cid(ghtlc, 0);
3783 if (gchat->users_list) {
3784 if (gchat->gwin)
3785 gdk_window_raise(gchat->gwin->widget->window);
3786 return;
3787 }
3788
3789 create_users_window(ghtlc, gchat);
3790
3791 if (gchat->chat)
3792 user_list(ghtlc->htlc, gchat->chat);
3793 }
3794
3795 static void
users_clear(struct htlc_conn * htlc,struct hx_chat * chat)3796 users_clear (struct htlc_conn *htlc, struct hx_chat *chat)
3797 {
3798 struct ghtlc_conn *ghtlc;
3799 struct gchat *gchat;
3800
3801 ghtlc = ghtlc_conn_with_htlc(htlc);
3802 gchat = gchat_with_chat(ghtlc, chat);
3803 if (!gchat || !gchat->users_list)
3804 return;
3805 gtk_hlist_clear(GTK_HLIST(gchat->users_list));
3806 }
3807
3808 static void
user_create(struct htlc_conn * htlc,struct hx_chat * chat,struct hx_user * user,const char * nam,u_int16_t icon,u_int16_t color)3809 user_create (struct htlc_conn *htlc, struct hx_chat *chat, struct hx_user *user,
3810 const char *nam, u_int16_t icon, u_int16_t color)
3811 {
3812 struct ghtlc_conn *ghtlc;
3813 struct gchat *gchat;
3814 struct pixmap_cache *pixc;
3815 GdkPixmap *pixmap;
3816 GdkBitmap *mask;
3817 GtkWidget *users_list;
3818 gint row;
3819 gchar *nulls[1] = {0};
3820
3821 ghtlc = ghtlc_conn_with_htlc(htlc);
3822 if (!chat->cid) {
3823 gchat = gchat_with_cid(ghtlc, 0);
3824 gchat->chat = chat;
3825 if (!gchat->users_list)
3826 open_users(ghtlc);
3827 } else {
3828 gchat = gchat_with_chat(ghtlc, chat);
3829 if (!gchat) {
3830 create_chat_window(ghtlc, chat);
3831 gchat = gchat_with_chat(ghtlc, chat);
3832 }
3833 }
3834 users_list = gchat->users_list;
3835 if (!users_list)
3836 return;
3837
3838 row = gtk_hlist_append(GTK_HLIST(users_list), nulls);
3839 gtk_hlist_set_row_data(GTK_HLIST(users_list), row, user);
3840 gtk_hlist_set_foreground(GTK_HLIST(users_list), row, colorgdk(color));
3841 if (color & 1)
3842 pixc = load_icon(users_list, icon, &user_icon_files, 0, 1);
3843 else
3844 pixc = load_icon(users_list, icon, &user_icon_files, 0, 0);
3845 if (pixc) {
3846 pixmap = pixc->pixmap;
3847 mask = pixc->mask;
3848 } else {
3849 pixmap = 0;
3850 mask = 0;
3851 }
3852 if (!pixmap)
3853 gtk_hlist_set_text(GTK_HLIST(users_list), row, 0, nam);
3854 else
3855 gtk_hlist_set_pixtext(GTK_HLIST(users_list), row, 0, nam, 34, pixmap, mask);
3856
3857 }
3858
3859 static void
user_delete(struct htlc_conn * htlc,struct hx_chat * chat,struct hx_user * user)3860 user_delete (struct htlc_conn *htlc, struct hx_chat *chat, struct hx_user *user)
3861 {
3862 struct ghtlc_conn *ghtlc;
3863 struct gchat *gchat;
3864 GtkWidget *users_list;
3865 gint row;
3866
3867 ghtlc = ghtlc_conn_with_htlc(htlc);
3868 gchat = gchat_with_chat(ghtlc, chat);
3869 if (!gchat)
3870 return;
3871 users_list = gchat->users_list;
3872 if (!users_list)
3873 return;
3874
3875 row = gtk_hlist_find_row_from_data(GTK_HLIST(users_list), user);
3876 gtk_hlist_remove(GTK_HLIST(users_list), row);
3877 }
3878
3879 static void
user_change(struct htlc_conn * htlc,struct hx_chat * chat,struct hx_user * user,const char * nam,u_int16_t icon,u_int16_t color)3880 user_change (struct htlc_conn *htlc, struct hx_chat *chat, struct hx_user *user,
3881 const char *nam, u_int16_t icon, u_int16_t color)
3882 {
3883 struct ghtlc_conn *ghtlc;
3884 struct gchat *gchat;
3885 struct pixmap_cache *pixc;
3886 GdkPixmap *pixmap;
3887 GdkBitmap *mask;
3888 GtkWidget *users_list;
3889 gint row;
3890
3891 ghtlc = ghtlc_conn_with_htlc(htlc);
3892 gchat = gchat_with_chat(ghtlc, chat);
3893 if (!gchat)
3894 return;
3895 users_list = gchat->users_list;
3896 if (!chat->cid) {
3897 for (gchat = ghtlc->gchat_list; gchat; gchat = gchat->prev) {
3898 if (gchat->chat && gchat->chat->cid) {
3899 struct hx_user *u;
3900
3901 u = hx_user_with_uid(gchat->chat->user_list, user->uid);
3902 if (u)
3903 user_change(htlc, gchat->chat, u, nam, icon, color);
3904 }
3905 }
3906 }
3907 if (!users_list)
3908 return;
3909
3910 row = gtk_hlist_find_row_from_data(GTK_HLIST(users_list), user);
3911 gtk_hlist_set_row_data(GTK_HLIST(users_list), row, user);
3912 gtk_hlist_set_foreground(GTK_HLIST(users_list), row, colorgdk(color));
3913 if (color & 1)
3914 pixc = load_icon(users_list, icon, &user_icon_files, 0, 1);
3915 else
3916 pixc = load_icon(users_list, icon, &user_icon_files, 0, 0);
3917
3918 if (pixc) {
3919 pixmap = pixc->pixmap;
3920 mask = pixc->mask;
3921 } else {
3922 pixmap = 0;
3923 mask = 0;
3924 }
3925 if (!pixmap)
3926 gtk_hlist_set_text(GTK_HLIST(users_list), row, 0, nam);
3927 else
3928 gtk_hlist_set_pixtext(GTK_HLIST(users_list), row, 0, nam, 34, pixmap, mask);
3929 }
3930
3931 struct gfile_list {
3932 struct gfile_list *next, *prev;
3933 struct gfile_list *from_gfl;
3934 struct ghtlc_conn *ghtlc;
3935 struct cached_filelist *cfl;
3936 GtkWidget *window, *hlist;
3937 char path[4];
3938 };
3939
3940 static struct gfile_list *
gfl_new(struct ghtlc_conn * ghtlc,GtkWidget * window,GtkWidget * hlist,char * path)3941 gfl_new (struct ghtlc_conn *ghtlc, GtkWidget *window, GtkWidget *hlist, char *path)
3942 {
3943 struct gfile_list *gfl;
3944
3945 gfl = xmalloc(sizeof(struct gfile_list) + strlen(path));
3946 gfl->next = 0;
3947 gfl->prev = ghtlc->gfile_list;
3948 if (ghtlc->gfile_list)
3949 ghtlc->gfile_list->next = gfl;
3950 ghtlc->gfile_list = gfl;
3951 gfl->ghtlc = ghtlc;
3952 gfl->cfl = 0;
3953 gfl->window = window;
3954 gfl->hlist = hlist;
3955 strcpy(gfl->path, path);
3956
3957 return gfl;
3958 }
3959
3960 static void
gfl_delete(struct ghtlc_conn * ghtlc,struct gfile_list * gfl)3961 gfl_delete (struct ghtlc_conn *ghtlc, struct gfile_list *gfl)
3962 {
3963 if (gfl->next)
3964 gfl->next->prev = gfl->prev;
3965 if (gfl->prev)
3966 gfl->prev->next = gfl->next;
3967 if (gfl == ghtlc->gfile_list)
3968 ghtlc->gfile_list = gfl->prev;
3969 xfree(gfl);
3970 }
3971
3972 static void
gfl_delete_all(struct ghtlc_conn * ghtlc)3973 gfl_delete_all (struct ghtlc_conn *ghtlc)
3974 {
3975 struct gfile_list *gfl, *prev;
3976
3977 for (gfl = ghtlc->gfile_list; gfl; gfl = prev) {
3978 prev = gfl->prev;
3979 gtk_widget_destroy(gfl->window);
3980 }
3981 }
3982
3983 static struct gfile_list *
gfl_with_hlist(struct ghtlc_conn * ghtlc,GtkWidget * hlist)3984 gfl_with_hlist (struct ghtlc_conn *ghtlc, GtkWidget *hlist)
3985 {
3986 struct gfile_list *gfl;
3987
3988 for (gfl = ghtlc->gfile_list; gfl; gfl = gfl->prev) {
3989 if (gfl->hlist == hlist)
3990 return gfl;
3991 }
3992
3993 return 0;
3994 }
3995
3996 static struct gfile_list *
gfl_with_path(struct ghtlc_conn * ghtlc,const char * path)3997 gfl_with_path (struct ghtlc_conn *ghtlc, const char *path)
3998 {
3999 struct gfile_list *gfl;
4000
4001 for (gfl = ghtlc->gfile_list; gfl; gfl = gfl->prev) {
4002 if (!strcmp(gfl->path, path))
4003 return gfl;
4004 }
4005
4006 return 0;
4007 }
4008
4009 static struct gfile_list *
gfl_with_cfl(struct ghtlc_conn * ghtlc,struct cached_filelist * cfl)4010 gfl_with_cfl (struct ghtlc_conn *ghtlc, struct cached_filelist *cfl)
4011 {
4012 struct gfile_list *gfl;
4013
4014 for (gfl = ghtlc->gfile_list; gfl; gfl = gfl->prev) {
4015 if (gfl->cfl == cfl)
4016 return gfl;
4017 }
4018 for (gfl = ghtlc->gfile_list; gfl; gfl = gfl->prev) {
4019 if (!strcmp(gfl->path, cfl->path)) {
4020 gfl->cfl = cfl;
4021 return gfl;
4022 }
4023 }
4024
4025 return 0;
4026 }
4027
4028 static void create_files_window (struct ghtlc_conn *ghtlc, char *path);
4029
4030 static void
open_folder(struct ghtlc_conn * ghtlc,struct cached_filelist * cfl,struct hl_filelist_hdr * fh)4031 open_folder (struct ghtlc_conn *ghtlc, struct cached_filelist *cfl, struct hl_filelist_hdr *fh)
4032 {
4033 char path[4096];
4034
4035 if (cfl->path[0] == '/' && cfl->path[1] == 0)
4036 snprintf(path, sizeof(path), "%c%.*s", dir_char,
4037 (int)ntohl(fh->fnlen), fh->fname);
4038 else
4039 snprintf(path, sizeof(path), "%s%c%.*s",
4040 cfl->path, dir_char, (int)ntohl(fh->fnlen), fh->fname);
4041 if (gfl_with_path(ghtlc, path))
4042 return;
4043 create_files_window(ghtlc, path);
4044 hx_list_dir(ghtlc->htlc, path, 1, 0, 0);
4045 }
4046
4047 static void
open_file(struct ghtlc_conn * ghtlc,struct cached_filelist * cfl,struct hl_filelist_hdr * fh)4048 open_file (struct ghtlc_conn *ghtlc, struct cached_filelist *cfl, struct hl_filelist_hdr *fh)
4049 {
4050 struct htxf_conn *htxf;
4051 char rpath[4096], lpath[4096];
4052
4053 snprintf(rpath, sizeof(rpath), "%s%c%.*s", cfl->path, dir_char, (int)ntohl(fh->fnlen), fh->fname);
4054 snprintf(lpath, sizeof(lpath), "%.*s", (int)ntohl(fh->fnlen), fh->fname);
4055 htxf = xfer_new(ghtlc->htlc, lpath, rpath, XFER_GET);
4056 htxf->opt.retry = 1;
4057 }
4058
4059 static void
file_reload_btn(gpointer data)4060 file_reload_btn (gpointer data)
4061 {
4062 struct gfile_list *gfl = (struct gfile_list *)data;
4063 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4064 GtkWidget *files_list = gfl->hlist;
4065
4066 if (!gfl->cfl)
4067 return;
4068
4069 gtk_hlist_clear(GTK_HLIST(files_list));
4070 hx_list_dir(ghtlc->htlc, gfl->cfl->path, 1, 0, 0);
4071 }
4072
4073 static void
file_download_btn(gpointer data)4074 file_download_btn (gpointer data)
4075 {
4076 struct gfile_list *gfl = (struct gfile_list *)data;
4077 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4078 GtkWidget *files_list = gfl->hlist;
4079 GList *lp;
4080 gint row;
4081 struct hl_filelist_hdr *fh;
4082
4083 if (!gfl->cfl)
4084 return;
4085
4086 for (lp = GTK_HLIST(files_list)->selection; lp; lp = lp->next) {
4087 row = GPOINTER_TO_INT(lp->data);
4088 fh = gtk_hlist_get_row_data(GTK_HLIST(files_list), row);
4089 if (fh) {
4090 if (memcmp(&fh->ftype, "fldr", 4)) {
4091 open_file(ghtlc, gfl->cfl, fh);
4092 }
4093 }
4094 }
4095 }
4096
4097 static void
filsel_ok(GtkWidget * widget,gpointer data)4098 filsel_ok (GtkWidget *widget, gpointer data)
4099 {
4100 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
4101 GtkWidget *files_list = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "fileslist");
4102 GtkWidget *filsel = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "filsel");
4103 struct gfile_list *gfl;
4104 char *lpath;
4105 char rpath[4096];
4106 struct htxf_conn *htxf;
4107
4108 gfl = gfl_with_hlist(ghtlc, files_list);
4109 if (!gfl || !gfl->cfl)
4110 return;
4111
4112 lpath = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filsel));
4113 if (!lpath)
4114 return;
4115 snprintf(rpath, sizeof(rpath), "%s%c%s", gfl->cfl->path, dir_char, basename(lpath));
4116 htxf = xfer_new(ghtlc->htlc, lpath, rpath, XFER_PUT);
4117 htxf->opt.retry = 1;
4118
4119 gtk_widget_destroy(filsel);
4120 }
4121
4122 static void
file_upload_btn(gpointer data)4123 file_upload_btn (gpointer data)
4124 {
4125 struct gfile_list *gfl = (struct gfile_list *)data;
4126 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4127 GtkWidget *files_list = gfl->hlist;
4128 GtkWidget *filsel;
4129 char *title;
4130
4131 gfl = gfl_with_hlist(ghtlc, files_list);
4132 if (!gfl || !gfl->cfl)
4133 return;
4134
4135 title = g_strdup_printf("Upload to %s", gfl->cfl->path);
4136 filsel = gtk_file_selection_new(title);
4137 g_free(title);
4138 gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(filsel)->ok_button), "fileslist", files_list);
4139 gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(filsel)->ok_button), "filsel", filsel);
4140 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filsel)->ok_button), "clicked",
4141 GTK_SIGNAL_FUNC(filsel_ok), ghtlc);
4142 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(filsel)->cancel_button),
4143 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(filsel));
4144
4145 gtk_widget_show_all(filsel);
4146 }
4147
4148 static void
file_preview_btn(gpointer data)4149 file_preview_btn (gpointer data)
4150 {
4151 struct gfile_list *gfl = (struct gfile_list *)data;
4152 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4153 GtkWidget *files_list = gfl->hlist;
4154 GList *lp;
4155 gint row;
4156 struct hl_filelist_hdr *fh;
4157 char rpath[4096];
4158
4159 gfl = gfl_with_hlist(ghtlc, files_list);
4160 if (!gfl || !gfl->cfl)
4161 return;
4162
4163 for (lp = GTK_HLIST(files_list)->selection; lp; lp = lp->next) {
4164 row = GPOINTER_TO_INT(lp->data);
4165 fh = gtk_hlist_get_row_data(GTK_HLIST(files_list), row);
4166 if (fh) {
4167 snprintf(rpath, sizeof(rpath), "%s%c%.*s",
4168 gfl->cfl->path, dir_char, (int)ntohl(fh->fnlen), fh->fname);
4169 hx_get_file_info(ghtlc->htlc, rpath, 0);
4170 }
4171 }
4172 }
4173
4174 static void
file_info_btn(gpointer data)4175 file_info_btn (gpointer data)
4176 {
4177 struct gfile_list *gfl = (struct gfile_list *)data;
4178 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4179 GtkWidget *files_list = gfl->hlist;
4180 GList *lp;
4181 gint row;
4182 struct hl_filelist_hdr *fh;
4183 char rpath[4096];
4184
4185 gfl = gfl_with_hlist(ghtlc, files_list);
4186 if (!gfl || !gfl->cfl)
4187 return;
4188
4189 for (lp = GTK_HLIST(files_list)->selection; lp; lp = lp->next) {
4190 row = GPOINTER_TO_INT(lp->data);
4191 fh = gtk_hlist_get_row_data(GTK_HLIST(files_list), row);
4192 if (fh) {
4193 snprintf(rpath, sizeof(rpath), "%s%c%.*s",
4194 gfl->cfl->path, dir_char, (int)ntohl(fh->fnlen), fh->fname);
4195 hx_get_file_info(ghtlc->htlc, rpath, 0);
4196 }
4197 }
4198 }
4199
4200 static void
file_delete_btn(GtkWidget * widget,gpointer data)4201 file_delete_btn (GtkWidget *widget, gpointer data)
4202 {
4203 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
4204 GtkWidget *files_list = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "fileslist");
4205 GtkWidget *dialog = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "dialog");
4206 struct gfile_list *gfl;
4207 GList *lp;
4208 gint row;
4209 struct hl_filelist_hdr *fh;
4210 char rpath[4096];
4211
4212 gfl = gfl_with_hlist(ghtlc, files_list);
4213 if (!gfl || !gfl->cfl)
4214 return;
4215
4216 for (lp = GTK_HLIST(files_list)->selection; lp; lp = lp->next) {
4217 row = GPOINTER_TO_INT(lp->data);
4218 fh = gtk_hlist_get_row_data(GTK_HLIST(files_list), row);
4219 if (fh) {
4220 snprintf(rpath, sizeof(rpath), "%s%c%.*s",
4221 gfl->cfl->path, dir_char, (int)ntohl(fh->fnlen), fh->fname);
4222 hx_file_delete(ghtlc->htlc, rpath, 0);
4223 }
4224 }
4225 gtk_widget_destroy(dialog);
4226 }
4227
4228 static void
file_delete_btn_ask(gpointer data)4229 file_delete_btn_ask (gpointer data)
4230 {
4231 struct gfile_list *gfl = (struct gfile_list *)data;
4232 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4233 GtkWidget *files_list = gfl->hlist;
4234 GtkWidget *dialog;
4235 GtkWidget *btnhbox;
4236 GtkWidget *okbtn;
4237 GtkWidget *cancelbtn;
4238
4239 if (!GTK_HLIST(files_list)->selection)
4240 return;
4241
4242 dialog = gtk_dialog_new();
4243 gtk_window_set_title(GTK_WINDOW(dialog), "Confirm Delete");
4244 okbtn = gtk_button_new_with_label("OK");
4245 gtk_object_set_data(GTK_OBJECT(okbtn), "dialog", dialog);
4246 gtk_object_set_data(GTK_OBJECT(okbtn), "fileslist", files_list);
4247 gtk_signal_connect(GTK_OBJECT(okbtn), "clicked",
4248 GTK_SIGNAL_FUNC(file_delete_btn), ghtlc);
4249 cancelbtn = gtk_button_new_with_label("Cancel");
4250 gtk_signal_connect_object(GTK_OBJECT(cancelbtn), "clicked",
4251 GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog));
4252
4253 GTK_WIDGET_SET_FLAGS(okbtn, GTK_CAN_DEFAULT);
4254 GTK_WIDGET_SET_FLAGS(cancelbtn, GTK_CAN_DEFAULT);
4255 btnhbox = gtk_hbox_new(0, 0);
4256 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), btnhbox);
4257 gtk_box_pack_start(GTK_BOX(btnhbox), okbtn, 0, 0, 0);
4258 gtk_box_pack_start(GTK_BOX(btnhbox), cancelbtn, 0, 0, 0);
4259 gtk_widget_grab_default(okbtn);
4260
4261 gtk_widget_show_all(dialog);
4262 }
4263
4264 static void
files_destroy(GtkWidget * widget,gpointer data)4265 files_destroy (GtkWidget *widget, gpointer data)
4266 {
4267 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
4268 struct gfile_list *gfl = (struct gfile_list *)gtk_object_get_data(GTK_OBJECT(widget), "gfl");
4269
4270 gfl_delete(ghtlc, gfl);
4271 }
4272
4273 static void
file_mkdir(GtkWidget * widget,gpointer data)4274 file_mkdir (GtkWidget *widget, gpointer data)
4275 {
4276 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
4277 GtkWidget *dialog = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "dialog");
4278 GtkWidget *entry = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget), "entry");
4279 char *path;
4280
4281 path = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
4282 hx_mkdir(ghtlc->htlc, path);
4283 g_free(path);
4284
4285 gtk_widget_destroy(GTK_WIDGET(dialog));
4286 }
4287
4288 static void
file_folder_btn(gpointer data)4289 file_folder_btn (gpointer data)
4290 {
4291 struct gfile_list *gfl = (struct gfile_list *)data;
4292 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4293 GtkWidget *files_list = gfl->hlist;
4294 GtkWidget *dialog;
4295 GtkWidget *nameentry;
4296 GtkWidget *okbtn;
4297 GtkWidget *cancelbtn;
4298 GtkWidget *namelabel;
4299 GtkWidget *entryhbox;
4300 GtkWidget *btnhbox;
4301 char *path;
4302
4303 gfl = gfl_with_hlist(ghtlc, files_list);
4304 if (!gfl || !gfl->cfl)
4305 return;
4306
4307 dialog = gtk_dialog_new();
4308 gtk_window_set_title(GTK_WINDOW(dialog), "New Folder");
4309 entryhbox = gtk_hbox_new(0, 0);
4310 gtk_container_border_width(GTK_CONTAINER(dialog), 5);
4311 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), entryhbox, 0, 0, 0);
4312 namelabel = gtk_label_new("Name: ");
4313 nameentry = gtk_entry_new();
4314 if (gfl->cfl->path[0] == dir_char && (gfl->cfl->path[1] == dir_char || !gfl->cfl->path[1]))
4315 path = g_strdup_printf("%s%c", gfl->cfl->path+1, dir_char);
4316 else
4317 path = g_strdup_printf("%s%c", gfl->cfl->path, dir_char);
4318 gtk_entry_set_text(GTK_ENTRY(nameentry), path);
4319 g_free(path);
4320 gtk_box_pack_start(GTK_BOX(entryhbox), namelabel, 0, 0, 0);
4321 gtk_box_pack_start(GTK_BOX(entryhbox), nameentry, 0, 0, 0);
4322
4323 okbtn = gtk_button_new_with_label("OK");
4324 gtk_object_set_data(GTK_OBJECT(okbtn), "entry", nameentry);
4325 gtk_object_set_data(GTK_OBJECT(okbtn), "dialog", dialog);
4326 gtk_signal_connect(GTK_OBJECT(okbtn), "clicked",
4327 GTK_SIGNAL_FUNC(file_mkdir), ghtlc);
4328 cancelbtn = gtk_button_new_with_label("Cancel");
4329 gtk_signal_connect_object(GTK_OBJECT(cancelbtn), "clicked",
4330 GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(dialog));
4331
4332 GTK_WIDGET_SET_FLAGS(nameentry, GTK_CAN_DEFAULT);
4333 GTK_WIDGET_SET_FLAGS(okbtn, GTK_CAN_DEFAULT);
4334 GTK_WIDGET_SET_FLAGS(cancelbtn, GTK_CAN_DEFAULT);
4335 btnhbox = gtk_hbox_new(0, 0);
4336 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), btnhbox);
4337 gtk_box_pack_start(GTK_BOX(btnhbox), okbtn, 0, 0, 0);
4338 gtk_box_pack_start(GTK_BOX(btnhbox), cancelbtn, 0, 0, 0);
4339
4340 gtk_widget_show_all(dialog);
4341 }
4342
4343 static struct context_menu_entry file_menu_entries[] = {
4344 { "get info", file_info_btn, 0, 0, 0, 0 },
4345 { "download", file_download_btn, 0, 0, 0, 0 },
4346 { 0, 0, 0, 0, 0, 0 },
4347 { "delete", file_delete_btn_ask, 0, 0, 0, 0 },
4348 { 0, 0, 0, 0, 0, 0 },
4349 { "move", 0, 0, 0, 0, 0 },
4350 { "link", 0, 0, 0, 0, 0 }
4351 };
4352
4353 static struct context_menu *file_menu = 0;
4354 static struct context_menu *move_menu = 0;
4355 static struct context_menu *link_menu = 0;
4356
4357 static void
file_move_btn(gpointer data)4358 file_move_btn (gpointer data)
4359 {
4360 struct gfile_list *gfl = (struct gfile_list *)data;
4361 struct gfile_list *from_gfl = gfl->from_gfl;
4362 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4363 GtkWidget *files_list = from_gfl->hlist;
4364 GList *lp;
4365 gint row;
4366 struct hl_filelist_hdr *fh;
4367 char topath[4096];
4368
4369 snprintf(topath, sizeof(topath), "%s%c", gfl->cfl->path, dir_char);
4370 for (lp = GTK_HLIST(files_list)->selection; lp; lp = lp->next) {
4371 row = GPOINTER_TO_INT(lp->data);
4372 fh = gtk_hlist_get_row_data(GTK_HLIST(files_list), row);
4373 if (fh) {
4374 char frompath[4096];
4375
4376 snprintf(frompath, sizeof(frompath), "%s%c%.*s",
4377 from_gfl->cfl->path, dir_char,
4378 (int)ntohl(fh->fnlen), fh->fname);
4379 hx_file_move(ghtlc->htlc, frompath, topath);
4380 }
4381 }
4382 }
4383
4384 static void
file_link_btn(gpointer data)4385 file_link_btn (gpointer data)
4386 {
4387 struct gfile_list *gfl = (struct gfile_list *)data;
4388 struct gfile_list *from_gfl = gfl->from_gfl;
4389 struct ghtlc_conn *ghtlc = gfl->ghtlc;
4390 GtkWidget *files_list = from_gfl->hlist;
4391 GList *lp;
4392 gint row;
4393 struct hl_filelist_hdr *fh;
4394 char topath[4096];
4395
4396 snprintf(topath, sizeof(topath), "%s%c", gfl->cfl->path, dir_char);
4397 for (lp = GTK_HLIST(files_list)->selection; lp; lp = lp->next) {
4398 row = GPOINTER_TO_INT(lp->data);
4399 fh = gtk_hlist_get_row_data(GTK_HLIST(files_list), row);
4400 if (fh) {
4401 char frompath[4096];
4402
4403 snprintf(frompath, sizeof(frompath), "%s%c%.*s",
4404 from_gfl->cfl->path, dir_char,
4405 (int)ntohl(fh->fnlen), fh->fname);
4406 hx_file_link(ghtlc->htlc, frompath, topath);
4407 }
4408 }
4409 }
4410
4411 static struct context_menu *
move_menu_new(struct ghtlc_conn * ghtlc,struct gfile_list * this_gfl,void (* movefn)(gpointer))4412 move_menu_new (struct ghtlc_conn *ghtlc, struct gfile_list *this_gfl, void (*movefn)(gpointer))
4413 {
4414 struct context_menu *cmenu;
4415 struct context_menu_entry *cme, *cmep;
4416 struct gfile_list *gfl;
4417 unsigned int nfl = 0;
4418
4419 for (gfl = ghtlc->gfile_list; gfl; gfl = gfl->prev) {
4420 if (gfl->cfl && gfl != this_gfl)
4421 nfl++;
4422 }
4423 if (!nfl)
4424 return 0;
4425 cme = xmalloc(nfl * sizeof(struct context_menu_entry));
4426 cmep = cme;
4427 for (gfl = ghtlc->gfile_list; gfl; gfl = gfl->prev) {
4428 if (!gfl->cfl || gfl == this_gfl)
4429 continue;
4430 gfl->from_gfl = this_gfl;
4431 cmep->name = xstrdup(gfl->cfl->path);
4432 cmep->signal_func = movefn;
4433 cmep->data = gfl;
4434 cmep->submenu = 0;
4435 cmep->menuitem = 0;
4436 cmep->hid = 0;
4437 cmep++;
4438 }
4439 cmenu = context_menu_new(cme, nfl);
4440 cmep = cme;
4441 for (gfl = ghtlc->gfile_list; gfl; gfl = gfl->prev) {
4442 if (!gfl->cfl || gfl == this_gfl)
4443 continue;
4444 xfree(cmep->name);
4445 cmep++;
4446 }
4447 xfree(cme);
4448
4449 return cmenu;
4450 }
4451
4452 static gint
file_clicked(GtkWidget * widget,GdkEventButton * event,gpointer data)4453 file_clicked (GtkWidget *widget, GdkEventButton *event, gpointer data)
4454 {
4455 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
4456 struct gfile_list *gfl;
4457 int row;
4458 int column;
4459
4460 gfl = gfl_with_hlist(ghtlc, widget);
4461 if (!gfl)
4462 return 1;
4463
4464 gtk_hlist_get_selection_info(GTK_HLIST(widget),
4465 event->x, event->y, &row, &column);
4466 if (event->type == GDK_2BUTTON_PRESS && event->button == 1) {
4467 struct hl_filelist_hdr *fh;
4468
4469 fh = gtk_hlist_get_row_data(GTK_HLIST(widget), row);
4470 if (fh) {
4471 if (!memcmp(&fh->ftype, "fldr", 4)) {
4472 open_folder(ghtlc, gfl->cfl, fh);
4473 } else {
4474 open_file(ghtlc, gfl->cfl, fh);
4475 }
4476 }
4477 return 1;
4478 } else if (event->button == 3) {
4479 if (!file_menu)
4480 file_menu = context_menu_new(file_menu_entries,
4481 CM_NENTRIES(file_menu_entries));
4482 if (move_menu)
4483 context_menu_delete(move_menu);
4484 move_menu = move_menu_new(ghtlc, gfl, file_move_btn);
4485 if (link_menu)
4486 context_menu_delete(link_menu);
4487 link_menu = move_menu_new(ghtlc, gfl, file_link_btn);
4488 context_menu_set_submenu(file_menu, 5, move_menu);
4489 context_menu_set_submenu(file_menu, 6, link_menu);
4490 if (file_menu->entries[0].data != gfl) {
4491 guint i;
4492 for (i = 0; i < file_menu->nentries; i++)
4493 context_menu_set_data(file_menu, i, gfl);
4494 }
4495 gtk_menu_popup(GTK_MENU(file_menu->menu), 0, 0, 0, 0,
4496 event->button, event->time);
4497 return 1;
4498 }
4499
4500 return 0;
4501 }
4502
4503 static gint
file_key_press(GtkWidget * widget,GdkEventKey * event,gpointer data)4504 file_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
4505 {
4506 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
4507 struct gfile_list *gfl;
4508 struct hl_filelist_hdr *fh;
4509 GtkWidget *files_list;
4510 GList *lp;
4511 gint row;
4512 guint k;
4513
4514 k = event->keyval;
4515 if (k == GDK_Return) {
4516 gfl = gfl_with_hlist(ghtlc, widget);
4517 if (!gfl)
4518 return 1;
4519 files_list = gfl->hlist;
4520 for (lp = GTK_HLIST(files_list)->selection; lp; lp = lp->next) {
4521 row = GPOINTER_TO_INT(lp->data);
4522 fh = gtk_hlist_get_row_data(GTK_HLIST(files_list), row);
4523 if (fh) {
4524 if (!memcmp(&fh->ftype, "fldr", 4)) {
4525 open_folder(ghtlc, gfl->cfl, fh);
4526 } else {
4527 open_file(ghtlc, gfl->cfl, fh);
4528 }
4529 }
4530 }
4531 return 1;
4532 }
4533
4534 return 0;
4535 }
4536
4537 static void
create_files_window(struct ghtlc_conn * ghtlc,char * path)4538 create_files_window (struct ghtlc_conn *ghtlc, char *path)
4539 {
4540 GtkWidget *files_window;
4541 GtkWidget *files_list;
4542 GtkWidget *files_window_scroll;
4543 GtkWidget *reloadbtn;
4544 GtkWidget *downloadbtn;
4545 GtkWidget *uploadbtn;
4546 GtkWidget *folderbtn;
4547 GtkWidget *previewbtn;
4548 GtkWidget *infobtn;
4549 GtkWidget *deletebtn;
4550 GtkWidget *vbox;
4551 GtkWidget *hbuttonbox;
4552 GtkWidget *topframe;
4553 GtkTooltips *tooltips;
4554 struct gfile_list *gfl;
4555 static gchar *titles[] = {"Name", "Size"};
4556
4557 files_list = gtk_hlist_new_with_titles(2, titles);
4558 gtk_hlist_set_column_width(GTK_HLIST(files_list), 0, 240);
4559 gtk_hlist_set_column_width(GTK_HLIST(files_list), 1, 40);
4560 gtk_hlist_set_row_height(GTK_HLIST(files_list), 18);
4561 gtk_hlist_set_shadow_type(GTK_HLIST(files_list), GTK_SHADOW_NONE);
4562 gtk_hlist_set_column_justification(GTK_HLIST(files_list), 0, GTK_JUSTIFY_LEFT);
4563 gtk_hlist_set_selection_mode(GTK_HLIST(files_list), GTK_SELECTION_EXTENDED);
4564 gtk_signal_connect(GTK_OBJECT(files_list), "button_press_event",
4565 GTK_SIGNAL_FUNC(file_clicked), ghtlc);
4566 gtk_signal_connect(GTK_OBJECT(files_list), "key_press_event",
4567 GTK_SIGNAL_FUNC(file_key_press), ghtlc);
4568
4569 files_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4570 gtk_window_set_policy(GTK_WINDOW(files_window), 1, 1, 0);
4571 gtk_window_set_title(GTK_WINDOW(files_window), path);
4572 gtk_widget_set_usize(files_window, 320, 400);
4573
4574 gfl = gfl_new(ghtlc, files_window, files_list, path);
4575 gtk_object_set_data(GTK_OBJECT(files_window), "gfl", gfl);
4576 gtk_signal_connect(GTK_OBJECT(files_window), "destroy",
4577 GTK_SIGNAL_FUNC(files_destroy), ghtlc);
4578
4579 files_window_scroll = gtk_scrolled_window_new(0, 0);
4580 SCROLLBAR_SPACING(files_window_scroll) = 0;
4581 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(files_window_scroll),
4582 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
4583
4584 topframe = gtk_frame_new(0);
4585 gtk_widget_set_usize(topframe, -2, 30);
4586 gtk_frame_set_shadow_type(GTK_FRAME(topframe), GTK_SHADOW_OUT);
4587
4588 tooltips = gtk_tooltips_new();
4589 reloadbtn = icon_button_new(ICON_RELOAD, "Reload", files_window, tooltips);
4590 gtk_signal_connect_object(GTK_OBJECT(reloadbtn), "clicked",
4591 GTK_SIGNAL_FUNC(file_reload_btn), (gpointer)gfl);
4592 downloadbtn = icon_button_new(ICON_DOWNLOAD, "Download", files_window, tooltips);
4593 gtk_signal_connect_object(GTK_OBJECT(downloadbtn), "clicked",
4594 GTK_SIGNAL_FUNC(file_download_btn), (gpointer)gfl);
4595 uploadbtn = icon_button_new(ICON_UPLOAD, "Upload", files_window, tooltips);
4596 gtk_signal_connect_object(GTK_OBJECT(uploadbtn), "clicked",
4597 GTK_SIGNAL_FUNC(file_upload_btn), (gpointer)gfl);
4598 folderbtn = icon_button_new(ICON_FOLDER, "New Folder", files_window, tooltips);
4599 gtk_signal_connect_object(GTK_OBJECT(folderbtn), "clicked",
4600 GTK_SIGNAL_FUNC(file_folder_btn), (gpointer)gfl);
4601 previewbtn = icon_button_new(ICON_PREVIEW, "Preview", files_window, tooltips);
4602 gtk_signal_connect_object(GTK_OBJECT(previewbtn), "clicked",
4603 GTK_SIGNAL_FUNC(file_preview_btn), (gpointer)gfl);
4604 infobtn = icon_button_new(ICON_INFO, "Get Info", files_window, tooltips);
4605 gtk_signal_connect_object(GTK_OBJECT(infobtn), "clicked",
4606 GTK_SIGNAL_FUNC(file_info_btn), (gpointer)gfl);
4607 deletebtn = icon_button_new(ICON_TRASH, "Delete", files_window, tooltips);
4608 gtk_signal_connect_object(GTK_OBJECT(deletebtn), "clicked",
4609 GTK_SIGNAL_FUNC(file_delete_btn_ask), (gpointer)gfl);
4610
4611 hbuttonbox = gtk_hbox_new(0, 0);
4612 gtk_box_pack_start(GTK_BOX(hbuttonbox), downloadbtn, 0, 0, 2);
4613 gtk_box_pack_start(GTK_BOX(hbuttonbox), uploadbtn, 0, 0, 2);
4614 gtk_box_pack_start(GTK_BOX(hbuttonbox), deletebtn, 0, 0, 2);
4615 gtk_box_pack_start(GTK_BOX(hbuttonbox), folderbtn, 0, 0, 2);
4616 gtk_box_pack_start(GTK_BOX(hbuttonbox), previewbtn, 0, 0, 2);
4617 gtk_box_pack_start(GTK_BOX(hbuttonbox), infobtn, 0, 0, 2);
4618 gtk_box_pack_start(GTK_BOX(hbuttonbox), reloadbtn, 0, 0, 2);
4619
4620 vbox = gtk_vbox_new(0, 0);
4621 gtk_widget_set_usize(vbox, 240, 400);
4622 gtk_container_add(GTK_CONTAINER(topframe), hbuttonbox);
4623 gtk_box_pack_start(GTK_BOX(vbox), topframe, 0, 0, 0);
4624 gtk_container_add(GTK_CONTAINER(files_window_scroll), files_list);
4625 gtk_box_pack_start(GTK_BOX(vbox), files_window_scroll, 1, 1, 0);
4626 gtk_container_add(GTK_CONTAINER(files_window), vbox);
4627
4628 gtk_widget_show_all(files_window);
4629
4630 keyaccel_attach(ghtlc, files_window);
4631 }
4632
4633 static void
open_files(gpointer data)4634 open_files (gpointer data)
4635 {
4636 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
4637 struct gfile_list *gfl;
4638 char dir_str[2];
4639
4640 dir_str[0] = dir_char;
4641 dir_str[1] = 0;
4642 if ((gfl = gfl_with_path(ghtlc, dir_str))) {
4643 gdk_window_show(gfl->hlist->window);
4644 return;
4645 }
4646 create_files_window(ghtlc, dir_str);
4647 hx_list_dir(ghtlc->htlc, dir_str, 1, 0, 0);
4648 }
4649
4650 char *
strcasestr_len(char * haystack,char * needle,size_t len)4651 strcasestr_len (char *haystack, char *needle, size_t len)
4652 {
4653 char *p, *startn = 0, *np = 0, *end = haystack + len;
4654
4655 for (p = haystack; p < end; p++) {
4656 if (np) {
4657 if (toupper(*p) == toupper(*np)) {
4658 if (!*++np)
4659 return startn;
4660 } else
4661 np = 0;
4662 } else if (toupper(*p) == toupper(*needle)) {
4663 np = needle + 1;
4664 startn = p;
4665 }
4666 }
4667
4668 return 0;
4669 }
4670
4671 static u_int16_t
icon_of_fh(struct hl_filelist_hdr * fh)4672 icon_of_fh (struct hl_filelist_hdr *fh)
4673 {
4674 u_int16_t icon;
4675
4676 if (!memcmp(&fh->ftype, "fldr", 4)) {
4677 u_int32_t len = ntohl(fh->fnlen);
4678 if (strcasestr_len(fh->fname, "DROP BOX", len)
4679 || strcasestr_len(fh->fname, "UPLOAD", len))
4680 icon = ICON_FOLDER_IN;
4681 else
4682 icon = ICON_FOLDER;
4683 } else if (!memcmp(&fh->ftype, "JPEG", 4)
4684 || !memcmp(&fh->ftype, "PNGf", 4)
4685 || !memcmp(&fh->ftype, "GIFf", 4)
4686 || !memcmp(&fh->ftype, "PICT", 4))
4687 icon = ICON_FILE_IMAGE;
4688 else if (!memcmp(&fh->ftype, "MPEG", 4)
4689 || !memcmp(&fh->ftype, "MPG ", 4)
4690 || !memcmp(&fh->ftype, "AVI ", 4)
4691 || !memcmp(&fh->ftype, "MooV", 4))
4692 icon = ICON_FILE_MOOV;
4693 else if (!memcmp(&fh->ftype, "MP3 ", 4))
4694 icon = ICON_FILE_NOTE;
4695 else if (!memcmp(&fh->ftype, "ZIP ", 4))
4696 icon = ICON_FILE_ZIP;
4697 else if (!memcmp(&fh->ftype, "SIT", 3))
4698 icon = ICON_FILE_SIT;
4699 else if (!memcmp(&fh->ftype, "APPL", 4))
4700 icon = ICON_FILE_APPL;
4701 else if (!memcmp(&fh->ftype, "rohd", 4))
4702 icon = ICON_FILE_DISK;
4703 else if (!memcmp(&fh->ftype, "HTft", 4))
4704 icon = ICON_FILE_HTft;
4705 else if (!memcmp(&fh->ftype, "alis", 4))
4706 icon = ICON_FILE_alis;
4707 else
4708 icon = ICON_FILE;
4709
4710 return icon;
4711 }
4712
4713 static void
output_file_list(struct htlc_conn * htlc,struct cached_filelist * cfl)4714 output_file_list (struct htlc_conn *htlc, struct cached_filelist *cfl)
4715 {
4716 struct ghtlc_conn *ghtlc;
4717 GtkWidget *files_list;
4718 struct pixmap_cache *pixc;
4719 GdkPixmap *pixmap;
4720 GdkBitmap *mask;
4721 u_int16_t icon;
4722 gint row;
4723 gchar *nulls[2] = {0, 0};
4724 char humanbuf[LONGEST_HUMAN_READABLE+1], *sizstr;
4725 char namstr[255];
4726 int len;
4727 struct gfile_list *gfl;
4728 struct hl_filelist_hdr *fh;
4729
4730 ghtlc = ghtlc_conn_with_htlc(htlc);
4731 gfl = gfl_with_cfl(ghtlc, cfl);
4732 if (!gfl)
4733 return;
4734 files_list = gfl->hlist;
4735
4736 gtk_hlist_freeze(GTK_HLIST(files_list));
4737 gtk_hlist_clear(GTK_HLIST(files_list));
4738 for (fh = cfl->fh; (u_int32_t)((char *)fh - (char *)cfl->fh) < cfl->fhlen;
4739 (char *)fh += ntohs(fh->len) + SIZEOF_HL_DATA_HDR) {
4740 row = gtk_hlist_append(GTK_HLIST(files_list), nulls);
4741 gtk_hlist_set_row_data(GTK_HLIST(files_list), row, fh);
4742 icon = icon_of_fh(fh);
4743 pixc = load_icon(files_list, icon, &icon_files, 0, 0);
4744 if (pixc) {
4745 pixmap = pixc->pixmap;
4746 mask = pixc->mask;
4747 } else {
4748 pixmap = 0;
4749 mask = 0;
4750 }
4751 len = ntohl(fh->fnlen);
4752 if (len > 255)
4753 len = 255;
4754 memcpy(namstr, fh->fname, len);
4755 namstr[len] = 0;
4756 if (!memcmp(&fh->ftype, "fldr", 4)) {
4757 sizstr = humanbuf;
4758 sprintf(sizstr, "(%u)", ntohl(fh->fsize));
4759 } else {
4760 sizstr = human_size(ntohl(fh->fsize), humanbuf);
4761 }
4762 gtk_hlist_set_text(GTK_HLIST(files_list), row, 1, sizstr);
4763 if (!pixmap)
4764 gtk_hlist_set_text(GTK_HLIST(files_list), row, 0, namstr);
4765 else
4766 gtk_hlist_set_pixtext(GTK_HLIST(files_list), row, 0, namstr, 34, pixmap, mask);
4767 }
4768 gtk_hlist_thaw(GTK_HLIST(files_list));
4769 }
4770
4771 static void
file_info(struct htlc_conn * htlc,const char * icon,const char * type,const char * crea,u_int32_t size,const char * name,const char * created,const char * modified,const char * comment)4772 file_info (struct htlc_conn *htlc, const char *icon, const char *type, const char *crea,
4773 u_int32_t size, const char *name, const char *created, const char *modified,
4774 const char *comment)
4775 {
4776 struct ghtlc_conn *ghtlc;
4777 GtkWidget *info_window;
4778 GtkWidget *vbox;
4779 GtkWidget *name_hbox;
4780 GtkWidget *size_hbox;
4781 GtkWidget *type_hbox;
4782 GtkWidget *crea_hbox;
4783 GtkWidget *created_hbox;
4784 GtkWidget *modified_hbox;
4785 GtkWidget *size_label;
4786 GtkWidget *type_label;
4787 GtkWidget *crea_label;
4788 GtkWidget *created_label;
4789 GtkWidget *modified_label;
4790 GtkWidget *icon_pmap;
4791 GtkWidget *name_entry;
4792 GtkWidget *comment_text;
4793 GtkStyle *style;
4794 char infotitle[1024];
4795 char buf[1024];
4796 char humanbuf[LONGEST_HUMAN_READABLE+1];
4797 struct hl_filelist_hdr *fh;
4798 u_int16_t iconid;
4799
4800 ghtlc = ghtlc_conn_with_htlc(htlc);
4801 info_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4802 gtk_window_set_policy(GTK_WINDOW(info_window), 1, 1, 0);
4803 gtk_widget_set_usize(info_window, 256, 0);
4804
4805 snprintf(infotitle, sizeof(infotitle), "File Info: %s", name);
4806 gtk_window_set_title(GTK_WINDOW(info_window), infotitle);
4807
4808 fh = (struct hl_filelist_hdr *)buf;
4809 fh->ftype = *((u_int32_t *)icon);
4810 fh->fnlen = htonl(strlen(name));
4811 strncpy(fh->fname, name, 768);
4812 iconid = icon_of_fh(fh);
4813 icon_pmap = icon_pixmap(info_window, iconid);
4814 name_entry = gtk_entry_new();
4815 gtk_entry_set_text(GTK_ENTRY(name_entry), name);
4816
4817 comment_text = gtk_text_new(0, 0);
4818 if (ghtlc->gchat_list) {
4819 style = gtk_widget_get_style(ghtlc->gchat_list->chat_output_text);
4820 gtk_widget_set_style(name_entry, style);
4821 gtk_widget_set_style(comment_text, style);
4822 }
4823 gtk_text_insert(GTK_TEXT(comment_text), 0, 0, 0, comment, -1);
4824
4825 sprintf(buf, "Size: %s (%u bytes)", human_size(size, humanbuf), size);
4826 size_label = gtk_label_new(buf);
4827 sprintf(buf, "Type: %s", type);
4828 type_label = gtk_label_new(buf);
4829 sprintf(buf, "Creator: %s", crea);
4830 crea_label = gtk_label_new(buf);
4831 sprintf(buf, "Created: %s", created);
4832 created_label = gtk_label_new(buf);
4833 sprintf(buf, "Modified: %s", modified);
4834 modified_label = gtk_label_new(buf);
4835
4836 size_hbox = gtk_hbox_new(0, 0);
4837 gtk_box_pack_start(GTK_BOX(size_hbox), size_label, 0, 0, 2);
4838 type_hbox = gtk_hbox_new(0, 0);
4839 gtk_box_pack_start(GTK_BOX(type_hbox), type_label, 0, 0, 2);
4840 crea_hbox = gtk_hbox_new(0, 0);
4841 gtk_box_pack_start(GTK_BOX(crea_hbox), crea_label, 0, 0, 2);
4842 created_hbox = gtk_hbox_new(0, 0);
4843 gtk_box_pack_start(GTK_BOX(created_hbox), created_label, 0, 0, 2);
4844 modified_hbox = gtk_hbox_new(0, 0);
4845 gtk_box_pack_start(GTK_BOX(modified_hbox), modified_label, 0, 0, 2);
4846
4847 name_hbox = gtk_hbox_new(0, 0);
4848 gtk_box_pack_start(GTK_BOX(name_hbox), icon_pmap, 0, 0, 2);
4849 gtk_box_pack_start(GTK_BOX(name_hbox), name_entry, 1, 1, 2);
4850 vbox = gtk_vbox_new(0, 0);
4851 gtk_box_pack_start(GTK_BOX(vbox), name_hbox, 0, 0, 2);
4852 gtk_box_pack_start(GTK_BOX(vbox), size_hbox, 0, 0, 2);
4853 gtk_box_pack_start(GTK_BOX(vbox), type_hbox, 0, 0, 2);
4854 gtk_box_pack_start(GTK_BOX(vbox), crea_hbox, 0, 0, 2);
4855 gtk_box_pack_start(GTK_BOX(vbox), created_hbox, 0, 0, 2);
4856 gtk_box_pack_start(GTK_BOX(vbox), modified_hbox, 0, 0, 2);
4857 gtk_box_pack_start(GTK_BOX(vbox), comment_text, 1, 1, 2);
4858 gtk_container_add(GTK_CONTAINER(info_window), vbox);
4859
4860 gtk_widget_show_all(info_window);
4861
4862 keyaccel_attach(ghtlc, info_window);
4863 }
4864
4865 struct gtask {
4866 struct gtask *next, *prev;
4867 u_int32_t trans;
4868 struct htxf_conn *htxf;
4869 GtkWidget *label;
4870 GtkWidget *pbar;
4871 GtkWidget *listitem;
4872 };
4873
4874 static struct gtask *
gtask_with_trans(struct ghtlc_conn * ghtlc,u_int32_t trans)4875 gtask_with_trans (struct ghtlc_conn *ghtlc, u_int32_t trans)
4876 {
4877 struct gtask *gtsk;
4878
4879 for (gtsk = ghtlc->gtask_list; gtsk; gtsk = gtsk->prev) {
4880 if (gtsk->trans == trans)
4881 return gtsk;
4882 }
4883
4884 return 0;
4885 }
4886
4887 static struct gtask *
gtask_with_htxf(struct ghtlc_conn * ghtlc,struct htxf_conn * htxf)4888 gtask_with_htxf (struct ghtlc_conn *ghtlc, struct htxf_conn *htxf)
4889 {
4890 struct gtask *gtsk;
4891
4892 for (gtsk = ghtlc->gtask_list; gtsk; gtsk = gtsk->prev) {
4893 if (gtsk->htxf == htxf)
4894 return gtsk;
4895 }
4896
4897 return 0;
4898 }
4899
4900 static struct gtask *
gtask_new(struct ghtlc_conn * ghtlc,u_int32_t trans,struct htxf_conn * htxf)4901 gtask_new (struct ghtlc_conn *ghtlc, u_int32_t trans, struct htxf_conn *htxf)
4902 {
4903 GtkWidget *pbar;
4904 GtkWidget *vbox;
4905 GtkWidget *hbox;
4906 GtkWidget *label;
4907 GtkWidget *listitem;
4908 struct gtask *gtsk;
4909
4910 gtsk = xmalloc(sizeof(struct gtask));
4911 gtsk->next = 0;
4912 gtsk->prev = ghtlc->gtask_list;
4913 if (ghtlc->gtask_list)
4914 ghtlc->gtask_list->next = gtsk;
4915
4916 pbar = gtk_progress_bar_new();
4917 label = gtk_label_new("");
4918 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
4919 vbox = gtk_vbox_new(0, 0);
4920 hbox = gtk_hbox_new(0, 0);
4921 gtk_widget_set_usize(vbox, 240, 40);
4922 gtk_box_pack_start(GTK_BOX(hbox), label, 0, 0, 0);
4923 gtk_box_pack_start(GTK_BOX(vbox), hbox, 0, 0, 0);
4924 gtk_box_pack_start(GTK_BOX(vbox), pbar, 1, 1, 0);
4925
4926 listitem = gtk_list_item_new();
4927 gtk_object_set_data(GTK_OBJECT(listitem), "gtsk", gtsk);
4928 gtk_container_add(GTK_CONTAINER(listitem), vbox);
4929 if (ghtlc->gtask_gtklist) {
4930 GList *itemlist;
4931
4932 itemlist = g_list_append(0, listitem);
4933 gtk_list_append_items(GTK_LIST(ghtlc->gtask_gtklist), itemlist);
4934 gtk_widget_show_all(listitem);
4935 }
4936
4937 gtsk->label = label;
4938 gtsk->pbar = pbar;
4939 gtsk->listitem = listitem;
4940 gtsk->trans = trans;
4941 gtsk->htxf = htxf;
4942 ghtlc->gtask_list = gtsk;
4943
4944 return gtsk;
4945 }
4946
4947 static void
gtask_delete(struct ghtlc_conn * ghtlc,struct gtask * gtsk)4948 gtask_delete (struct ghtlc_conn *ghtlc, struct gtask *gtsk)
4949 {
4950 if (ghtlc->gtask_gtklist) {
4951 GList *itemlist;
4952
4953 itemlist = g_list_append(0, gtsk->listitem);
4954 gtk_list_remove_items(GTK_LIST(ghtlc->gtask_gtklist), itemlist);
4955 g_list_free(itemlist);
4956 /*gtk_widget_destroy(gtsk->listitem);*/
4957 }
4958 if (gtsk->next)
4959 gtsk->next->prev = gtsk->prev;
4960 if (gtsk->prev)
4961 gtsk->prev->next = gtsk->next;
4962 if (gtsk == ghtlc->gtask_list)
4963 ghtlc->gtask_list = gtsk->prev;
4964 xfree(gtsk);
4965 }
4966
4967 static void
gtask_list_delete(struct ghtlc_conn * ghtlc)4968 gtask_list_delete (struct ghtlc_conn *ghtlc)
4969 {
4970 struct gtask *gtsk, *prev;
4971 GList *itemlist = 0;
4972
4973 for (gtsk = ghtlc->gtask_list; gtsk; gtsk = prev) {
4974 prev = gtsk->prev;
4975 if (ghtlc->gtask_gtklist)
4976 itemlist = g_list_append(itemlist, gtsk->listitem);
4977 /*gtk_widget_destroy(gtsk->listitem);*/
4978 xfree(gtsk);
4979 }
4980 if (ghtlc->gtask_gtklist) {
4981 gtk_list_remove_items(GTK_LIST(ghtlc->gtask_gtklist), itemlist);
4982 g_list_free(itemlist);
4983 gtk_widget_destroy(ghtlc->gtask_gtklist);
4984 ghtlc->gtask_gtklist = 0;
4985 }
4986 ghtlc->gtask_list = 0;
4987 }
4988
4989 static void
task_update(struct htlc_conn * htlc,struct task * tsk)4990 task_update (struct htlc_conn *htlc, struct task *tsk)
4991 {
4992 GtkWidget *pbar;
4993 GtkWidget *label;
4994 char taskstr[256];
4995 struct ghtlc_conn *ghtlc;
4996 struct gtask *gtsk;
4997 u_int32_t pos = tsk->pos, len = tsk->len;
4998
4999 ghtlc = ghtlc_conn_with_htlc(htlc);
5000 gtsk = gtask_with_trans(ghtlc, tsk->trans);
5001 if (!gtsk)
5002 gtsk = gtask_new(ghtlc, tsk->trans, 0);
5003 label = gtsk->label;
5004 pbar = gtsk->pbar;
5005 snprintf(taskstr, sizeof(taskstr), "Task 0x%x (%s) %u/%u", tsk->trans, tsk->str ? tsk->str : "", pos, pos+len);
5006 gtk_label_set_text(GTK_LABEL(label), taskstr);
5007 if (pos)
5008 gtk_progress_bar_update(GTK_PROGRESS_BAR(pbar), (gfloat)pos / (gfloat)(pos + len));
5009
5010 if (len == 0)
5011 gtask_delete(ghtlc, gtsk);
5012 }
5013
5014 static void
tasks_destroy(gpointer data)5015 tasks_destroy (gpointer data)
5016 {
5017 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
5018
5019 gtask_list_delete(ghtlc);
5020 }
5021
5022 static void
task_stop(gpointer data)5023 task_stop (gpointer data)
5024 {
5025 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
5026 struct gtask *gtsk;
5027 GList *lp, *next;
5028 GtkWidget *listitem;
5029
5030 if (!ghtlc->gtask_gtklist)
5031 return;
5032 for (lp = GTK_LIST(ghtlc->gtask_gtklist)->selection; lp; lp = next) {
5033 next = lp->next;
5034 listitem = (GtkWidget *)lp->data;
5035 gtsk = (struct gtask *)gtk_object_get_data(GTK_OBJECT(listitem), "gtsk");
5036 if (gtsk->htxf) {
5037 xfer_delete(gtsk->htxf);
5038 gtask_delete(ghtlc, gtsk);
5039 }
5040 }
5041 }
5042
5043 static void
task_go(gpointer data)5044 task_go (gpointer data)
5045 {
5046 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
5047 struct gtask *gtsk;
5048 GList *lp, *next;
5049 GtkWidget *listitem;
5050
5051 if (!ghtlc->gtask_gtklist)
5052 return;
5053 for (lp = GTK_LIST(ghtlc->gtask_gtklist)->selection; lp; lp = next) {
5054 next = lp->next;
5055 listitem = (GtkWidget *)lp->data;
5056 gtsk = (struct gtask *)gtk_object_get_data(GTK_OBJECT(listitem), "gtsk");
5057 if (gtsk->htxf)
5058 xfer_go(gtsk->htxf);
5059 }
5060 }
5061
5062 extern void task_tasks_update (struct htlc_conn *htlc);
5063 extern void xfer_tasks_update (struct htlc_conn *htlc);
5064
5065 static void
create_tasks_window(struct ghtlc_conn * ghtlc)5066 create_tasks_window (struct ghtlc_conn *ghtlc)
5067 {
5068 struct ghx_window *gwin;
5069 GtkWidget *window;
5070 GtkWidget *vbox;
5071 GtkWidget *scroll;
5072 GtkWidget *gtklist;
5073 GtkWidget *hbuttonbox;
5074 GtkWidget *topframe;
5075 GtkWidget *stopbtn;
5076 GtkWidget *gobtn;
5077 GtkTooltips *tooltips;
5078
5079 if ((gwin = ghx_window_with_wgi(ghtlc, WG_TASKS))) {
5080 gdk_window_show(gwin->widget->window);
5081 return;
5082 }
5083
5084 gwin = window_create(ghtlc, WG_TASKS);
5085 window = gwin->widget;
5086
5087 changetitle(ghtlc, window, "Tasks");
5088
5089 topframe = gtk_frame_new(0);
5090 gtk_widget_set_usize(topframe, -2, 30);
5091 gtk_frame_set_shadow_type(GTK_FRAME(topframe), GTK_SHADOW_OUT);
5092
5093 tooltips = gtk_tooltips_new();
5094 stopbtn = icon_button_new(ICON_KICK, "Stop", window, tooltips);
5095 gtk_signal_connect_object(GTK_OBJECT(stopbtn), "clicked",
5096 GTK_SIGNAL_FUNC(task_stop), (gpointer)ghtlc);
5097 gobtn = icon_button_new(ICON_GO, "Go", window, tooltips);
5098 gtk_signal_connect_object(GTK_OBJECT(stopbtn), "clicked",
5099 GTK_SIGNAL_FUNC(task_go), (gpointer)ghtlc);
5100
5101 hbuttonbox = gtk_hbox_new(0, 0);
5102 gtk_box_pack_start(GTK_BOX(hbuttonbox), stopbtn, 0, 0, 2);
5103 gtk_box_pack_start(GTK_BOX(hbuttonbox), gobtn, 0, 0, 2);
5104 gtk_container_add(GTK_CONTAINER(topframe), hbuttonbox);
5105 vbox = gtk_vbox_new(0, 0);
5106 gtk_box_pack_start(GTK_BOX(vbox), topframe, 0, 0, 0);
5107 gtk_container_add(GTK_CONTAINER(window), vbox);
5108
5109 gtklist = gtk_list_new();
5110 gtk_list_set_selection_mode(GTK_LIST(gtklist), GTK_SELECTION_EXTENDED);
5111 scroll = gtk_scrolled_window_new(0, 0);
5112 SCROLLBAR_SPACING(scroll) = 0;
5113 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
5114 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
5115 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), gtklist);
5116 gtk_box_pack_start(GTK_BOX(vbox), scroll, 1, 1, 0);
5117
5118 gtk_signal_connect_object(GTK_OBJECT(window), "destroy",
5119 GTK_SIGNAL_FUNC(tasks_destroy), (gpointer)ghtlc);
5120
5121 gtask_list_delete(ghtlc);
5122 ghtlc->gtask_gtklist = gtklist;
5123
5124 task_tasks_update(ghtlc->htlc);
5125 xfer_tasks_update(ghtlc->htlc);
5126
5127 gtk_widget_show_all(window);
5128 }
5129
5130 static void
open_tasks(gpointer data)5131 open_tasks (gpointer data)
5132 {
5133 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
5134
5135 create_tasks_window(ghtlc);
5136 }
5137
5138 static void
file_update(struct htxf_conn * htxf)5139 file_update (struct htxf_conn *htxf)
5140 {
5141 GtkWidget *pbar;
5142 GtkWidget *label;
5143 struct ghtlc_conn *ghtlc;
5144 struct gtask *gtsk;
5145 char str[4096];
5146 char humanbuf[LONGEST_HUMAN_READABLE*3+3], *posstr, *sizestr, *bpsstr;
5147 u_int32_t pos, size;
5148 struct timeval now;
5149 time_t sdiff, usdiff, Bps, eta;
5150
5151 ghtlc = ghtlc_conn_with_htlc(htxf->htlc);
5152 if (!ghtlc)
5153 return;
5154 gtsk = gtask_with_htxf(ghtlc, htxf);
5155 if (!gtsk)
5156 gtsk = gtask_new(ghtlc, 0, htxf);
5157 label = gtsk->label;
5158 pbar = gtsk->pbar;
5159 pos = htxf->total_pos;
5160 size = htxf->total_size;
5161
5162 gettimeofday(&now, 0);
5163 sdiff = now.tv_sec - htxf->start.tv_sec;
5164 usdiff = now.tv_usec - htxf->start.tv_usec;
5165 if (!sdiff)
5166 sdiff = 1;
5167 Bps = pos / sdiff;
5168 if (!Bps)
5169 Bps = 1;
5170 eta = (size - pos) / Bps
5171 + ((size - pos) % Bps) / Bps;
5172
5173 posstr = human_size(pos, humanbuf);
5174 sizestr = human_size(size, humanbuf+LONGEST_HUMAN_READABLE+1);
5175 bpsstr = human_size(Bps, humanbuf+LONGEST_HUMAN_READABLE*2+2);
5176 snprintf(str, sizeof(str), "%s %s/%s %s/s ETA: %lu s %s",
5177 htxf->type == XFER_GET ? "get" : "put",
5178 posstr, sizestr, bpsstr, eta, htxf->path);
5179 gtk_label_set_text(GTK_LABEL(label), str);
5180 gtk_progress_bar_update(GTK_PROGRESS_BAR(pbar), (gfloat)pos / (float)size);
5181
5182 if (pos == size)
5183 gtask_delete(ghtlc, gtsk);
5184 }
5185
5186 struct access_name {
5187 int bitno;
5188 char *name;
5189 } access_names[] = {
5190 { -1, "File" },
5191 { 1, "upload files" },
5192 { 2, "download fIles" },
5193 { 4, "move files" },
5194 { 8, "move folders" },
5195 { 5, "create folders" },
5196 { 0, "delete files" },
5197 { 6, "delete folders" },
5198 { 3, "rename files" },
5199 { 7, "rename folders" },
5200 { 28, "comment files" },
5201 { 29, "comment folders" },
5202 { 31, "make aliases" },
5203 { 25, "upload anywhere" },
5204 { 30, "view drop boxes" },
5205 { -1, "Chat" },
5206 { 9, "read chat" },
5207 { 10, "send chat" },
5208 { -1, "News" },
5209 { 20, "read news" },
5210 { 21, "post news" },
5211 { -1, "User" },
5212 { 14, "create users" },
5213 { 15, "delete users" },
5214 { 16, "read users" },
5215 { 17, "modify users" },
5216 { 22, "disconnect users" },
5217 { 23, "not be disconnected" },
5218 { 24, "get user info" },
5219 { 26, "use any name" },
5220 { 27, "not be shown agreement" },
5221 { -1, "Admin" },
5222 { 32, "broadcast" },
5223 };
5224
5225 static int
test_bit(char * buf,int bitno)5226 test_bit (char *buf, int bitno)
5227 {
5228 char c, m;
5229 c = buf[bitno / 8];
5230 bitno = bitno % 8;
5231 bitno = 7 - bitno;
5232 if (!bitno)
5233 m = 1;
5234 else {
5235 m = 2;
5236 while (--bitno)
5237 m *= 2;
5238 }
5239
5240 return c & m;
5241 }
5242
5243 static void
inverse_bit(char * buf,int bitno)5244 inverse_bit (char *buf, int bitno)
5245 {
5246 char *p, c, m;
5247 p = &buf[bitno / 8];
5248 c = *p;
5249 bitno = bitno % 8;
5250 bitno = 7 - bitno;
5251 if (!bitno)
5252 m = 1;
5253 else {
5254 m = 2;
5255 while (--bitno)
5256 m *= 2;
5257 }
5258 if (c & m)
5259 *p = c & ~m;
5260 else
5261 *p = c | m;
5262 }
5263
5264 struct access_widget {
5265 int bitno;
5266 GtkWidget *widget;
5267 };
5268
5269 struct useredit_session {
5270 struct ghtlc_conn *ghtlc;
5271 char access_buf[8];
5272 char name[32];
5273 char login[32];
5274 char pass[32];
5275 GtkWidget *window;
5276 GtkWidget *name_entry;
5277 GtkWidget *login_entry;
5278 GtkWidget *pass_entry;
5279 #define NACCESS 28
5280 struct access_widget access_widgets[NACCESS];
5281 };
5282
5283 static void
user_open(void * __uesp,const char * name,const char * login,const char * pass,const struct hl_access_bits * access)5284 user_open (void *__uesp, const char *name, const char *login, const char *pass, const struct hl_access_bits *access)
5285 {
5286 struct useredit_session *ues = (struct useredit_session *)__uesp;
5287 unsigned int i;
5288 int on;
5289
5290 gtk_entry_set_text(GTK_ENTRY(ues->name_entry), name);
5291 gtk_entry_set_text(GTK_ENTRY(ues->login_entry), login);
5292 gtk_entry_set_text(GTK_ENTRY(ues->pass_entry), pass);
5293 strcpy(ues->name, name);
5294 strcpy(ues->login, login);
5295 strcpy(ues->pass, pass);
5296 memcpy(ues->access_buf, access, 8);
5297 for (i = 0; i < NACCESS; i++) {
5298 on = test_bit(ues->access_buf, ues->access_widgets[i].bitno);
5299 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ues->access_widgets[i].widget), on);
5300 }
5301 }
5302
5303 static void
useredit_login_activate(GtkWidget * widget,gpointer data)5304 useredit_login_activate (GtkWidget *widget, gpointer data)
5305 {
5306 struct useredit_session *ues = (struct useredit_session *)data;
5307 char *login;
5308 size_t len;
5309
5310 login = gtk_entry_get_text(GTK_ENTRY(widget));
5311 if (ues->ghtlc->htlc)
5312 hx_useredit_open(ues->ghtlc->htlc, login, user_open, ues);
5313 len = strlen(login);
5314 if (len > 31)
5315 len = 31;
5316 memcpy(ues->login, login, len);
5317 ues->login[len] = 0;
5318 }
5319
5320 static void
useredit_name_activate(GtkWidget * widget,gpointer data)5321 useredit_name_activate (GtkWidget *widget, gpointer data)
5322 {
5323 struct useredit_session *ues = (struct useredit_session *)data;
5324 char *name;
5325 size_t len;
5326
5327 name = gtk_entry_get_text(GTK_ENTRY(widget));
5328 len = strlen(name);
5329 if (len > 31)
5330 len = 31;
5331 memcpy(ues->name, name, len);
5332 ues->name[len] = 0;
5333 }
5334
5335 static void
useredit_pass_activate(GtkWidget * widget,gpointer data)5336 useredit_pass_activate (GtkWidget *widget, gpointer data)
5337 {
5338 struct useredit_session *ues = (struct useredit_session *)data;
5339 char *pass;
5340 size_t len;
5341
5342 pass = gtk_entry_get_text(GTK_ENTRY(widget));
5343 len = strlen(pass);
5344 if (len > 31)
5345 len = 31;
5346 memcpy(ues->pass, pass, len);
5347 ues->pass[len] = 0;
5348 }
5349
5350 static void
useredit_chk_activate(GtkWidget * widget,gpointer data)5351 useredit_chk_activate (GtkWidget *widget, gpointer data)
5352 {
5353 struct useredit_session *ues = (struct useredit_session *)data;
5354 unsigned int i;
5355 int bitno;
5356
5357 for (i = 0; i < NACCESS; i++) {
5358 if (ues->access_widgets[i].widget == widget)
5359 break;
5360 }
5361 if (i == NACCESS)
5362 return;
5363 bitno = ues->access_widgets[i].bitno;
5364 if (GTK_TOGGLE_BUTTON(widget)->active) {
5365 if (!test_bit(ues->access_buf, bitno))
5366 inverse_bit(ues->access_buf, bitno);
5367 } else {
5368 if (test_bit(ues->access_buf, bitno))
5369 inverse_bit(ues->access_buf, bitno);
5370 }
5371 }
5372
5373 static void
useredit_save(gpointer data)5374 useredit_save (gpointer data)
5375 {
5376 struct useredit_session *ues = (struct useredit_session *)data;
5377
5378 useredit_name_activate(ues->name_entry, data);
5379 useredit_pass_activate(ues->pass_entry, data);
5380 if (ues->ghtlc->htlc)
5381 hx_useredit_create(ues->ghtlc->htlc, ues->login, ues->pass,
5382 ues->name, (struct hl_access_bits *)ues->access_buf);
5383 }
5384
5385 static void
useredit_delete(gpointer data)5386 useredit_delete (gpointer data)
5387 {
5388 struct useredit_session *ues = (struct useredit_session *)data;
5389
5390 if (ues->ghtlc->htlc)
5391 hx_useredit_delete(ues->ghtlc->htlc, ues->login);
5392 }
5393
5394 static void
useredit_close(gpointer data)5395 useredit_close (gpointer data)
5396 {
5397 struct useredit_session *ues = (struct useredit_session *)data;
5398
5399 gtk_widget_destroy(ues->window);
5400 }
5401
5402 static void
useredit_destroy(gpointer data)5403 useredit_destroy (gpointer data)
5404 {
5405 struct useredit_session *ues = (struct useredit_session *)data;
5406
5407 xfree(ues);
5408 }
5409
5410 static void
create_useredit_window(struct ghtlc_conn * ghtlc)5411 create_useredit_window (struct ghtlc_conn *ghtlc)
5412 {
5413 struct ghx_window *gwin;
5414 GtkWidget *window;
5415 GtkWidget *usermod_scroll;
5416 GtkWidget *wvbox;
5417 GtkWidget *avbox;
5418 GtkWidget *vbox = 0;
5419 GtkWidget *frame;
5420 GtkWidget *info_frame;
5421 GtkWidget *chk;
5422 GtkWidget *name_entry;
5423 GtkWidget *name_label;
5424 GtkWidget *login_entry;
5425 GtkWidget *login_label;
5426 GtkWidget *pass_entry;
5427 GtkWidget *pass_label;
5428 GtkWidget *info_table;
5429 GtkWidget *btnhbox;
5430 GtkWidget *savebtn;
5431 GtkWidget *delbtn;
5432 GtkWidget *closebtn;
5433 unsigned int i, awi, nframes = 0;
5434 struct useredit_session *ues;
5435
5436 if ((gwin = ghx_window_with_wgi(ghtlc, WG_USEREDIT))) {
5437 gdk_window_show(gwin->widget->window);
5438 return;
5439 }
5440
5441 gwin = window_create(ghtlc, WG_USEREDIT);
5442 window = gwin->widget;
5443
5444 changetitle(ghtlc, window, "User Editor");
5445
5446 ues = xmalloc(sizeof(struct useredit_session));
5447 memset(ues, 0, sizeof(struct useredit_session));
5448 ues->ghtlc = ghtlc;
5449 ues->window = window;
5450 gtk_signal_connect_object(GTK_OBJECT(window), "destroy",
5451 GTK_SIGNAL_FUNC(useredit_destroy), (gpointer)ues);
5452
5453 usermod_scroll = gtk_scrolled_window_new(0, 0);
5454 SCROLLBAR_SPACING(usermod_scroll) = 0;
5455 gtk_widget_set_usize(usermod_scroll, 250, 500);
5456 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(usermod_scroll),
5457 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
5458 wvbox = gtk_vbox_new(0, 0);
5459
5460 savebtn = gtk_button_new_with_label("Save");
5461 gtk_signal_connect_object(GTK_OBJECT(savebtn), "clicked",
5462 GTK_SIGNAL_FUNC(useredit_save), (gpointer)ues);
5463 delbtn = gtk_button_new_with_label("Delete User");
5464 gtk_signal_connect_object(GTK_OBJECT(delbtn), "clicked",
5465 GTK_SIGNAL_FUNC(useredit_delete), (gpointer)ues);
5466 closebtn = gtk_button_new_with_label("Close");
5467 gtk_signal_connect_object(GTK_OBJECT(closebtn), "clicked",
5468 GTK_SIGNAL_FUNC(useredit_close), (gpointer)ues);
5469 btnhbox = gtk_hbox_new(0, 0);
5470 gtk_box_pack_start(GTK_BOX(btnhbox), savebtn, 0, 0, 2);
5471 gtk_box_pack_start(GTK_BOX(btnhbox), delbtn, 0, 0, 2);
5472 gtk_box_pack_start(GTK_BOX(btnhbox), closebtn, 0, 0, 2);
5473 gtk_box_pack_start(GTK_BOX(wvbox), btnhbox, 0, 0, 2);
5474
5475 info_frame = gtk_frame_new("User Info");
5476 info_table = gtk_table_new(3, 2, 0);
5477 gtk_container_add(GTK_CONTAINER(info_frame), info_table);
5478 login_entry = gtk_entry_new();
5479 gtk_signal_connect(GTK_OBJECT(login_entry), "activate",
5480 GTK_SIGNAL_FUNC(useredit_login_activate), ues);
5481 login_label = gtk_label_new("Login:");
5482 name_entry = gtk_entry_new();
5483 gtk_signal_connect(GTK_OBJECT(name_entry), "activate",
5484 GTK_SIGNAL_FUNC(useredit_name_activate), ues);
5485 name_label = gtk_label_new("Name:");
5486 pass_entry = gtk_entry_new();
5487 gtk_entry_set_visibility(GTK_ENTRY(pass_entry), 0);
5488 gtk_signal_connect(GTK_OBJECT(pass_entry), "activate",
5489 GTK_SIGNAL_FUNC(useredit_pass_activate), ues);
5490 pass_label = gtk_label_new("Pass:");
5491 gtk_table_set_row_spacings(GTK_TABLE(info_table), 10);
5492 gtk_table_set_col_spacings(GTK_TABLE(info_table), 5);
5493 gtk_box_pack_start(GTK_BOX(wvbox), info_frame, 0, 0, 2);
5494
5495 avbox = gtk_vbox_new(0, 0);
5496 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(usermod_scroll), avbox);
5497 gtk_container_add(GTK_CONTAINER(window), wvbox);
5498 gtk_box_pack_start(GTK_BOX(wvbox), usermod_scroll, 0, 0, 2);
5499
5500 ues->name_entry = name_entry;
5501 ues->login_entry = login_entry;
5502 ues->pass_entry = pass_entry;
5503
5504 gtk_misc_set_alignment(GTK_MISC(login_label), 0, 0.5);
5505 gtk_misc_set_alignment(GTK_MISC(name_label), 0, 0.5);
5506 gtk_misc_set_alignment(GTK_MISC(pass_label), 0, 0.5);
5507 gtk_label_set_justify(GTK_LABEL(login_label), GTK_JUSTIFY_LEFT);
5508 gtk_label_set_justify(GTK_LABEL(name_label), GTK_JUSTIFY_LEFT);
5509 gtk_label_set_justify(GTK_LABEL(pass_label), GTK_JUSTIFY_LEFT);
5510 gtk_table_attach(GTK_TABLE(info_table), login_label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
5511 gtk_table_attach(GTK_TABLE(info_table), login_entry, 1, 2, 0, 1, GTK_EXPAND|GTK_FILL, 0, 0, 0);
5512 gtk_table_attach(GTK_TABLE(info_table), name_label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
5513 gtk_table_attach(GTK_TABLE(info_table), name_entry, 1, 2, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0);
5514 gtk_table_attach(GTK_TABLE(info_table), pass_label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
5515 gtk_table_attach(GTK_TABLE(info_table), pass_entry, 1, 2, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0);
5516
5517 for (i = 0; i < sizeof(access_names)/sizeof(struct access_name); i++) {
5518 if (access_names[i].bitno == -1) {
5519 nframes++;
5520 frame = gtk_frame_new(access_names[i].name);
5521 vbox = gtk_vbox_new(0, 0);
5522 gtk_container_add(GTK_CONTAINER(frame), vbox);
5523 gtk_box_pack_start(GTK_BOX(avbox), frame, 0, 0, 0);
5524 continue;
5525 }
5526 chk = gtk_check_button_new_with_label(access_names[i].name);
5527 awi = i - nframes;
5528 ues->access_widgets[awi].bitno = access_names[i].bitno;
5529 ues->access_widgets[awi].widget = chk;
5530 gtk_signal_connect(GTK_OBJECT(chk), "clicked",
5531 GTK_SIGNAL_FUNC(useredit_chk_activate), ues);
5532 if (vbox)
5533 gtk_box_pack_start(GTK_BOX(vbox), chk, 0, 0, 0);
5534 }
5535
5536 gtk_widget_show_all(window);
5537 }
5538
5539 static void
open_useredit(gpointer data)5540 open_useredit (gpointer data)
5541 {
5542 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
5543
5544 create_useredit_window(ghtlc);
5545 }
5546
5547 static void
toolbar_disconnect(gpointer data)5548 toolbar_disconnect (gpointer data)
5549 {
5550 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
5551
5552 if (ghtlc->connected)
5553 hx_htlc_close(ghtlc->htlc);
5554 }
5555
5556 static void
toolbar_close(gpointer data)5557 toolbar_close (gpointer data)
5558 {
5559 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
5560
5561 ghtlc_conn_delete(ghtlc);
5562 }
5563
5564 static void
toolbar_destroy(gpointer data)5565 toolbar_destroy (gpointer data)
5566 {
5567 struct ghtlc_conn *ghtlc = (struct ghtlc_conn *)data;
5568
5569 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->connectbtn);
5570 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->disconnectbtn);
5571 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->closebtn);
5572 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->trackerbtn);
5573 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->optionsbtn);
5574 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->newsbtn);
5575 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->filesbtn);
5576 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->usersbtn);
5577 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->chatbtn);
5578 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->tasksbtn);
5579 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->usereditbtn);
5580 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->aboutbtn);
5581 gtk_container_remove(GTK_CONTAINER(ghtlc->toolbar_hbox), ghtlc->quitbtn);
5582 ghtlc->toolbar_hbox = 0;
5583 }
5584
5585 static void
quit_btn(void)5586 quit_btn (void)
5587 {
5588 hx_exit(0);
5589 }
5590
5591 extern void create_about_window (void);
5592
5593 static void
toolbar_buttons_init(struct ghtlc_conn * ghtlc,GtkWidget * window)5594 toolbar_buttons_init (struct ghtlc_conn *ghtlc, GtkWidget *window)
5595 {
5596 GtkWidget *connectbtn;
5597 GtkWidget *disconnectbtn;
5598 GtkWidget *closebtn;
5599 GtkWidget *trackerbtn;
5600 GtkWidget *optionsbtn;
5601 GtkWidget *newsbtn;
5602 GtkWidget *filesbtn;
5603 GtkWidget *usersbtn;
5604 GtkWidget *chatbtn;
5605 GtkWidget *tasksbtn;
5606 GtkWidget *usereditbtn;
5607 GtkWidget *aboutbtn;
5608 GtkWidget *quitbtn;
5609 GtkTooltips *tooltips;
5610
5611 tooltips = gtk_tooltips_new();
5612 connectbtn = icon_button_new(ICON_CONNECT, "Connect", window, tooltips);
5613 gtk_signal_connect_object(GTK_OBJECT(connectbtn), "clicked",
5614 GTK_SIGNAL_FUNC(open_connect), (gpointer)ghtlc);
5615 disconnectbtn = icon_button_new(ICON_KICK, "Disconnect", window, tooltips);
5616 gtk_signal_connect_object(GTK_OBJECT(disconnectbtn), "clicked",
5617 GTK_SIGNAL_FUNC(toolbar_disconnect), (gpointer)ghtlc);
5618 closebtn = icon_button_new(ICON_NUKE, "Close", window, tooltips);
5619 gtk_signal_connect_object(GTK_OBJECT(closebtn), "clicked",
5620 GTK_SIGNAL_FUNC(toolbar_close), (gpointer)ghtlc);
5621 trackerbtn = icon_button_new(ICON_TRACKER, "Tracker", window, tooltips);
5622 gtk_signal_connect_object(GTK_OBJECT(trackerbtn), "clicked",
5623 GTK_SIGNAL_FUNC(open_tracker), (gpointer)ghtlc);
5624 optionsbtn = icon_button_new(ICON_OPTIONS, "Options", window, tooltips);
5625 gtk_signal_connect_object(GTK_OBJECT(optionsbtn), "clicked",
5626 GTK_SIGNAL_FUNC(open_options), (gpointer)ghtlc);
5627 newsbtn = icon_button_new(ICON_NEWS, "News", window, tooltips);
5628 gtk_signal_connect_object(GTK_OBJECT(newsbtn), "clicked",
5629 GTK_SIGNAL_FUNC(open_news), (gpointer)ghtlc);
5630 filesbtn = icon_button_new(ICON_FILE, "Files", window, tooltips);
5631 gtk_signal_connect_object(GTK_OBJECT(filesbtn), "clicked",
5632 GTK_SIGNAL_FUNC(open_files), (gpointer)ghtlc);
5633 usersbtn = icon_button_new(ICON_USER, "Users", window, tooltips);
5634 gtk_signal_connect_object(GTK_OBJECT(usersbtn), "clicked",
5635 GTK_SIGNAL_FUNC(open_users), (gpointer)ghtlc);
5636 chatbtn = icon_button_new(ICON_CHAT, "Chat", window, tooltips);
5637 gtk_signal_connect_object(GTK_OBJECT(chatbtn), "clicked",
5638 GTK_SIGNAL_FUNC(open_chat), (gpointer)ghtlc);
5639 tasksbtn = icon_button_new(ICON_TASKS, "Tasks", window, tooltips);
5640 gtk_signal_connect_object(GTK_OBJECT(tasksbtn), "clicked",
5641 GTK_SIGNAL_FUNC(open_tasks), (gpointer)ghtlc);
5642 usereditbtn = icon_button_new(ICON_YELLOWUSER, "User Edit", window, tooltips);
5643 gtk_signal_connect_object(GTK_OBJECT(usereditbtn), "clicked",
5644 GTK_SIGNAL_FUNC(open_useredit), (gpointer)ghtlc);
5645 aboutbtn = icon_button_new(ICON_INFO, "About", window, tooltips);
5646 gtk_signal_connect_object(GTK_OBJECT(aboutbtn), "clicked",
5647 GTK_SIGNAL_FUNC(create_about_window), 0);
5648 quitbtn = icon_button_new(ICON_STOP, "Quit", window, tooltips);
5649 gtk_signal_connect_object(GTK_OBJECT(quitbtn), "clicked",
5650 GTK_SIGNAL_FUNC(quit_btn), 0);
5651
5652 gtk_object_ref(GTK_OBJECT(connectbtn));
5653 gtk_object_sink(GTK_OBJECT(connectbtn));
5654 gtk_object_ref(GTK_OBJECT(disconnectbtn));
5655 gtk_object_sink(GTK_OBJECT(disconnectbtn));
5656 gtk_object_ref(GTK_OBJECT(closebtn));
5657 gtk_object_sink(GTK_OBJECT(closebtn));
5658 gtk_object_ref(GTK_OBJECT(trackerbtn));
5659 gtk_object_sink(GTK_OBJECT(trackerbtn));
5660 gtk_object_ref(GTK_OBJECT(optionsbtn));
5661 gtk_object_sink(GTK_OBJECT(optionsbtn));
5662 gtk_object_ref(GTK_OBJECT(newsbtn));
5663 gtk_object_sink(GTK_OBJECT(newsbtn));
5664 gtk_object_ref(GTK_OBJECT(filesbtn));
5665 gtk_object_sink(GTK_OBJECT(filesbtn));
5666 gtk_object_ref(GTK_OBJECT(usersbtn));
5667 gtk_object_sink(GTK_OBJECT(usersbtn));
5668 gtk_object_ref(GTK_OBJECT(chatbtn));
5669 gtk_object_sink(GTK_OBJECT(chatbtn));
5670 gtk_object_ref(GTK_OBJECT(tasksbtn));
5671 gtk_object_sink(GTK_OBJECT(tasksbtn));
5672 gtk_object_ref(GTK_OBJECT(usereditbtn));
5673 gtk_object_sink(GTK_OBJECT(usereditbtn));
5674 gtk_object_ref(GTK_OBJECT(aboutbtn));
5675 gtk_object_sink(GTK_OBJECT(aboutbtn));
5676 gtk_object_ref(GTK_OBJECT(quitbtn));
5677 gtk_object_sink(GTK_OBJECT(quitbtn));
5678
5679 ghtlc->connectbtn = connectbtn;
5680 ghtlc->disconnectbtn = disconnectbtn;
5681 ghtlc->closebtn = closebtn;
5682 ghtlc->trackerbtn = trackerbtn;
5683 ghtlc->optionsbtn = optionsbtn;
5684 ghtlc->newsbtn = newsbtn;
5685 ghtlc->filesbtn = filesbtn;
5686 ghtlc->usersbtn = usersbtn;
5687 ghtlc->chatbtn = chatbtn;
5688 ghtlc->tasksbtn = tasksbtn;
5689 ghtlc->usereditbtn = usereditbtn;
5690 ghtlc->aboutbtn = aboutbtn;
5691 ghtlc->quitbtn = quitbtn;
5692 }
5693
5694 static void
create_toolbar_window(struct ghtlc_conn * ghtlc)5695 create_toolbar_window (struct ghtlc_conn *ghtlc)
5696 {
5697 struct ghx_window *gwin;
5698 struct window_geometry *wg;
5699 GtkWidget *window;
5700 GtkWidget *hbox;
5701 GtkWidget *connectbtn;
5702 GtkWidget *disconnectbtn;
5703 GtkWidget *closebtn;
5704 GtkWidget *trackerbtn;
5705 GtkWidget *optionsbtn;
5706 GtkWidget *newsbtn;
5707 GtkWidget *filesbtn;
5708 GtkWidget *usersbtn;
5709 GtkWidget *chatbtn;
5710 GtkWidget *tasksbtn;
5711 GtkWidget *usereditbtn;
5712 GtkWidget *aboutbtn;
5713 GtkWidget *quitbtn;
5714
5715 if ((gwin = ghx_window_with_wgi(ghtlc, WG_TOOLBAR))) {
5716 gdk_window_show(gwin->widget->window);
5717 return;
5718 }
5719
5720 gwin = window_create(ghtlc, WG_TOOLBAR);
5721 wg = gwin->wg;
5722 window = gwin->widget;
5723
5724 gtk_signal_connect_object(GTK_OBJECT(window), "destroy",
5725 GTK_SIGNAL_FUNC(toolbar_destroy), (gpointer)ghtlc);
5726
5727 changetitle(ghtlc, window, "Toolbar");
5728
5729 if (!ghtlc->connectbtn) {
5730 toolbar_buttons_init(ghtlc, window);
5731 keyaccel_attach(ghtlc, window);
5732 }
5733 connectbtn = ghtlc->connectbtn;
5734 disconnectbtn = ghtlc->disconnectbtn;
5735 closebtn = ghtlc->closebtn;
5736 trackerbtn = ghtlc->trackerbtn;
5737 optionsbtn = ghtlc->optionsbtn;
5738 newsbtn = ghtlc->newsbtn;
5739 filesbtn = ghtlc->filesbtn;
5740 usersbtn = ghtlc->usersbtn;
5741 chatbtn = ghtlc->chatbtn;
5742 tasksbtn = ghtlc->tasksbtn;
5743 usereditbtn = ghtlc->usereditbtn;
5744 aboutbtn = ghtlc->aboutbtn;
5745 quitbtn = ghtlc->quitbtn;
5746
5747 hbox = gtk_hbox_new(0, 2);
5748 gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);
5749 gtk_container_add(GTK_CONTAINER(window), hbox);
5750 gtk_box_pack_start(GTK_BOX(hbox), connectbtn, 1, 1, 0);
5751 gtk_box_pack_start(GTK_BOX(hbox), disconnectbtn, 1, 1, 0);
5752 gtk_box_pack_start(GTK_BOX(hbox), closebtn, 1, 1, 0);
5753 gtk_box_pack_start(GTK_BOX(hbox), trackerbtn, 1, 1, 0);
5754 gtk_box_pack_start(GTK_BOX(hbox), optionsbtn, 1, 1, 0);
5755 gtk_box_pack_start(GTK_BOX(hbox), newsbtn, 1, 1, 0);
5756 gtk_box_pack_start(GTK_BOX(hbox), filesbtn, 1, 1, 0);
5757 gtk_box_pack_start(GTK_BOX(hbox), usersbtn, 1, 1, 0);
5758 gtk_box_pack_start(GTK_BOX(hbox), chatbtn, 1, 1, 0);
5759 gtk_box_pack_start(GTK_BOX(hbox), tasksbtn, 1, 1, 0);
5760 gtk_box_pack_start(GTK_BOX(hbox), usereditbtn, 1, 1, 0);
5761 gtk_box_pack_start(GTK_BOX(hbox), aboutbtn, 1, 1, 0);
5762 gtk_box_pack_start(GTK_BOX(hbox), quitbtn, 1, 1, 0);
5763
5764 ghtlc->toolbar_hbox = hbox;
5765
5766 gtk_widget_show_all(window);
5767
5768 gtk_widget_set_sensitive(disconnectbtn, ghtlc->connected);
5769 gtk_widget_set_sensitive(filesbtn, ghtlc->connected);
5770 }
5771
5772 static void
fe_init(void)5773 fe_init (void)
5774 {
5775 struct ghtlc_conn *ghtlc;
5776
5777 ghtlc = ghtlc_conn_with_htlc(&hx_htlc);
5778 create_toolbar_window(ghtlc);
5779 create_chat_window(ghtlc, 0);
5780 }
5781
5782 static void
loop(void)5783 loop (void)
5784 {
5785 fe_init();
5786 gtk_main();
5787 }
5788
5789 static void
set_window_geometry(struct window_geometry * wg,const char * str,const char * varstr)5790 set_window_geometry (struct window_geometry *wg, const char *str, const char *varstr)
5791 {
5792 const char *p, *strp;
5793 char buf[8];
5794 unsigned int i, w, h, x, y, len;
5795
5796 /* "window_geometry[*][*]" */
5797 p = &varstr[16];
5798 if (!strncmp(p, "0]", 2) || !strncmp(p, "default]", 8)) {
5799 wg = default_window_geometry;
5800 } else {
5801 return;
5802 }
5803 p = strchr(p, ']');
5804 if (!p)
5805 return;
5806 p += 2;
5807 if (isdigit(*p)) {
5808 i = strtoul(p, 0, 0);
5809 } else if (!strncmp(p, "chat]", 5)) {
5810 i = WG_CHAT;
5811 } else if (!strncmp(p, "toolbar]", 8)) {
5812 i = WG_TOOLBAR;
5813 } else if (!strncmp(p, "tasks]", 6)) {
5814 i = WG_TASKS;
5815 } else if (!strncmp(p, "news]", 5)) {
5816 i = WG_NEWS;
5817 } else if (!strncmp(p, "post]", 5)) {
5818 i = WG_POST;
5819 } else if (!strncmp(p, "users]", 5)) {
5820 i = WG_USERS;
5821 } else if (!strncmp(p, "tracker]", 8)) {
5822 i = WG_TRACKER;
5823 } else if (!strncmp(p, "options]", 8)) {
5824 i = WG_OPTIONS;
5825 } else if (!strncmp(p, "useredit]", 9)) {
5826 i = WG_USEREDIT;
5827 } else if (!strncmp(p, "connect]", 8)) {
5828 i = WG_CONNECT;
5829 } else if (!strncmp(p, "files]", 6)) {
5830 i = WG_FILES;
5831 } else {
5832 return;
5833 }
5834
5835 w = h = x = y = 0;
5836 for (p = strp = str; ; p++) {
5837 if (*p == 'x' || *p == '+' || *p == '-' || *p == 0) {
5838 len = (unsigned)(p - strp) >= sizeof(buf) ? sizeof(buf)-1 : (unsigned)(p - strp);
5839 if (!len)
5840 break;
5841 memcpy(buf, strp, len);
5842 buf[len] = 0;
5843 if (*p == 'x')
5844 w = strtoul(buf, 0, 0);
5845 else if (*p == 0 || *p == '+' || *p == '-') {
5846 if (!h)
5847 h = strtoul(buf, 0, 0);
5848 else if (!x)
5849 x = strtoul(buf, 0, 0);
5850 else
5851 y = strtoul(buf, 0, 0);
5852 }
5853 strp = p + 1;
5854 }
5855 if (*p == 0)
5856 break;
5857 }
5858
5859 if (!w || !h)
5860 return;
5861 wg[i].width = w;
5862 wg[i].height = h;
5863 wg[i].xpos = x;
5864 wg[i].ypos = y;
5865 }
5866
5867 static void
set_font(char ** fontstr,const char * str,const char * varstr)5868 set_font (char **fontstr, const char *str, const char *varstr)
5869 {
5870 struct ghtlc_conn *ghtlc;
5871 GdkFont *font;
5872
5873 if (varstr) {} /* removes compiler warning */
5874 if (*fontstr) {
5875 if (!strcmp(*fontstr, str))
5876 return;
5877 xfree(*fontstr);
5878 }
5879 *fontstr = xstrdup(str);
5880 font = gdk_font_load(*fontstr);
5881 if (font)
5882 for (ghtlc = ghtlc_conn_list; ghtlc; ghtlc = ghtlc->prev)
5883 change_font(ghtlc, font);
5884 }
5885
5886 static void
init(int argc,char ** argv)5887 init (int argc, char **argv)
5888 {
5889 struct ghtlc_conn *ghtlc;
5890 struct gchat *gchat;
5891 unsigned int i;
5892
5893 variable_add(default_window_geometry, set_window_geometry,
5894 "window_geometry\\[*\\]\\[*\\]");
5895 variable_add(&icon_files, set_icon_files,
5896 "icon_files\\[*\\]");
5897 variable_add(&user_icon_files, set_icon_files,
5898 "user_icon_files\\[*\\]");
5899 default_font = xstrdup("shine");
5900 variable_add(&default_font, set_font,
5901 "chat_font\\[*\\]\\[*\\]");
5902
5903 for (i = 0; i < 1024; i++) {
5904 rinput_tags[i] = -1;
5905 winput_tags[i] = -1;
5906 }
5907
5908 gtk_init(&argc, &argv);
5909
5910 ghtlc = ghtlc_conn_new(&hx_htlc);
5911 gchat = gchat_new(ghtlc, hx_htlc.chat_list);
5912 gchat_create_chat_text(gchat, 1);
5913 }
5914
5915 static void
chat_output(struct gchat * gchat,const char * buf,size_t len)5916 chat_output (struct gchat *gchat, const char *buf, size_t len)
5917 {
5918 GtkAdjustment *adj;
5919 GtkWidget *text;
5920 guint val, scroll;
5921 const char *p, *realtext, *end;
5922 char numstr[4];
5923 GdkColor *bgcolor, *fgcolor;
5924 int i, bold = 0;
5925
5926 text = gchat->chat_output_text;
5927 if (!text)
5928 return;
5929 adj = (GTK_TEXT(text))->vadj;
5930 val = adj->upper - adj->lower - adj->page_size;
5931 scroll = adj->value == val;
5932 gtk_text_freeze(GTK_TEXT(text));
5933 fgcolor = &text->style->fg[GTK_STATE_NORMAL];
5934 bgcolor = &text->style->bg[GTK_STATE_NORMAL];
5935 if (gchat->do_lf)
5936 gtk_text_insert(GTK_TEXT(text), 0, fgcolor, bgcolor, "\n", 1);
5937 realtext = buf;
5938 end = buf + len;
5939 for (p = buf; p < end; p++) {
5940 if (*p == '\033' && *(p+1) == '[') {
5941 gtk_text_insert(GTK_TEXT(text), 0, fgcolor, bgcolor, realtext, p - realtext);
5942 p += 2;
5943 i = 0;
5944 while (i < 2 && ((*p >= '0' && *p <= '7') || *p == ';')) {
5945 if (*p == ';') {
5946 if (i)
5947 bold = numstr[0] == '1' ? 8 : 0;
5948 i = 0;
5949 p++;
5950 continue;
5951 }
5952 numstr[i++] = *p;
5953 p++;
5954 }
5955 realtext = p+1;
5956 if (i) {
5957 numstr[i--] = 0;
5958 i = i == 1 ? numstr[i] - '0' : 0;
5959 i += 8 * (numstr[0] - '0');
5960 if (!i) {
5961 fgcolor = &text->style->fg[GTK_STATE_NORMAL];
5962 bgcolor = &text->style->bg[GTK_STATE_NORMAL];
5963 continue;
5964 }
5965 i &= 0xf;
5966 if (i >= 8)
5967 fgcolor = &colors[i-8+bold];
5968 else
5969 bgcolor = &colors[i+bold];
5970 }
5971 }
5972 }
5973 if (*(p-1) == '\n') {
5974 gtk_text_insert(GTK_TEXT(text), 0, fgcolor, bgcolor, realtext, p - realtext - 1);
5975 gchat->do_lf = 1;
5976 } else {
5977 gtk_text_insert(GTK_TEXT(text), 0, fgcolor, bgcolor, realtext, p - realtext);
5978 gchat->do_lf = 0;
5979 }
5980 gtk_text_thaw(GTK_TEXT(text));
5981 if (scroll)
5982 gtk_adjustment_set_value(adj, adj->upper - adj->lower - adj->page_size);
5983 }
5984
5985 void
hx_printf(struct htlc_conn * htlc,struct hx_chat * chat,const char * fmt,...)5986 hx_printf (struct htlc_conn *htlc, struct hx_chat *chat, const char *fmt, ...)
5987 {
5988 va_list ap;
5989 va_list save;
5990 char autobuf[1024], *buf;
5991 size_t mal_len;
5992 int len;
5993 struct ghtlc_conn *ghtlc;
5994 struct gchat *gchat;
5995
5996 __va_copy(save, ap);
5997 mal_len = sizeof(autobuf);
5998 buf = autobuf;
5999 for (;;) {
6000 va_start(ap, fmt);
6001 len = vsnprintf(buf, mal_len, fmt, ap);
6002 va_end(ap);
6003 if (len != -1)
6004 break;
6005 __va_copy(ap, save);
6006 mal_len <<= 1;
6007 if (buf == autobuf)
6008 buf = xmalloc(mal_len);
6009 else
6010 buf = xrealloc(buf, mal_len);
6011 }
6012
6013 ghtlc = ghtlc_conn_with_htlc(htlc);
6014 if (ghtlc) {
6015 gchat = gchat_with_chat(ghtlc, chat);
6016 if (!gchat)
6017 gchat = gchat_with_cid(ghtlc, 0);
6018 chat_output(gchat, buf, len);
6019 }
6020
6021 if (buf != autobuf)
6022 xfree(buf);
6023 }
6024
6025 void
hx_printf_prefix(struct htlc_conn * htlc,struct hx_chat * chat,const char * prefix,const char * fmt,...)6026 hx_printf_prefix (struct htlc_conn *htlc, struct hx_chat *chat, const char *prefix, const char *fmt, ...)
6027 {
6028 va_list ap;
6029 va_list save;
6030 char autobuf[1024], *buf;
6031 size_t mal_len;
6032 int len;
6033 size_t plen;
6034 struct ghtlc_conn *ghtlc;
6035 struct gchat *gchat;
6036
6037 __va_copy(save, ap);
6038 mal_len = sizeof(autobuf);
6039 buf = autobuf;
6040 if (prefix)
6041 plen = strlen(prefix);
6042 else
6043 plen = 0;
6044 for (;;) {
6045 va_start(ap, fmt);
6046 len = vsnprintf(buf + plen, mal_len - plen, fmt, ap);
6047 va_end(ap);
6048 if (len != -1)
6049 break;
6050 __va_copy(ap, save);
6051 mal_len <<= 1;
6052 if (buf == autobuf)
6053 buf = xmalloc(mal_len);
6054 else
6055 buf = xrealloc(buf, mal_len);
6056 }
6057 memcpy(buf, prefix, plen);
6058
6059 ghtlc = ghtlc_conn_with_htlc(htlc);
6060 if (ghtlc) {
6061 gchat = gchat_with_chat(ghtlc, chat);
6062 if (!gchat)
6063 gchat = gchat_with_cid(ghtlc, 0);
6064 chat_output(gchat, buf, len+plen);
6065 }
6066
6067 if (buf != autobuf)
6068 xfree(buf);
6069 }
6070
6071 static void
output_user_info(struct htlc_conn * htlc,u_int32_t uid,const char * nam,const char * info,u_int16_t len)6072 output_user_info (struct htlc_conn *htlc, u_int32_t uid, const char *nam,
6073 const char *info, u_int16_t len)
6074 {
6075 struct ghtlc_conn *ghtlc;
6076 GtkWidget *info_window;
6077 GtkWidget *info_text;
6078 GtkStyle *style;
6079 char infotitle[64];
6080
6081 ghtlc = ghtlc_conn_with_htlc(htlc);
6082 info_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
6083 gtk_window_set_policy(GTK_WINDOW(info_window), 1, 1, 0);
6084 gtk_widget_set_usize(info_window, 256, 128);
6085
6086 sprintf(infotitle, "User Info: %s (%u)", nam, uid);
6087 gtk_window_set_title(GTK_WINDOW(info_window), infotitle);
6088
6089 info_text = gtk_text_new(0, 0);
6090 if (ghtlc->gchat_list) {
6091 style = gtk_widget_get_style(ghtlc->gchat_list->chat_output_text);
6092 gtk_widget_set_style(info_text, style);
6093 }
6094 gtk_text_insert(GTK_TEXT(info_text), 0, 0, 0, info, len);
6095 gtk_container_add(GTK_CONTAINER(info_window), info_text);
6096
6097 gtk_widget_show_all(info_window);
6098
6099 keyaccel_attach(ghtlc, info_window);
6100 }
6101
6102 void
hx_save(struct htlc_conn * htlc,struct hx_chat * chat,const char * filnam)6103 hx_save (struct htlc_conn *htlc, struct hx_chat *chat, const char *filnam)
6104 {
6105 struct ghtlc_conn *ghtlc;
6106 GtkWidget *text;
6107 char *chars;
6108 int f;
6109 ssize_t r;
6110 size_t pos, len;
6111 char path[MAXPATHLEN];
6112
6113 expand_tilde(path, filnam);
6114 f = open(path, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
6115 if (f < 0) {
6116 hx_printf(htlc, chat, "save: %s: %s\n", path, strerror(errno));
6117 return;
6118 }
6119 pos = 0;
6120 ghtlc = ghtlc_conn_with_htlc(htlc);
6121 if (!ghtlc || !ghtlc->gchat_list)
6122 return;
6123 text = ghtlc->gchat_list->chat_output_text;
6124 len = gtk_text_get_length(GTK_TEXT(text));
6125 chars = gtk_editable_get_chars(GTK_EDITABLE(text), 0, len);
6126 while (len) {
6127 r = write(f, chars + pos, len);
6128 if (r <= 0)
6129 break;
6130 pos += r;
6131 len -= r;
6132 }
6133 fsync(f);
6134 close(f);
6135 g_free(chars);
6136 hx_printf_prefix(htlc, chat, INFOPREFIX, "%d bytes written to %s\n", pos, path);
6137 }
6138
6139 static void
wg_save(void)6140 wg_save (void)
6141 {
6142 struct ghtlc_conn *ghtlc;
6143 struct window_geometry *wg;
6144 char buf[32];
6145 unsigned int i;
6146
6147 ghtlc = ghtlc_conn_with_htlc(&hx_htlc);
6148 if (!ghtlc)
6149 return;
6150 for (i = 0; i < NWG; i++) {
6151 wg = wg_get(i);
6152 snprintf(buf, sizeof(buf), "%ux%u%c%d%c%d", wg->width, wg->height,
6153 (wg->xpos-wg->xoff) < 0 ? '-' : '+', abs(wg->xpos-wg->xoff),
6154 (wg->ypos-wg->yoff) < 0 ? '-' : '+', abs(wg->ypos-wg->yoff));
6155 switch (i) {
6156 case WG_CHAT:
6157 variable_set(ghtlc->htlc, 0, "window_geometry[0][chat]", buf);
6158 break;
6159 case WG_TOOLBAR:
6160 variable_set(ghtlc->htlc, 0, "window_geometry[0][toolbar]", buf);
6161 break;
6162 case WG_USERS:
6163 variable_set(ghtlc->htlc, 0, "window_geometry[0][users]", buf);
6164 break;
6165 case WG_TASKS:
6166 variable_set(ghtlc->htlc, 0, "window_geometry[0][tasks]", buf);
6167 break;
6168 case WG_NEWS:
6169 variable_set(ghtlc->htlc, 0, "window_geometry[0][news]", buf);
6170 break;
6171 case WG_POST:
6172 variable_set(ghtlc->htlc, 0, "window_geometry[0][post]", buf);
6173 break;
6174 case WG_TRACKER:
6175 variable_set(ghtlc->htlc, 0, "window_geometry[0][tracker]", buf);
6176 break;
6177 case WG_OPTIONS:
6178 variable_set(ghtlc->htlc, 0, "window_geometry[0][options]", buf);
6179 break;
6180 case WG_USEREDIT:
6181 variable_set(ghtlc->htlc, 0, "window_geometry[0][useredit]", buf);
6182 break;
6183 case WG_CONNECT:
6184 variable_set(ghtlc->htlc, 0, "window_geometry[0][connect]", buf);
6185 break;
6186 case WG_FILES:
6187 variable_set(ghtlc->htlc, 0, "window_geometry[0][files]", buf);
6188 break;
6189 }
6190 }
6191 hx_savevars();
6192 }
6193
6194 static void
cleanup(void)6195 cleanup (void)
6196 {
6197 wg_save();
6198 gtk_main_quit();
6199 }
6200
6201 static void
status()6202 status ()
6203 {
6204 }
6205
6206 static void
clear(struct htlc_conn * htlc,struct hx_chat * chat)6207 clear (struct htlc_conn *htlc, struct hx_chat *chat)
6208 {
6209 struct ghtlc_conn *ghtlc;
6210 struct gchat *gchat;
6211 GtkWidget *text;
6212
6213 ghtlc = ghtlc_conn_with_htlc(htlc);
6214 if (!ghtlc)
6215 return;
6216 gchat = gchat_with_chat(ghtlc, chat);
6217 if (!gchat || !gchat->chat_output_text)
6218 return;
6219 text = gchat->chat_output_text;
6220 gtk_text_set_point(GTK_TEXT(text), 0);
6221 gtk_text_forward_delete(GTK_TEXT(text), gtk_text_get_length(GTK_TEXT(text)));
6222 }
6223
6224 static void
term_mode_underline()6225 term_mode_underline ()
6226 {
6227 }
6228
6229 static void
term_mode_clear()6230 term_mode_clear ()
6231 {
6232 }
6233
6234 static void
output_chat(struct htlc_conn * htlc,u_int32_t cid,char * chat,u_int16_t chatlen)6235 output_chat (struct htlc_conn *htlc, u_int32_t cid, char *chat, u_int16_t chatlen)
6236 {
6237 struct ghtlc_conn *ghtlc;
6238 struct gchat *gchat;
6239
6240 chat[chatlen] = '\n';
6241 ghtlc = ghtlc_conn_with_htlc(htlc);
6242 gchat = gchat_with_cid(ghtlc, cid);
6243 if (gchat)
6244 chat_output(gchat, chat, chatlen+1);
6245 }
6246
6247 static void
sendmessage(gpointer data)6248 sendmessage (gpointer data)
6249 {
6250 struct msgchat *mc = (struct msgchat *)data;
6251 struct ghtlc_conn *ghtlc = mc->ghtlc;
6252 GtkWidget *msgtext;
6253 GtkWidget *msgwin;
6254 u_int32_t uid;
6255 char *msgbuf;
6256
6257 msgtext = mc->to_text;
6258 msgwin = mc->win;
6259 uid = mc->uid;
6260 msgbuf = gtk_editable_get_chars(GTK_EDITABLE(msgtext), 0, -1);
6261 hx_send_msg(ghtlc->htlc, uid, msgbuf, strlen(msgbuf), 0);
6262 g_free(msgbuf);
6263
6264 gtk_widget_destroy(msgwin);
6265 }
6266
6267 static void
replymessage(gpointer data)6268 replymessage (gpointer data)
6269 {
6270 struct msgchat *mc = (struct msgchat *)data;
6271 GtkWidget *msgtext;
6272 GtkWidget *vscrollbar;
6273 GtkWidget *msgwin;
6274 GtkWidget *vpane;
6275 GtkWidget *thbox;
6276 GtkWidget *btn;
6277
6278 msgwin = mc->win;
6279 vpane = mc->vpane;
6280 btn = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(msgwin), "btn");
6281
6282 msgtext = gtk_text_new(0, 0);
6283 gtk_text_set_editable(GTK_TEXT(msgtext), 1);
6284 mc->to_text = msgtext;
6285 vscrollbar = gtk_vscrollbar_new(GTK_TEXT(msgtext)->vadj);
6286 thbox = gtk_hbox_new(0, 0);
6287 gtk_box_pack_start(GTK_BOX(thbox), msgtext, 1, 1, 0);
6288 gtk_box_pack_start(GTK_BOX(thbox), vscrollbar, 0, 0, 0);
6289 gtk_paned_add2(GTK_PANED(vpane), thbox);
6290 mc->to_hbox = thbox;
6291 gtk_widget_set_usize(mc->from_hbox, 300, 150);
6292 gtk_widget_set_usize(mc->to_hbox, 300, 150);
6293 gtk_widget_show_all(thbox);
6294
6295 gtk_label_set_text(GTK_LABEL(GTK_BIN(btn)->child), "Send and Close");
6296 gtk_widget_set_usize(btn, 110, -2);
6297 gtk_signal_disconnect_by_func(GTK_OBJECT(btn), GTK_SIGNAL_FUNC(replymessage), mc);
6298 gtk_signal_connect_object(GTK_OBJECT(btn), "clicked",
6299 GTK_SIGNAL_FUNC(sendmessage), (gpointer)mc);
6300 gtk_signal_emit_stop_by_name(GTK_OBJECT(btn), "clicked");
6301 if (mc->chat) {
6302 gtk_signal_connect(GTK_OBJECT(msgtext), "key_press_event",
6303 GTK_SIGNAL_FUNC(msgchat_input_key_press), mc);
6304 gtk_signal_connect(GTK_OBJECT(msgtext), "activate",
6305 GTK_SIGNAL_FUNC(msgchat_input_activate), mc);
6306 gtk_widget_set_usize(mc->from_hbox, 300, 180);
6307 gtk_widget_set_usize(mc->to_hbox, 300, 40);
6308 }
6309 }
6310
6311 static void
output_msg(struct htlc_conn * htlc,u_int32_t uid,const char * nam,const char * msgbuf,u_int16_t msglen)6312 output_msg (struct htlc_conn *htlc, u_int32_t uid, const char *nam, const char *msgbuf, u_int16_t msglen)
6313 {
6314 GtkWidget *msgwin;
6315 GtkWidget *thbox;
6316 GtkWidget *vbox1;
6317 GtkWidget *hbox2;
6318 GtkWidget *infobtn;
6319 GtkWidget *chatbtn;
6320 GtkWidget *msgtext;
6321 GtkWidget *vscrollbar;
6322 GtkWidget *hbox1;
6323 GtkWidget *chat_btn;
6324 GtkWidget *replybtn;
6325 GtkWidget *okbtn;
6326 GtkWidget *pixmap;
6327 GtkWidget *vpane;
6328 GtkTooltips *tooltips;
6329 struct ghtlc_conn *ghtlc;
6330 char title[64];
6331 struct hx_chat *chat;
6332 struct hx_user *user;
6333 u_int16_t icon;
6334 struct msgchat *mc;
6335
6336 ghtlc = ghtlc_conn_with_htlc(htlc);
6337 mc = msgchat_with_uid(ghtlc, uid);
6338 if (mc) {
6339 guint len;
6340 msgtext = mc->from_text;
6341 len = gtk_text_get_length(GTK_TEXT(msgtext));
6342 gtk_text_set_point(GTK_TEXT(msgtext), len);
6343 if (len)
6344 gtk_text_insert(GTK_TEXT(msgtext), 0, MSG_FROM_COLOR, 0, "\n", 1);
6345 gtk_text_insert(GTK_TEXT(msgtext), 0, MSG_FROM_COLOR, 0, msgbuf, msglen);
6346 return;
6347 }
6348
6349 if (!uid)
6350 nam = "Server";
6351
6352 snprintf(title, sizeof(title), "%s (%u)", nam, uid);
6353
6354 msgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
6355 gtk_window_set_policy(GTK_WINDOW(msgwin), 1, 1, 0);
6356 gtk_window_set_title(GTK_WINDOW(msgwin), "msgwin");
6357 gtk_window_set_default_size(GTK_WINDOW(msgwin), 300, 300);
6358 gtk_window_set_title(GTK_WINDOW(msgwin), title);
6359
6360 mc = msgchat_new(ghtlc, uid);
6361 mc->ghtlc = ghtlc;
6362 mc->win = msgwin;
6363 strcpy(mc->name, nam);
6364 gtk_signal_connect_object(GTK_OBJECT(msgwin), "destroy",
6365 GTK_SIGNAL_FUNC(destroy_msgchat), (gpointer)mc);
6366
6367 vbox1 = gtk_vbox_new(0, 0);
6368 gtk_container_add(GTK_CONTAINER(msgwin), vbox1);
6369
6370 hbox2 = gtk_hbox_new(0, 5);
6371 gtk_box_pack_start(GTK_BOX(vbox1), hbox2, 0, 0, 0);
6372 gtk_container_set_border_width(GTK_CONTAINER(hbox2), 5);
6373
6374 tooltips = gtk_tooltips_new();
6375
6376 infobtn = icon_button_new(ICON_INFO, "Get Info", msgwin, tooltips);
6377 gtk_signal_connect_object(GTK_OBJECT(infobtn), "clicked",
6378 GTK_SIGNAL_FUNC(msgwin_get_info), (gpointer)mc);
6379 gtk_box_pack_start(GTK_BOX(hbox2), infobtn, 0, 0, 0);
6380
6381 chatbtn = icon_button_new(ICON_CHAT, "Chat", msgwin, tooltips);
6382 gtk_signal_connect_object(GTK_OBJECT(chatbtn), "clicked",
6383 GTK_SIGNAL_FUNC(msgwin_chat), (gpointer)mc);
6384 gtk_box_pack_start(GTK_BOX(hbox2), chatbtn, 0, 0, 0);
6385
6386 chat = hx_chat_with_cid(ghtlc->htlc, 0);
6387 if (chat) {
6388 user = hx_user_with_uid(chat->user_list, uid);
6389 if (user) {
6390 icon = user->icon;
6391 gtk_widget_realize(msgwin);
6392 pixmap = user_pixmap(msgwin, ghtlc->users_font, colorgdk(user->color), icon, nam);
6393 if (pixmap)
6394 gtk_box_pack_start(GTK_BOX(hbox2), pixmap, 0, 1, 0);
6395 }
6396 }
6397
6398 msgtext = gtk_text_new(0, 0);
6399 mc->from_text = msgtext;
6400 vscrollbar = gtk_vscrollbar_new(GTK_TEXT(msgtext)->vadj);
6401 thbox = gtk_hbox_new(0, 0);
6402 gtk_box_pack_start(GTK_BOX(thbox), msgtext, 1, 1, 0);
6403 gtk_box_pack_start(GTK_BOX(thbox), vscrollbar, 0, 0, 0);
6404
6405 vpane = gtk_vpaned_new();
6406 gtk_paned_add1(GTK_PANED(vpane), thbox);
6407 gtk_box_pack_start(GTK_BOX(vbox1), vpane, 1, 1, 0);
6408 mc->vpane = vpane;
6409
6410 mc->from_hbox = thbox;
6411 gtk_widget_set_usize(mc->from_hbox, 300, 220);
6412
6413 hbox1 = gtk_hbox_new(0, 5);
6414 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, 0, 0, 0);
6415 gtk_container_set_border_width(GTK_CONTAINER(hbox1), 5);
6416
6417 chat_btn = gtk_check_button_new_with_label("Chat");
6418 gtk_signal_connect(GTK_OBJECT(chat_btn), "clicked",
6419 GTK_SIGNAL_FUNC(chat_chk_activate), mc);
6420 gtk_box_pack_start(GTK_BOX(hbox1), chat_btn, 0, 0, 0);
6421 gtk_widget_set_usize(chat_btn, 55, -2);
6422 mc->chat_chk = chat_btn;
6423
6424 replybtn = gtk_button_new_with_label("Reply");
6425 gtk_box_pack_end(GTK_BOX(hbox1), replybtn, 0, 0, 0);
6426 gtk_widget_set_usize(replybtn, 55, -2);
6427 gtk_object_set_data(GTK_OBJECT(msgwin), "btn", replybtn);
6428 gtk_signal_connect_object(GTK_OBJECT(replybtn), "clicked",
6429 GTK_SIGNAL_FUNC(replymessage), (gpointer)mc);
6430
6431 okbtn = gtk_button_new_with_label("Dismiss");
6432 gtk_box_pack_end(GTK_BOX(hbox1), okbtn, 0, 0, 0);
6433 gtk_widget_set_usize(okbtn, 55, -2);
6434 gtk_signal_connect_object(GTK_OBJECT(okbtn), "clicked",
6435 GTK_SIGNAL_FUNC(gtk_widget_destroy), (gpointer)msgwin);
6436
6437 gtk_text_insert(GTK_TEXT(msgtext), 0, 0, 0, msgbuf, msglen);
6438
6439 gtk_widget_show_all(msgwin);
6440
6441 keyaccel_attach(ghtlc, msgwin);
6442 }
6443
6444 static void
output_agreement(struct htlc_conn * htlc,const char * agreement,u_int16_t len)6445 output_agreement (struct htlc_conn *htlc, const char *agreement, u_int16_t len)
6446 {
6447 hx_printf_prefix(htlc, 0, INFOPREFIX, "Agreement:\n%.*s\n", len, agreement);
6448 }
6449
6450 static void
output_news_file(struct htlc_conn * htlc,const char * news,u_int16_t len)6451 output_news_file (struct htlc_conn *htlc, const char *news, u_int16_t len)
6452 {
6453 struct ghtlc_conn *ghtlc;
6454 GdkColor *fgcolor, *bgcolor;
6455 GtkWidget *text;
6456
6457 ghtlc = ghtlc_conn_with_htlc(htlc);
6458 if (!ghx_window_with_wgi(ghtlc, WG_NEWS))
6459 return;
6460 open_news(ghtlc);
6461 text = ghtlc->news_text;
6462 fgcolor = &text->style->fg[GTK_STATE_NORMAL];
6463 bgcolor = &text->style->bg[GTK_STATE_NORMAL];
6464 gtk_text_freeze(GTK_TEXT(text));
6465 gtk_text_set_point(GTK_TEXT(text), 0);
6466 gtk_text_forward_delete(GTK_TEXT(text), gtk_text_get_length(GTK_TEXT(text)));
6467 gtk_text_insert(GTK_TEXT(text), 0, fgcolor, bgcolor, news, len);
6468 gtk_text_thaw(GTK_TEXT(text));
6469 }
6470
6471 static void
output_news_post(struct htlc_conn * htlc,const char * news,u_int16_t len)6472 output_news_post (struct htlc_conn *htlc, const char *news, u_int16_t len)
6473 {
6474 struct ghtlc_conn *ghtlc;
6475 GdkColor *fgcolor, *bgcolor;
6476 GtkWidget *text;
6477
6478 ghtlc = ghtlc_conn_with_htlc(htlc);
6479 if (!ghx_window_with_wgi(ghtlc, WG_NEWS))
6480 return;
6481 open_news(ghtlc);
6482 text = ghtlc->news_text;
6483 fgcolor = &text->style->fg[GTK_STATE_NORMAL];
6484 bgcolor = &text->style->bg[GTK_STATE_NORMAL];
6485 gtk_text_set_point(GTK_TEXT(text), 0);
6486 gtk_text_insert(GTK_TEXT(text), 0, fgcolor, bgcolor, news, len);
6487 hx_printf_prefix(htlc, 0, INFOPREFIX, "news posted\n");
6488 }
6489
6490 static void
on_connect(struct htlc_conn * htlc)6491 on_connect (struct htlc_conn *htlc)
6492 {
6493 struct ghtlc_conn *ghtlc;
6494
6495 ghtlc = ghtlc_conn_with_htlc(htlc);
6496 if (!ghtlc)
6497 ghtlc = ghtlc_conn_new(htlc);
6498 if (ghtlc)
6499 ghtlc_conn_connect(ghtlc);
6500
6501 hx_get_user_list(htlc, 0);
6502 if (ghx_window_with_wgi(ghtlc, WG_NEWS))
6503 hx_get_news(htlc);
6504 }
6505
6506 static void
on_disconnect(struct htlc_conn * htlc)6507 on_disconnect (struct htlc_conn *htlc)
6508 {
6509 struct ghtlc_conn *ghtlc;
6510
6511 ghtlc = ghtlc_conn_with_htlc(htlc);
6512 if (ghtlc)
6513 ghtlc_conn_disconnect(ghtlc);
6514 }
6515
6516 struct output_functions hx_gtk_output = {
6517 init,
6518 loop,
6519 cleanup,
6520 status,
6521 clear,
6522 term_mode_underline,
6523 term_mode_clear,
6524 output_chat,
6525 chat_subject,
6526 chat_password,
6527 chat_invite,
6528 chat_delete,
6529 output_msg,
6530 output_agreement,
6531 output_news_file,
6532 output_news_post,
6533 output_user_info,
6534 user_create,
6535 user_delete,
6536 user_change,
6537 user_list,
6538 users_clear,
6539 output_file_list,
6540 file_info,
6541 file_update,
6542 tracker_server_create,
6543 task_update,
6544 on_connect,
6545 on_disconnect
6546 };
6547