summary refs log blame commit diff stats
path: root/src/fe-gtk/about.c
blob: c47fba4fe00a372c0e4cd5005ea38109bddcb70e (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "fe-gtk.h"

#ifdef USE_XLIB
#include <gdk/gdkx.h>
#endif

#include "../common/hexchat.h"
#include "../common/util.h"
#include "../common/hexchatc.h"
#include "palette.h"
#include "pixmaps.h"
#include "gtkutil.h"
#include "about.h"

static GtkWidget *about = 0;

static int
about_close (void)
{
	about = 0;
	return 0;
}

void
menu_about (GtkWidget * wid, gpointer sess)
{
	GtkWidget *vbox;									/* the main vertical box inside the about dialog */
	GtkWidget *hbox_main;								/* horizontal box for containing text on the left and logo on the right */
	GtkWidget *vbox_logo;								/* vertical box for our logo */
	GtkWidget *vbox_text;								/* vertical box for text */
	GtkWidget *label_title;								/* label for the main title */
	GtkWidget *label_subtitle;							/* label for the subtitle */
	GtkWidget *label_info;								/* for the informative text */
	GtkWidget *label_copyright;							/* for copyright notices */
	GdkColor color;										/* color buffer for our nice paintings */
	char buf[512];										/* text buffer for the labels */
	const char *locale = NULL;
	extern GtkWindow *parent_window;					/* maingui.c */

	if (about)
	{
		gtk_window_present (GTK_WINDOW (about));
		return;
	}

	/* general about dialog initialization */
	about = gtk_dialog_new ();
	gtk_window_set_position (GTK_WINDOW (about), GTK_WIN_POS_CENTER_ON_PARENT);
	gtk_window_set_resizable (GTK_WINDOW (about), FALSE);
	gtk_window_set_title (GTK_WINDOW (about), _("About "DISPLAY_NAME));
	if (parent_window)
	{
		gtk_window_set_transient_for (GTK_WINDOW (about), parent_window);
	}
	g_signal_connect (G_OBJECT (about), "destroy", G_CALLBACK (about_close), 0);
	vbox = GTK_DIALOG (about)->vbox;

	/* main horizontal box, text on the left, logo on the right */
	hbox_main = gtk_hbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (hbox_main));

	/* textbox on the left */
	vbox_text = gtk_vbox_new (FALSE, 0);
	gtk_box_pack_start (GTK_BOX (hbox_main), vbox_text, 0, 0, 5);

	/* label for title */
	snprintf (buf, sizeof (buf), "<span size=\"x-large\"><b>"DISPLAY_NAME"</b></span>");
	label_title = gtk_label_new (NULL);
	gtk_misc_set_alignment (GTK_MISC (label_title), 0, 0);
	gtk_box_pack_start (GTK_BOX (vbox_text), label_title, 0, 0, 10);
	color.red   = 0xd7d7;
	color.green = 0x4343;
	color.blue  = 0x0404;
	gtk_widget_modify_fg (label_title, GTK_STATE_NORMAL, &color);
	gtk_label_set_markup (GTK_LABEL (label_title), buf);

	/* label for subtitle */
	snprintf (buf, sizeof (buf), "%s", _("<b>A multiplatform IRC Client</b>"));
	label_subtitle = gtk_label_new (NULL);
	gtk_misc_set_alignment (GTK_MISC (label_subtitle), 0, 0);
	gtk_box_pack_start (GTK_BOX (vbox_text), label_subtitle, 0, 0, 10);
	color.red   = 0x5555;
	color.green = 0x5555;
	color.blue  = 0x5555;
	gtk_widget_modify_fg (label_subtitle, GTK_STATE_NORMAL, &color);
	gtk_label_set_markup (GTK_LABEL (label_subtitle), buf);

	/* label for additional info */
	g_get_charset (&locale);
	(snprintf) (buf, sizeof (buf),
				"<b>Version:</b> "PACKAGE_VERSION"\n"
				"<b>Compiled:</b> "__DATE__"\n"
#ifdef WIN32
				"<b>Portable Mode:</b> %s\n"
				"<b>Build Type:</b> x%d\n"
#endif
				"<b>OS:</b> %s\n"
				"<b>Charset:</b> %s",
#ifdef WIN32
				(portable_mode () ? "Yes" : "No"),
				get_cpu_arch (),
#endif
				get_sys_str (0),
				locale);

	label_info = gtk_label_new (NULL);
	gtk_misc_set_alignment (GTK_MISC (label_info), 0, 0);
	gtk_box_pack_start (GTK_BOX (vbox_text), label_info, 0, 0, 10);
	gtk_label_set_selectable (GTK_LABEL (label_info), TRUE);
	gtk_label_set_markup (GTK_LABEL (label_info), buf);

	/* label for copyright notices */
	snprintf (buf, sizeof (buf), "<small>\302\251 1998-2010 Peter \305\275elezn\303\275\n\302\251 2009-2013 Berke Viktor</small>");
	label_copyright = gtk_label_new (NULL);
	gtk_misc_set_alignment (GTK_MISC (label_copyright), 0, 0);
	gtk_box_pack_start (GTK_BOX (vbox_text), label_copyright, 0, 0, 10);
	gtk_label_set_markup (GTK_LABEL (label_copyright), buf);

	/* imagebox on the right */
	vbox_logo = gtk_vbox_new (FALSE, 0);
	gtk_box_pack_start (GTK_BOX (hbox_main), vbox_logo, 0, 0, 10);

	/* the actual image */
	wid = gtk_image_new_from_pixbuf (pix_hexchat);
	gtk_box_pack_start (GTK_BOX (vbox_logo), wid, 0, 0, 10);

	/* our close button on the bottom right */
	wid = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
	GTK_WIDGET_SET_FLAGS (GTK_WIDGET (wid), GTK_CAN_DEFAULT);
	gtk_box_pack_end (GTK_BOX (GTK_DIALOG (about)->action_area), wid, 0, 0, 0);
	gtk_widget_grab_default (wid);
	g_signal_connect (G_OBJECT (wid), "clicked", G_CALLBACK (gtkutil_destroy), about);

	/* pure white background for the whole about widget*/
	color.red = color.green = color.blue = 0xffff;
	gtk_widget_modify_bg (about, GTK_STATE_NORMAL, &color);

	/* show off! */
	gtk_widget_show_all (about);
}
span class="w"> gint argument_num = 0; gint argument_offset = 0; gint argument_length = 0; int i = 0; gchar *arguments_start; /* find out if the mode currently exists */ arguments_start = g_strstr_len(current->str , -1, " "); if (arguments_start) { modes_length = arguments_start - current->str; } else { modes_length = current->len; /* set this to the end of the modes */ arguments_start = current->str + current->len; } while (mode_pos == -1 && i < modes_length) { if (*current_char == mode) { mode_pos = i; } else { i++; current_char++; } } /* if the mode currently exists and has an arg, need to know where * (including leading space) */ if (mode_pos != -1 && mode_has_arg(serv, '+', mode)) { current_char = current->str; i = 0; while (i <= mode_pos) { if (mode_has_arg(serv, '+', *current_char)) argument_num++; current_char++; i++; } /* check through arguments for where to start */ current_char = arguments_start; i = 0; while (i < argument_num && *current_char != '\0') { if (*current_char == ' ') i++; if (i != argument_num) current_char++; } argument_offset = current_char - current->str; /* how long the existing argument is for this key * important for malloc and strncpy */ if (i == argument_num) { argument_length++; current_char++; while (*current_char != '\0' && *current_char != ' ') { argument_length++; current_char++; } } } /* two cases, adding and removing a mode, handled differently */ if (sign == '+') { if (mode_pos != -1) { /* if it already exists, only need to do something (change) * if there should be a param */ if (mode_has_arg(serv, sign, mode)) { /* leave the old space there */ current = g_string_erase(current, argument_offset+1, argument_length-1); current = g_string_insert(current, argument_offset+1, arg); g_free(sess->current_modes); sess->current_modes = g_string_free(current, FALSE); } } /* mode wasn't there before */ else { /* insert the new mode character */ current = g_string_insert_c(current, modes_length, mode); /* add the argument, with space if there is one */ if (mode_has_arg(serv, sign, mode)) { current = g_string_append_c(current, ' '); current = g_string_append(current, arg); } g_free(sess->current_modes); sess->current_modes = g_string_free(current, FALSE); } } else if (sign == '-' && mode_pos != -1) { /* remove the argument first if it has one*/ if (mode_has_arg(serv, '+', mode)) current = g_string_erase(current, argument_offset, argument_length); /* remove the mode character */ current = g_string_erase(current, mode_pos, 1); g_free(sess->current_modes); sess->current_modes = g_string_free(current, FALSE); } } static char * mode_cat (char *str, char *addition) { int len; if (str) { len = strlen (str) + strlen (addition) + 2; str = g_realloc (str, len); strcat (str, " "); strcat (str, addition); } else { str = g_strdup (addition); } return str; } /* handle one mode, e.g. handle_single_mode (mr,'+','b',"elite","#warez","banneduser",) */ static void handle_single_mode (mode_run *mr, char sign, char mode, char *nick, char *chan, char *arg, int quiet, int is_324, const message_tags_data *tags_data) { session *sess; server *serv = mr->serv; char outbuf[4]; char *cm = serv->chanmodes; gboolean supportsq = FALSE; outbuf[0] = sign; outbuf[1] = 0; outbuf[2] = mode; outbuf[3] = 0; sess = find_channel (serv, chan); if (!sess || !is_channel (serv, chan)) { /* got modes for a chan we're not in! probably nickmode +isw etc */ sess = serv->front_session; goto genmode; } /* is this a nick mode? */ if (strchr (serv->nick_modes, mode)) { /* update the user in the userlist */ userlist_update_mode (sess, /*nickname */ arg, mode, sign); } else { if (!is_324 && !sess->ignore_mode && mode_chanmode_type(serv, mode) >= 1) record_chan_mode (sess, sign, mode, arg); } /* Is q a chanmode on this server? */ if (cm) while (*cm) { if (*cm == ',') break; if (*cm == 'q') supportsq = TRUE; cm++; } switch (sign) { case '+': switch (mode) { case 'k': safe_strcpy (sess->channelkey, arg, sizeof (sess->channelkey)); fe_update_channel_key (sess); fe_update_mode_buttons (sess, mode, sign); if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANSETKEY, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'l': sess->limit = atoi (arg); fe_update_channel_limit (sess); fe_update_mode_buttons (sess, mode, sign); if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANSETLIMIT, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'o': if (!quiet) mr->op = mode_cat (mr->op, arg); return; case 'h': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANHOP, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'v': if (!quiet) mr->voice = mode_cat (mr->voice, arg); return; case 'b': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANBAN, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'e': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANEXEMPT, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'I': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANINVITE, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'q': if (!supportsq) break; /* +q is owner on this server */ if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANQUIET, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; } break; case '-': switch (mode) { case 'k': sess->channelkey[0] = 0; fe_update_channel_key (sess); fe_update_mode_buttons (sess, mode, sign); if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANRMKEY, sess, nick, NULL, NULL, NULL, 0, tags_data->timestamp); return; case 'l': sess->limit = 0; fe_update_channel_limit (sess); fe_update_mode_buttons (sess, mode, sign); if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANRMLIMIT, sess, nick, NULL, NULL, NULL, 0, tags_data->timestamp); return; case 'o': if (!quiet) mr->deop = mode_cat (mr->deop, arg); return; case 'h': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANDEHOP, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'v': if (!quiet) mr->devoice = mode_cat (mr->devoice, arg); return; case 'b': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANUNBAN, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'e': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANRMEXEMPT, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'I': if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANRMINVITE, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; case 'q': if (!supportsq) break; /* -q is owner on this server */ if (!quiet) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANUNQUIET, sess, nick, arg, NULL, NULL, 0, tags_data->timestamp); return; } } fe_update_mode_buttons (sess, mode, sign); genmode: /* Received umode +e. If we're waiting to send JOIN then send now! */ if (mode == 'e' && sign == '+' && !serv->p_cmp (chan, serv->nick)) inbound_identified (serv); if (!quiet) { if (*arg) { char *buf = g_strdup_printf ("%s %s", chan, arg); EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMODEGEN, sess, nick, outbuf, outbuf + 2, buf, 0, tags_data->timestamp); g_free (buf); } else EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMODEGEN, sess, nick, outbuf, outbuf + 2, chan, 0, tags_data->timestamp); } } /* does this mode have an arg? like +b +l +o */ static int mode_has_arg (server * serv, char sign, char mode) { int type; /* if it's a nickmode, it must have an arg */ if (strchr (serv->nick_modes, mode)) return 1; type = mode_chanmode_type (serv, mode); switch (type) { case 0: /* type A */ case 1: /* type B */ return 1; case 2: /* type C */ if (sign == '+') return 1; case 3: /* type D */ return 0; default: return 0; } } /* what type of chanmode is it? -1 for not in chanmode */ static int mode_chanmode_type (server * serv, char mode) { /* see what numeric 005 CHANMODES=xxx said */ char *cm = serv->chanmodes; int type = 0; int found = 0; while (*cm && !found) { if (*cm == ',') { type++; } else if (*cm == mode) { found = 1; } cm++; } if (found) return type; /* not found? -1 */ else return -1; } static void mode_print_grouped (session *sess, char *nick, mode_run *mr, const message_tags_data *tags_data) { /* print all the grouped Op/Deops */ if (mr->op) { EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANOP, sess, nick, mr->op, NULL, NULL, 0, tags_data->timestamp); g_free(mr->op); mr->op = NULL; } if (mr->deop) { EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANDEOP, sess, nick, mr->deop, NULL, NULL, 0, tags_data->timestamp); g_free(mr->deop); mr->deop = NULL; } if (mr->voice) { EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANVOICE, sess, nick, mr->voice, NULL, NULL, 0, tags_data->timestamp); g_free(mr->voice); mr->voice = NULL; } if (mr->devoice) { EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANDEVOICE, sess, nick, mr->devoice, NULL, NULL, 0, tags_data->timestamp); g_free(mr->devoice); mr->devoice = NULL; } } /* handle a MODE or numeric 324 from server */ void handle_mode (server * serv, char *word[], char *word_eol[], char *nick, int numeric_324, const message_tags_data *tags_data) { session *sess; char *chan; char *modes; char *argstr; char sign; int len; size_t arg; size_t i, num_args; int num_modes; size_t offset = 3; int all_modes_have_args = FALSE; int using_front_tab = FALSE; mode_run mr; mr.serv = serv; mr.op = mr.deop = mr.voice = mr.devoice = NULL; /* numeric 324 has everything 1 word later (as opposed to MODE) */ if (numeric_324) offset++; chan = word[offset]; modes = word[offset + 1]; if (*modes == ':') modes++; if (*modes == 0) return; /* beyondirc's blank modes */ sess = find_channel (serv, chan); if (!sess) { sess = serv->front_session; using_front_tab = TRUE; } /* remove trailing space */ len = strlen (word_eol[offset]) - 1; if (word_eol[offset][len] == ' ') word_eol[offset][len] = 0; if (prefs.hex_irc_raw_modes && !numeric_324) EMIT_SIGNAL_TIMESTAMP (XP_TE_RAWMODES, sess, nick, word_eol[offset], 0, 0, 0, tags_data->timestamp); if (numeric_324 && !using_front_tab) { g_free (sess->current_modes); sess->current_modes = g_strdup (word_eol[offset+1]); } sign = *modes; modes++; arg = 1; /* count the number of arguments (e.g. after the -o+v) */ num_args = 0; i = 1; while ((i + offset + 1) < PDIWORDS) { i++; if (!(*word[i + offset])) break; num_args++; } /* count the number of modes (without the -/+ chars */ num_modes = 0; i = 0; while (i < strlen (modes)) { if (modes[i] != '+' && modes[i] != '-') num_modes++; i++; } if (num_args == num_modes) all_modes_have_args = TRUE; while (*modes) { switch (*modes) { case '-': case '+': /* print all the grouped Op/Deops */ mode_print_grouped (sess, nick, &mr, tags_data); sign = *modes; break; default: argstr = ""; if ((all_modes_have_args || mode_has_arg (serv, sign, *modes)) && arg < (num_args + 1)) { arg++; argstr = word[arg + offset]; } handle_single_mode (&mr, sign, *modes, nick, chan, argstr, numeric_324 || prefs.hex_irc_raw_modes, numeric_324, tags_data); } modes++; } /* update the title at the end, now that the mode update is internal now */ if (!using_front_tab) fe_set_title (sess); /* print all the grouped Op/Deops */ mode_print_grouped (sess, nick, &mr, tags_data); } /* handle the 005 numeric */ void inbound_005 (server * serv, char *word[], const message_tags_data *tags_data) { int w; char *pre; w = 4; /* start at the 4th word */ while (w < PDIWORDS && *word[w]) { if (strncmp (word[w], "MODES=", 6) == 0) { serv->modes_per_line = atoi (word[w] + 6); } else if (strncmp (word[w], "CHANTYPES=", 10) == 0) { g_free (serv->chantypes); serv->chantypes = g_strdup (word[w] + 10); } else if (strncmp (word[w], "CHANMODES=", 10) == 0) { g_free (serv->chanmodes); serv->chanmodes = g_strdup (word[w] + 10); } else if (strncmp (word[w], "PREFIX=", 7) == 0) { pre = strchr (word[w] + 7, ')'); if (pre) { pre[0] = 0; /* NULL out the ')' */ g_free (serv->nick_prefixes); g_free (serv->nick_modes); serv->nick_prefixes = g_strdup (pre + 1); serv->nick_modes = g_strdup (word[w] + 8); } else { /* bad! some ircds don't give us the modes. */ /* in this case, we use it only to strip /NAMES */ serv->bad_prefix = TRUE; g_free (serv->bad_nick_prefixes); serv->bad_nick_prefixes = g_strdup (word[w] + 7); } } else if (strncmp (word[w], "WATCH=", 6) == 0) { serv->supports_watch = TRUE; } else if (strncmp (word[w], "MONITOR=", 8) == 0) { serv->supports_monitor = TRUE; } else if (strncmp (word[w], "NETWORK=", 8) == 0) { if (serv->server_session->type == SESS_SERVER) { safe_strcpy (serv->server_session->channel, word[w] + 8, CHANLEN); fe_set_channel (serv->server_session); } } else if (strncmp (word[w], "CASEMAPPING=", 12) == 0) { if (strcmp (word[w] + 12, "ascii") == 0) /* bahamut */ serv->p_cmp = (void *)g_ascii_strcasecmp; } else if (strncmp (word[w], "CHARSET=", 8) == 0) { if (g_ascii_strncasecmp (word[w] + 8, "UTF-8", 5) == 0) { server_set_encoding (serv, "UTF-8"); } } else if (strcmp (word[w], "NAMESX") == 0) { /* 12345678901234567 */ tcp_send_len (serv, "PROTOCTL NAMESX\r\n", 17); } else if (strcmp (word[w], "WHOX") == 0) { serv->have_whox = TRUE; } else if (strcmp (word[w], "EXCEPTS") == 0) { serv->have_except = TRUE; } else if (strcmp (word[w], "INVEX") == 0) { /* supports mode letter +I, default channel invite */ serv->have_invite = TRUE; } else if (strncmp (word[w], "ELIST=", 6) == 0) { /* supports LIST >< min/max user counts? */ if (strchr (word[w] + 6, 'U') || strchr (word[w] + 6, 'u')) serv->use_listargs = TRUE; } w++; } }