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