Use macros instead of raw numbers for login type
[rofl0r-ixchat.git] / src / fe-gtk / dccgui.c
blob2655af8b51bb50d54d888eb55a454d6c35f225ba
1 /* X-Chat
2 * Copyright (C) 1998-2006 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <time.h>
26 #define WANTSOCKET
27 #define WANTARPA
28 #include "../common/inet.h"
29 #include "fe-gtk.h"
31 #include <gtk/gtkhbbox.h>
32 #include <gtk/gtkhbox.h>
33 #include <gtk/gtklabel.h>
34 #include <gtk/gtkstock.h>
35 #include <gtk/gtkmessagedialog.h>
36 #include <gtk/gtktable.h>
37 #include <gtk/gtktreeview.h>
38 #include <gtk/gtkexpander.h>
39 #include <gtk/gtkliststore.h>
40 #include <gtk/gtktreeselection.h>
41 #include <gtk/gtkcellrendererpixbuf.h>
42 #include <gtk/gtkcellrenderertext.h>
43 #include <gtk/gtkcheckmenuitem.h>
44 #include <gtk/gtkradiobutton.h>
45 #include <gtk/gtkversion.h>
47 #include "../common/xchat.h"
48 #include "../common/xchatc.h"
49 #include "../common/fe.h"
50 #include "../common/util.h"
51 #include "../common/network.h"
52 #include "gtkutil.h"
53 #include "palette.h"
54 #include "maingui.h"
57 enum /* DCC SEND/RECV */
59 COL_TYPE,
60 COL_STATUS,
61 COL_FILE,
62 COL_SIZE,
63 COL_POS,
64 COL_PERC,
65 COL_SPEED,
66 COL_ETA,
67 COL_NICK,
68 COL_DCC, /* struct DCC * */
69 COL_COLOR, /* GdkColor */
70 N_COLUMNS
73 enum /* DCC CHAT */
75 CCOL_STATUS,
76 CCOL_NICK,
77 CCOL_RECV,
78 CCOL_SENT,
79 CCOL_START,
80 CCOL_DCC, /* struct DCC * */
81 CCOL_COLOR, /* GdkColor * */
82 CN_COLUMNS
85 struct dccwindow
87 GtkWidget *window;
89 GtkWidget *list;
90 GtkListStore *store;
91 GtkTreeSelection *sel;
93 GtkWidget *abort_button;
94 GtkWidget *accept_button;
95 GtkWidget *resume_button;
96 GtkWidget *open_button;
98 GtkWidget *file_label;
99 GtkWidget *address_label;
102 struct my_dcc_send
104 struct session *sess;
105 char *nick;
106 int maxcps;
107 int passive;
110 static struct dccwindow dccfwin = {NULL, }; /* file */
111 static struct dccwindow dcccwin = {NULL, }; /* chat */
112 static GdkPixbuf *pix_up = NULL; /* down arrow */
113 static GdkPixbuf *pix_dn = NULL; /* up arrow */
114 static int win_width = 600;
115 static int win_height = 256;
116 static short view_mode; /* 1=download 2=upload 3=both */
117 #define VIEW_DOWNLOAD 1
118 #define VIEW_UPLOAD 2
119 #define VIEW_BOTH 3
121 #define KILOBYTE 1024
122 #define MEGABYTE (KILOBYTE * 1024)
123 #define GIGABYTE (MEGABYTE * 1024)
126 static void
127 proper_unit (DCC_SIZE size, char *buf, int buf_len)
129 if (size <= KILOBYTE)
131 snprintf (buf, buf_len, "%"DCC_SFMT"B", size);
133 else if (size > KILOBYTE && size <= MEGABYTE)
135 snprintf (buf, buf_len, "%"DCC_SFMT"kB", size / KILOBYTE);
137 else
139 snprintf (buf, buf_len, "%.2fMB", (float)size / MEGABYTE);
143 static void
144 dcc_send_filereq_file (struct my_dcc_send *mdc, char *file)
146 if (file)
147 dcc_send (mdc->sess, mdc->nick, file, mdc->maxcps, mdc->passive);
148 else
150 free (mdc->nick);
151 free (mdc);
155 void
156 fe_dcc_send_filereq (struct session *sess, char *nick, int maxcps, int passive)
158 char tbuf[128];
159 struct my_dcc_send *mdc;
161 mdc = malloc (sizeof (*mdc));
162 mdc->sess = sess;
163 mdc->nick = strdup (nick);
164 mdc->maxcps = maxcps;
165 mdc->passive = passive;
167 snprintf (tbuf, sizeof tbuf, _("Send file to %s"), nick);
168 gtkutil_file_req (tbuf, dcc_send_filereq_file, mdc, NULL, FRF_MULTIPLE);
171 static void
172 dcc_prepare_row_chat (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter,
173 gboolean update_only)
175 static char pos[16], siz[16];
176 char *date;
178 date = ctime (&dcc->starttime);
179 date[strlen (date) - 1] = 0; /* remove the \n */
181 proper_unit (dcc->pos, pos, sizeof (pos));
182 proper_unit (dcc->size, siz, sizeof (siz));
184 gtk_list_store_set (store, iter,
185 CCOL_STATUS, _(dccstat[dcc->dccstat].name),
186 CCOL_NICK, dcc->nick,
187 CCOL_RECV, pos,
188 CCOL_SENT, siz,
189 CCOL_START, date,
190 CCOL_DCC, dcc,
191 CCOL_COLOR,
192 dccstat[dcc->dccstat].color == 1 ?
193 NULL :
194 colors + dccstat[dcc->dccstat].color,
195 -1);
198 static void
199 dcc_prepare_row_send (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter,
200 gboolean update_only)
202 static char pos[16], size[16], kbs[14], perc[14], eta[14];
203 int to_go;
204 float per;
206 if (!pix_up)
207 pix_up = gtk_widget_render_icon (dccfwin.window, "gtk-go-up",
208 GTK_ICON_SIZE_MENU, NULL);
210 /* percentage ack'ed */
211 per = (float) ((dcc->ack * 100.00) / dcc->size);
212 proper_unit (dcc->size, size, sizeof (size));
213 proper_unit (dcc->pos, pos, sizeof (pos));
214 snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024);
215 /* proper_unit (dcc->ack, ack, sizeof (ack));*/
216 snprintf (perc, sizeof (perc), "%.0f%%", per);
217 if (dcc->cps != 0)
219 to_go = (dcc->size - dcc->ack) / dcc->cps;
220 snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d",
221 to_go / 3600, (to_go / 60) % 60, to_go % 60);
222 } else
223 strcpy (eta, "--:--:--");
225 if (update_only)
226 gtk_list_store_set (store, iter,
227 COL_STATUS, _(dccstat[dcc->dccstat].name),
228 COL_POS, pos,
229 COL_PERC, perc,
230 COL_SPEED, kbs,
231 COL_ETA, eta,
232 COL_COLOR,
233 dccstat[dcc->dccstat].color == 1 ?
234 NULL :
235 colors + dccstat[dcc->dccstat].color,
236 -1);
237 else
238 gtk_list_store_set (store, iter,
239 COL_TYPE, pix_up,
240 COL_STATUS, _(dccstat[dcc->dccstat].name),
241 COL_FILE, file_part (dcc->file),
242 COL_SIZE, size,
243 COL_POS, pos,
244 COL_PERC, perc,
245 COL_SPEED, kbs,
246 COL_ETA, eta,
247 COL_NICK, dcc->nick,
248 COL_DCC, dcc,
249 COL_COLOR,
250 dccstat[dcc->dccstat].color == 1 ?
251 NULL :
252 colors + dccstat[dcc->dccstat].color,
253 -1);
256 static void
257 dcc_prepare_row_recv (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter,
258 gboolean update_only)
260 static char size[16], pos[16], kbs[16], perc[14], eta[16];
261 float per;
262 int to_go;
264 if (!pix_dn)
265 pix_dn = gtk_widget_render_icon (dccfwin.window, "gtk-go-down",
266 GTK_ICON_SIZE_MENU, NULL);
268 proper_unit (dcc->size, size, sizeof (size));
269 if (dcc->dccstat == STAT_QUEUED)
270 proper_unit (dcc->resumable, pos, sizeof (pos));
271 else
272 proper_unit (dcc->pos, pos, sizeof (pos));
273 snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024);
274 /* percentage recv'ed */
275 per = (float) ((dcc->pos * 100.00) / dcc->size);
276 snprintf (perc, sizeof (perc), "%.0f%%", per);
277 if (dcc->cps != 0)
279 to_go = (dcc->size - dcc->pos) / dcc->cps;
280 snprintf (eta, sizeof (eta), "%.2d:%.2d:%.2d",
281 to_go / 3600, (to_go / 60) % 60, to_go % 60);
282 } else
283 strcpy (eta, "--:--:--");
285 if (update_only)
286 gtk_list_store_set (store, iter,
287 COL_STATUS, _(dccstat[dcc->dccstat].name),
288 COL_POS, pos,
289 COL_PERC, perc,
290 COL_SPEED, kbs,
291 COL_ETA, eta,
292 COL_COLOR,
293 dccstat[dcc->dccstat].color == 1 ?
294 NULL :
295 colors + dccstat[dcc->dccstat].color,
296 -1);
297 else
298 gtk_list_store_set (store, iter,
299 COL_TYPE, pix_dn,
300 COL_STATUS, _(dccstat[dcc->dccstat].name),
301 COL_FILE, file_part (dcc->file),
302 COL_SIZE, size,
303 COL_POS, pos,
304 COL_PERC, perc,
305 COL_SPEED, kbs,
306 COL_ETA, eta,
307 COL_NICK, dcc->nick,
308 COL_DCC, dcc,
309 COL_COLOR,
310 dccstat[dcc->dccstat].color == 1 ?
311 NULL :
312 colors + dccstat[dcc->dccstat].color,
313 -1);
316 static gboolean
317 dcc_find_row (struct DCC *find_dcc, GtkTreeModel *model, GtkTreeIter *iter, int col)
319 struct DCC *dcc;
321 if (gtk_tree_model_get_iter_first (model, iter))
325 gtk_tree_model_get (model, iter, col, &dcc, -1);
326 if (dcc == find_dcc)
327 return TRUE;
329 while (gtk_tree_model_iter_next (model, iter));
332 return FALSE;
335 static void
336 dcc_update_recv (struct DCC *dcc)
338 GtkTreeIter iter;
340 if (!dccfwin.window)
341 return;
343 if (!dcc_find_row (dcc, GTK_TREE_MODEL (dccfwin.store), &iter, COL_DCC))
344 return;
346 dcc_prepare_row_recv (dcc, dccfwin.store, &iter, TRUE);
349 static void
350 dcc_update_chat (struct DCC *dcc)
352 GtkTreeIter iter;
354 if (!dcccwin.window)
355 return;
357 if (!dcc_find_row (dcc, GTK_TREE_MODEL (dcccwin.store), &iter, CCOL_DCC))
358 return;
360 dcc_prepare_row_chat (dcc, dcccwin.store, &iter, TRUE);
363 static void
364 dcc_update_send (struct DCC *dcc)
366 GtkTreeIter iter;
368 if (!dccfwin.window)
369 return;
371 if (!dcc_find_row (dcc, GTK_TREE_MODEL (dccfwin.store), &iter, COL_DCC))
372 return;
374 dcc_prepare_row_send (dcc, dccfwin.store, &iter, TRUE);
377 static void
378 close_dcc_file_window (GtkWindow *win, gpointer data)
380 dccfwin.window = NULL;
383 static void
384 dcc_append (struct DCC *dcc, GtkListStore *store, gboolean prepend)
386 GtkTreeIter iter;
388 if (prepend)
389 gtk_list_store_prepend (store, &iter);
390 else
391 gtk_list_store_append (store, &iter);
393 if (dcc->type == TYPE_RECV)
394 dcc_prepare_row_recv (dcc, store, &iter, FALSE);
395 else
396 dcc_prepare_row_send (dcc, store, &iter, FALSE);
399 static void
400 dcc_fill_window (int flags)
402 struct DCC *dcc;
403 GSList *list;
404 GtkTreeIter iter;
405 int i = 0;
407 gtk_list_store_clear (GTK_LIST_STORE (dccfwin.store));
409 if (flags & VIEW_UPLOAD)
411 list = dcc_list;
412 while (list)
414 dcc = list->data;
415 if (dcc->type == TYPE_SEND)
417 dcc_append (dcc, dccfwin.store, FALSE);
418 i++;
420 list = list->next;
424 if (flags & VIEW_DOWNLOAD)
426 list = dcc_list;
427 while (list)
429 dcc = list->data;
430 if (dcc->type == TYPE_RECV)
432 dcc_append (dcc, dccfwin.store, FALSE);
433 i++;
435 list = list->next;
439 /* if only one entry, select it (so Accept button can work) */
440 if (i == 1)
442 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dccfwin.store), &iter);
443 gtk_tree_selection_select_iter (dccfwin.sel, &iter);
447 /* return list of selected DCCs */
449 static GSList *
450 treeview_get_selected (GtkTreeModel *model, GtkTreeSelection *sel, int column)
452 GtkTreeIter iter;
453 GSList *list = NULL;
454 void *ptr;
456 if (gtk_tree_model_get_iter_first (model, &iter))
460 if (gtk_tree_selection_iter_is_selected (sel, &iter))
462 gtk_tree_model_get (model, &iter, column, &ptr, -1);
463 list = g_slist_prepend (list, ptr);
466 while (gtk_tree_model_iter_next (model, &iter));
469 return g_slist_reverse (list);
472 static GSList *
473 dcc_get_selected (void)
475 return treeview_get_selected (GTK_TREE_MODEL (dccfwin.store),
476 dccfwin.sel, COL_DCC);
479 static void
480 resume_clicked (GtkWidget * wid, gpointer none)
482 struct DCC *dcc;
483 char buf[512];
484 GSList *list;
486 list = dcc_get_selected ();
487 if (!list)
488 return;
489 dcc = list->data;
490 g_slist_free (list);
492 if (dcc->type == TYPE_RECV && !dcc_resume (dcc))
494 switch (dcc->resume_error)
496 case 0: /* unknown error */
497 fe_message (_("That file is not resumable."), FE_MSG_ERROR);
498 break;
499 case 1:
500 snprintf (buf, sizeof (buf),
501 _( "Cannot access file: %s\n"
502 "%s.\n"
503 "Resuming not possible."), dcc->destfile,
504 errorstring (dcc->resume_errno));
505 fe_message (buf, FE_MSG_ERROR);
506 break;
507 case 2:
508 fe_message (_("File in download directory is larger "
509 "than file offered. Resuming not possible."), FE_MSG_ERROR);
510 break;
511 case 3:
512 fe_message (_("Cannot resume the same file from two people."), FE_MSG_ERROR);
517 static void
518 abort_clicked (GtkWidget * wid, gpointer none)
520 struct DCC *dcc;
521 GSList *start, *list;
523 start = list = dcc_get_selected ();
524 for (; list; list = list->next)
526 dcc = list->data;
527 dcc_abort (dcc->serv->front_session, dcc);
529 g_slist_free (start);
532 static void
533 accept_clicked (GtkWidget * wid, gpointer none)
535 struct DCC *dcc;
536 GSList *start, *list;
538 start = list = dcc_get_selected ();
539 for (; list; list = list->next)
541 dcc = list->data;
542 if (dcc->type != TYPE_SEND)
543 dcc_get (dcc);
545 g_slist_free (start);
548 static void
549 browse_folder (char *dir)
551 char buf[512];
553 snprintf (buf, sizeof (buf), "file://%s", dir);
554 fe_open_url (buf);
557 static void
558 browse_dcc_folder (void)
560 if (prefs.dcc_completed_dir[0])
561 browse_folder (prefs.dcc_completed_dir);
562 else
563 browse_folder (prefs.dccdir);
566 static void
567 dcc_details_populate (struct DCC *dcc)
569 char buf[128];
571 if (!dcc)
573 gtk_label_set_text (GTK_LABEL (dccfwin.file_label), NULL);
574 gtk_label_set_text (GTK_LABEL (dccfwin.address_label), NULL);
575 return;
578 /* full path */
579 if (dcc->type == TYPE_RECV)
580 gtk_label_set_text (GTK_LABEL (dccfwin.file_label), dcc->destfile);
581 else
582 gtk_label_set_text (GTK_LABEL (dccfwin.file_label), dcc->file);
584 /* address and port */
585 snprintf (buf, sizeof (buf), "%s : %d", net_ip (dcc->addr), dcc->port);
586 gtk_label_set_text (GTK_LABEL (dccfwin.address_label), buf);
589 static void
590 dcc_row_cb (GtkTreeSelection *sel, gpointer user_data)
592 struct DCC *dcc;
593 GSList *list;
595 list = dcc_get_selected ();
596 if (!list)
598 gtk_widget_set_sensitive (dccfwin.accept_button, FALSE);
599 gtk_widget_set_sensitive (dccfwin.resume_button, FALSE);
600 gtk_widget_set_sensitive (dccfwin.abort_button, FALSE);
601 dcc_details_populate (NULL);
602 return;
605 gtk_widget_set_sensitive (dccfwin.abort_button, TRUE);
607 if (list->next) /* multi selection */
609 gtk_widget_set_sensitive (dccfwin.accept_button, TRUE);
610 gtk_widget_set_sensitive (dccfwin.resume_button, TRUE);
611 dcc_details_populate (list->data);
613 else
615 /* turn OFF/ON appropriate buttons */
616 dcc = list->data;
617 if (dcc->dccstat == STAT_QUEUED && dcc->type == TYPE_RECV)
619 gtk_widget_set_sensitive (dccfwin.accept_button, TRUE);
620 gtk_widget_set_sensitive (dccfwin.resume_button, TRUE);
622 else
624 gtk_widget_set_sensitive (dccfwin.accept_button, FALSE);
625 gtk_widget_set_sensitive (dccfwin.resume_button, FALSE);
628 dcc_details_populate (dcc);
631 g_slist_free (list);
634 static void
635 dcc_dclick_cb (GtkTreeView *view, GtkTreePath *path,
636 GtkTreeViewColumn *column, gpointer data)
638 struct DCC *dcc;
639 GSList *list;
641 list = dcc_get_selected ();
642 if (!list)
643 return;
644 dcc = list->data;
645 g_slist_free (list);
647 if (dcc->type == TYPE_RECV)
649 accept_clicked (0, 0);
650 return;
653 switch (dcc->dccstat)
655 case STAT_FAILED:
656 case STAT_ABORTED:
657 case STAT_DONE:
658 dcc_abort (dcc->serv->front_session, dcc);
662 static void
663 dcc_add_column (GtkWidget *tree, int textcol, int colorcol, char *title, gboolean right_justified)
665 GtkCellRenderer *renderer;
667 renderer = gtk_cell_renderer_text_new ();
668 if (right_justified)
669 g_object_set (G_OBJECT (renderer), "xalign", (float) 1.0, NULL);
670 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree), -1, title, renderer,
671 "text", textcol, "foreground-gdk", colorcol,
672 NULL);
673 gtk_cell_renderer_text_set_fixed_height_from_font (GTK_CELL_RENDERER_TEXT (renderer), 1);
676 static GtkWidget *
677 dcc_detail_label (char *text, GtkWidget *box, int num)
679 GtkWidget *label;
680 char buf[64];
682 label = gtk_label_new (NULL);
683 snprintf (buf, sizeof (buf), "<b>%s</b>", text);
684 gtk_label_set_markup (GTK_LABEL (label), buf);
685 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
686 gtk_table_attach (GTK_TABLE (box), label, 0, 1, 0 + num, 1 + num, GTK_FILL, GTK_FILL, 0, 0);
688 label = gtk_label_new (NULL);
689 gtk_label_set_selectable (GTK_LABEL (label), TRUE);
690 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
691 gtk_table_attach (GTK_TABLE (box), label, 1, 2, 0 + num, 1 + num, GTK_FILL, GTK_FILL, 0, 0);
693 return label;
696 static void
697 dcc_exp_cb (GtkWidget *exp, GtkWidget *box)
699 #if GTK_CHECK_VERSION(2,20,0)
700 if (gtk_widget_get_visible (box))
701 #else
702 if (GTK_WIDGET_VISIBLE (box))
703 #endif
704 gtk_widget_hide (box);
705 else
706 gtk_widget_show (box);
709 static void
710 dcc_toggle (GtkWidget *item, gpointer data)
712 if (GTK_TOGGLE_BUTTON (item)->active)
714 view_mode = GPOINTER_TO_INT (data);
715 dcc_fill_window (GPOINTER_TO_INT (data));
719 static gboolean
720 dcc_configure_cb (GtkWindow *win, GdkEventConfigure *event, gpointer data)
722 /* remember the window size */
723 gtk_window_get_size (win, &win_width, &win_height);
724 return FALSE;
728 fe_dcc_open_recv_win (int passive)
730 GtkWidget *radio, *table, *vbox, *bbox, *view, *exp, *detailbox;
731 GtkListStore *store;
732 GSList *group;
734 if (dccfwin.window)
736 if (!passive)
737 mg_bring_tofront (dccfwin.window);
738 return TRUE;
740 dccfwin.window = mg_create_generic_tab ("Transfers", _("XChat: Uploads and Downloads"),
741 FALSE, TRUE, close_dcc_file_window, NULL,
742 win_width, win_height, &vbox, 0);
743 gtk_container_set_border_width (GTK_CONTAINER (dccfwin.window), 3);
744 gtk_box_set_spacing (GTK_BOX (vbox), 3);
746 store = gtk_list_store_new (N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING,
747 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
748 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
749 G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_COLOR);
750 view = gtkutil_treeview_new (vbox, GTK_TREE_MODEL (store), NULL, -1);
751 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);
752 /* Up/Down Icon column */
753 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), -1, NULL,
754 gtk_cell_renderer_pixbuf_new (),
755 "pixbuf", COL_TYPE, NULL);
756 dcc_add_column (view, COL_STATUS, COL_COLOR, _("Status"), FALSE);
757 dcc_add_column (view, COL_FILE, COL_COLOR, _("File"), FALSE);
758 dcc_add_column (view, COL_SIZE, COL_COLOR, _("Size"), TRUE);
759 dcc_add_column (view, COL_POS, COL_COLOR, _("Position"), TRUE);
760 dcc_add_column (view, COL_PERC, COL_COLOR, "%", TRUE);
761 dcc_add_column (view, COL_SPEED, COL_COLOR, "KB/s", TRUE);
762 dcc_add_column (view, COL_ETA, COL_COLOR, _("ETA"), FALSE);
763 dcc_add_column (view, COL_NICK, COL_COLOR, _("Nick"), FALSE);
765 gtk_tree_view_column_set_expand (gtk_tree_view_get_column (GTK_TREE_VIEW (view), COL_FILE), TRUE);
766 gtk_tree_view_column_set_expand (gtk_tree_view_get_column (GTK_TREE_VIEW (view), COL_NICK), TRUE);
768 dccfwin.list = view;
769 dccfwin.store = store;
770 dccfwin.sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
771 view_mode = VIEW_BOTH;
772 gtk_tree_selection_set_mode (dccfwin.sel, GTK_SELECTION_MULTIPLE);
774 if (!prefs.windows_as_tabs)
775 g_signal_connect (G_OBJECT (dccfwin.window), "configure_event",
776 G_CALLBACK (dcc_configure_cb), 0);
777 g_signal_connect (G_OBJECT (dccfwin.sel), "changed",
778 G_CALLBACK (dcc_row_cb), NULL);
779 /* double click */
780 g_signal_connect (G_OBJECT (view), "row-activated",
781 G_CALLBACK (dcc_dclick_cb), NULL);
783 table = gtk_table_new (1, 3, FALSE);
784 gtk_table_set_col_spacings (GTK_TABLE (table), 16);
785 gtk_box_pack_start (GTK_BOX (vbox), table, 0, 0, 0);
787 radio = gtk_radio_button_new_with_mnemonic (NULL, _("Both"));
788 g_signal_connect (G_OBJECT (radio), "toggled",
789 G_CALLBACK (dcc_toggle), GINT_TO_POINTER (VIEW_BOTH));
790 gtk_table_attach (GTK_TABLE (table), radio, 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
791 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio));
793 radio = gtk_radio_button_new_with_mnemonic (group, _("Uploads"));
794 g_signal_connect (G_OBJECT (radio), "toggled",
795 G_CALLBACK (dcc_toggle), GINT_TO_POINTER (VIEW_UPLOAD));
796 gtk_table_attach (GTK_TABLE (table), radio, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
797 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio));
799 radio = gtk_radio_button_new_with_mnemonic (group, _("Downloads"));
800 g_signal_connect (G_OBJECT (radio), "toggled",
801 G_CALLBACK (dcc_toggle), GINT_TO_POINTER (VIEW_DOWNLOAD));
802 gtk_table_attach (GTK_TABLE (table), radio, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
804 exp = gtk_expander_new (_("Details"));
805 gtk_table_attach (GTK_TABLE (table), exp, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
807 detailbox = gtk_table_new (3, 3, FALSE);
808 gtk_table_set_col_spacings (GTK_TABLE (detailbox), 6);
809 gtk_table_set_row_spacings (GTK_TABLE (detailbox), 2);
810 gtk_container_set_border_width (GTK_CONTAINER (detailbox), 6);
811 g_signal_connect (G_OBJECT (exp), "activate",
812 G_CALLBACK (dcc_exp_cb), detailbox);
813 gtk_table_attach (GTK_TABLE (table), detailbox, 0, 4, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
815 dccfwin.file_label = dcc_detail_label (_("File:"), detailbox, 0);
816 dccfwin.address_label = dcc_detail_label (_("Address:"), detailbox, 1);
818 bbox = gtk_hbutton_box_new ();
819 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
820 gtk_box_pack_end (GTK_BOX (vbox), bbox, FALSE, FALSE, 2);
822 dccfwin.abort_button = gtkutil_button (bbox, GTK_STOCK_CANCEL, 0, abort_clicked, 0, _("Abort"));
823 dccfwin.accept_button = gtkutil_button (bbox, GTK_STOCK_APPLY, 0, accept_clicked, 0, _("Accept"));
824 dccfwin.resume_button = gtkutil_button (bbox, GTK_STOCK_REFRESH, 0, resume_clicked, 0, _("Resume"));
825 dccfwin.open_button = gtkutil_button (bbox, 0, 0, browse_dcc_folder, 0, _("Open Folder..."));
826 gtk_widget_set_sensitive (dccfwin.accept_button, FALSE);
827 gtk_widget_set_sensitive (dccfwin.resume_button, FALSE);
828 gtk_widget_set_sensitive (dccfwin.abort_button, FALSE);
830 dcc_fill_window (3);
831 gtk_widget_show_all (dccfwin.window);
832 gtk_widget_hide (detailbox);
834 return FALSE;
838 fe_dcc_open_send_win (int passive)
840 /* combined send/recv GUI */
841 return fe_dcc_open_recv_win (passive);
845 /* DCC CHAT GUIs BELOW */
847 static GSList *
848 dcc_chat_get_selected (void)
850 return treeview_get_selected (GTK_TREE_MODEL (dcccwin.store),
851 dcccwin.sel, CCOL_DCC);
854 static void
855 accept_chat_clicked (GtkWidget * wid, gpointer none)
857 struct DCC *dcc;
858 GSList *start, *list;
860 start = list = dcc_chat_get_selected ();
861 for (; list; list = list->next)
863 dcc = list->data;
864 dcc_get (dcc);
866 g_slist_free (start);
869 static void
870 abort_chat_clicked (GtkWidget * wid, gpointer none)
872 struct DCC *dcc;
873 GSList *start, *list;
875 start = list = dcc_chat_get_selected ();
876 for (; list; list = list->next)
878 dcc = list->data;
879 dcc_abort (dcc->serv->front_session, dcc);
881 g_slist_free (start);
884 static void
885 dcc_chat_close_cb (void)
887 dcccwin.window = NULL;
890 static void
891 dcc_chat_append (struct DCC *dcc, GtkListStore *store, gboolean prepend)
893 GtkTreeIter iter;
895 if (prepend)
896 gtk_list_store_prepend (store, &iter);
897 else
898 gtk_list_store_append (store, &iter);
900 dcc_prepare_row_chat (dcc, store, &iter, FALSE);
903 static void
904 dcc_chat_fill_win (void)
906 struct DCC *dcc;
907 GSList *list;
908 GtkTreeIter iter;
909 int i = 0;
911 gtk_list_store_clear (GTK_LIST_STORE (dcccwin.store));
913 list = dcc_list;
914 while (list)
916 dcc = list->data;
917 if (dcc->type == TYPE_CHATSEND || dcc->type == TYPE_CHATRECV)
919 dcc_chat_append (dcc, dcccwin.store, FALSE);
920 i++;
922 list = list->next;
925 /* if only one entry, select it (so Accept button can work) */
926 if (i == 1)
928 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dcccwin.store), &iter);
929 gtk_tree_selection_select_iter (dcccwin.sel, &iter);
933 static void
934 dcc_chat_row_cb (GtkTreeSelection *sel, gpointer user_data)
936 struct DCC *dcc;
937 GSList *list;
939 list = dcc_chat_get_selected ();
940 if (!list)
942 gtk_widget_set_sensitive (dcccwin.accept_button, FALSE);
943 gtk_widget_set_sensitive (dcccwin.abort_button, FALSE);
944 return;
947 gtk_widget_set_sensitive (dcccwin.abort_button, TRUE);
949 if (list->next) /* multi selection */
950 gtk_widget_set_sensitive (dcccwin.accept_button, TRUE);
951 else
953 /* turn OFF/ON appropriate buttons */
954 dcc = list->data;
955 if (dcc->dccstat == STAT_QUEUED && dcc->type == TYPE_CHATRECV)
956 gtk_widget_set_sensitive (dcccwin.accept_button, TRUE);
957 else
958 gtk_widget_set_sensitive (dcccwin.accept_button, FALSE);
961 g_slist_free (list);
964 static void
965 dcc_chat_dclick_cb (GtkTreeView *view, GtkTreePath *path,
966 GtkTreeViewColumn *column, gpointer data)
968 accept_chat_clicked (0, 0);
972 fe_dcc_open_chat_win (int passive)
974 GtkWidget *view, *vbox, *bbox;
975 GtkListStore *store;
977 if (dcccwin.window)
979 if (!passive)
980 mg_bring_tofront (dcccwin.window);
981 return TRUE;
984 dcccwin.window =
985 mg_create_generic_tab ("DCCChat", _("XChat: DCC Chat List"),
986 FALSE, TRUE, dcc_chat_close_cb, NULL, 550, 180, &vbox, 0);
987 gtk_container_set_border_width (GTK_CONTAINER (dcccwin.window), 3);
988 gtk_box_set_spacing (GTK_BOX (vbox), 3);
990 store = gtk_list_store_new (CN_COLUMNS, G_TYPE_STRING, G_TYPE_STRING,
991 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
992 G_TYPE_POINTER, GDK_TYPE_COLOR);
993 view = gtkutil_treeview_new (vbox, GTK_TREE_MODEL (store), NULL, -1);
995 dcc_add_column (view, CCOL_STATUS, CCOL_COLOR, _("Status"), FALSE);
996 dcc_add_column (view, CCOL_NICK, CCOL_COLOR, _("Nick"), FALSE);
997 dcc_add_column (view, CCOL_RECV, CCOL_COLOR, _("Recv"), TRUE);
998 dcc_add_column (view, CCOL_SENT, CCOL_COLOR, _("Sent"), TRUE);
999 dcc_add_column (view, CCOL_START, CCOL_COLOR, _("Start Time"), FALSE);
1001 gtk_tree_view_column_set_expand (gtk_tree_view_get_column (GTK_TREE_VIEW (view), 1), TRUE);
1002 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);
1004 dcccwin.list = view;
1005 dcccwin.store = store;
1006 dcccwin.sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1007 gtk_tree_selection_set_mode (dcccwin.sel, GTK_SELECTION_MULTIPLE);
1009 g_signal_connect (G_OBJECT (dcccwin.sel), "changed",
1010 G_CALLBACK (dcc_chat_row_cb), NULL);
1011 /* double click */
1012 g_signal_connect (G_OBJECT (view), "row-activated",
1013 G_CALLBACK (dcc_chat_dclick_cb), NULL);
1015 bbox = gtk_hbutton_box_new ();
1016 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
1017 gtk_box_pack_end (GTK_BOX (vbox), bbox, FALSE, FALSE, 2);
1019 dcccwin.abort_button = gtkutil_button (bbox, GTK_STOCK_CANCEL, 0, abort_chat_clicked, 0, _("Abort"));
1020 dcccwin.accept_button = gtkutil_button (bbox, GTK_STOCK_APPLY, 0, accept_chat_clicked, 0, _("Accept"));
1021 gtk_widget_set_sensitive (dcccwin.accept_button, FALSE);
1022 gtk_widget_set_sensitive (dcccwin.abort_button, FALSE);
1024 dcc_chat_fill_win ();
1025 gtk_widget_show_all (dcccwin.window);
1027 return FALSE;
1030 void
1031 fe_dcc_add (struct DCC *dcc)
1033 switch (dcc->type)
1035 case TYPE_RECV:
1036 if (dccfwin.window && (view_mode & VIEW_DOWNLOAD))
1037 dcc_append (dcc, dccfwin.store, TRUE);
1038 break;
1040 case TYPE_SEND:
1041 if (dccfwin.window && (view_mode & VIEW_UPLOAD))
1042 dcc_append (dcc, dccfwin.store, TRUE);
1043 break;
1045 default: /* chat */
1046 if (dcccwin.window)
1047 dcc_chat_append (dcc, dcccwin.store, TRUE);
1051 void
1052 fe_dcc_update (struct DCC *dcc)
1054 switch (dcc->type)
1056 case TYPE_SEND:
1057 dcc_update_send (dcc);
1058 break;
1060 case TYPE_RECV:
1061 dcc_update_recv (dcc);
1062 break;
1064 default:
1065 dcc_update_chat (dcc);
1069 void
1070 fe_dcc_remove (struct DCC *dcc)
1072 GtkTreeIter iter;
1074 switch (dcc->type)
1076 case TYPE_SEND:
1077 case TYPE_RECV:
1078 if (dccfwin.window)
1080 if (dcc_find_row (dcc, GTK_TREE_MODEL (dccfwin.store), &iter, COL_DCC))
1081 gtk_list_store_remove (dccfwin.store, &iter);
1083 break;
1085 default: /* chat */
1086 if (dcccwin.window)
1088 if (dcc_find_row (dcc, GTK_TREE_MODEL (dcccwin.store), &iter, CCOL_DCC))
1089 gtk_list_store_remove (dcccwin.store, &iter);
1091 break;