Mercurial > pidgin
changeset 2289:38e156136896
[gaim-migrate @ 2299]
some irc fixes
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Mon, 17 Sep 2001 05:00:56 +0000 |
parents | b41c88001ab5 |
children | 23c06449ae8e |
files | ChangeLog pixmaps/Makefile.am pixmaps/irc_icon.xpm src/buddy_chat.c src/gaim.h src/protocols/irc/irc.c src/protocols/jabber/jabber.c src/prpl.h src/server.c |
diffstat | 9 files changed, 1043 insertions(+), 1897 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Sun Sep 16 18:30:44 2001 +0000 +++ b/ChangeLog Mon Sep 17 05:00:56 2001 +0000 @@ -17,6 +17,7 @@ * Improved the look of the proxy preferences * event_im_recv and event_im_display_rcvd passed whether the message received was auto-response (see SIGNALS) + * IRC fixes version 0.43 (09/06/2001): * Updated German Translation (thanks Daniel Seifert)
--- a/pixmaps/Makefile.am Sun Sep 16 18:30:44 2001 +0000 +++ b/pixmaps/Makefile.am Mon Sep 17 05:00:56 2001 +0000 @@ -44,6 +44,7 @@ gnomeicu-online.xpm \ group.xpm \ import_small.xpm \ + irc_icon.xpm \ italic.xpm \ join.xpm \ kiss.xpm \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pixmaps/irc_icon.xpm Mon Sep 17 05:00:56 2001 +0000 @@ -0,0 +1,26 @@ +/* XPM */ +static char * irc_icon_xpm[] = { +"12 12 11 1", +" c None", +". c #000000", +"+ c #FF2B2B", +"@ c #FF0000", +"# c #0047E0", +"$ c #0050FF", +"% c #F2FF00", +"& c #F8FF42", +"* c #EFEF00", +"= c #003BB2", +"- c #E80000", +" ", +" ", +" ", +" .. .... .. ", +".+@.###$..%.", +".+@.#..$.&*.", +".+@.##$=.&..", +".+-.##$.&&. ", +".+-.#$..&%..", +".@-.#$$..%*.", +".@-.#.$=..*.", +" .. . .. .. "};
--- a/src/buddy_chat.c Sun Sep 16 18:30:44 2001 +0000 +++ b/src/buddy_chat.c Mon Sep 17 05:00:56 2001 +0000 @@ -107,6 +107,7 @@ { GList *list, *tmp; struct proto_chat_entry *pce; + gboolean focus = TRUE; if (!joinchatgc) return; @@ -149,7 +150,10 @@ gtk_box_pack_start(GTK_BOX(rowbox), entry, TRUE, TRUE, 0); if (pce->def) gtk_entry_set_text(GTK_ENTRY(entry), pce->def); - gtk_widget_grab_focus(entry); + if (focus) { + gtk_widget_grab_focus(entry); + focus = FALSE; + } gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(do_join_chat), NULL); gtk_widget_show(entry); @@ -487,7 +491,10 @@ if (!(flag & WFLAG_WHISPER)) { str = g_strdup(normalize(who)); if (!g_strcasecmp(str, normalize(b->gc->username))) { - debug_printf("%s %s\n", normalize(who), normalize(b->gc->username)); + if (b->makesound && (sound_options & OPT_SOUND_CHAT_YOU_SAY)) + play_sound(CHAT_YOU_SAY); + flag |= WFLAG_SEND; + } else if (!g_strcasecmp(str, normalize(b->gc->displayname))) { if (b->makesound && (sound_options & OPT_SOUND_CHAT_YOU_SAY)) play_sound(CHAT_YOU_SAY); flag |= WFLAG_SEND; @@ -540,14 +547,6 @@ } -void topic_callback(GtkWidget *widget, struct conversation *b) { - char *buf = gtk_entry_get_text(GTK_ENTRY(widget));; - - serv_chat_set_topic(b->gc, b->id, buf); - - g_free(buf); -} - static gint insertname(gconstpointer one, gconstpointer two) { const char *a = (const char *)one; @@ -968,8 +967,7 @@ gtk_widget_show(label); b->topic_text = gtk_entry_new(); - gtk_signal_connect(GTK_OBJECT(b->topic_text), "activate", - GTK_SIGNAL_FUNC(topic_callback), b); + gtk_entry_set_editable(GTK_ENTRY(b->topic_text), FALSE); gtk_box_pack_start(GTK_BOX(hbox), b->topic_text, TRUE, TRUE, 5); gtk_widget_show(b->topic_text); }
--- a/src/gaim.h Sun Sep 16 18:30:44 2001 +0000 +++ b/src/gaim.h Mon Sep 17 05:00:56 2001 +0000 @@ -692,7 +692,6 @@ extern void serv_chat_leave(struct gaim_connection *, int); extern void serv_chat_whisper(struct gaim_connection *, int, char *, char *); extern int serv_chat_send(struct gaim_connection *, int, char *); -extern void serv_chat_set_topic(struct gaim_connection *, int, char *); extern void update_keepalive(struct gaim_connection *, gboolean); /* output from serv */
--- a/src/protocols/irc/irc.c Sun Sep 16 18:30:44 2001 +0000 +++ b/src/protocols/irc/irc.c Mon Sep 17 05:00:56 2001 +0000 @@ -23,17 +23,12 @@ #include <config.h> -#include <netdb.h> #include <unistd.h> #include <errno.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <fcntl.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <time.h> -#include <sys/socket.h> #include <sys/stat.h> #include <ctype.h> #include "multi.h" @@ -41,32 +36,26 @@ #include "gaim.h" #include "proxy.h" -#include "pixmaps/free_icon.xpm" +#include "pixmaps/irc_icon.xpm" #define IRC_BUF_LEN 4096 - +#define PDIWORDS 32 #define USEROPT_SERV 0 #define USEROPT_PORT 1 -static int chat_id = 0; - -struct irc_channel { - int id; - gchar *name; -}; - struct irc_data { int fd; - int inpa; /* used for non-block logins */ - - int timer; + gboolean online; + guint32 timer; - int totalblocks; - int recblocks; + GString *str; + int bc; - GSList *templist; - GList *channels; + char *chantypes; + char *chanmodes; + char *nickmodes; + gboolean six_modes; }; static char *irc_name() @@ -74,536 +63,604 @@ return "IRC"; } -static void irc_get_info(struct gaim_connection *gc, char *who); +static int irc_write(int fd, char *data, int len) +{ + debug_printf("IRC C: %s", data); + return write(fd, data, len); +} + +static struct conversation *irc_find_chat(struct gaim_connection *gc, char *name) +{ + GSList *bcs = gc->buddy_chats; -static GList *irc_chat_info(struct gaim_connection *gc) + while (bcs) { + struct conversation *b = bcs->data; + if (!strcmp(b->name, name)) + return b; + bcs = bcs->next; + } + return NULL; +} + +static struct conversation *irc_find_chat_by_id(struct gaim_connection *gc, int id) +{ + GSList *bcs = gc->buddy_chats; + + while (bcs) { + struct conversation *b = bcs->data; + if (b->id == id) + return b; + bcs = bcs->next; + } + return NULL; +} + +static void process_data_init(char *buf, char *cmd, char *word[], char *eol[], gboolean quotes) { - GList *m = NULL; - struct proto_chat_entry *pce; + int wordcount = 2; + gboolean space = FALSE; + gboolean quote = FALSE; + int j = 0; + + word[1] = cmd; + eol[1] = buf; - pce = g_new0(struct proto_chat_entry, 1); - pce->label = _("Room:"); - m = g_list_append(m, pce); + while (TRUE) { + switch (*cmd) { + case 0: + buf[j] = 0; + for (j = wordcount; j < PDIWORDS; j++) { + word[j] = "\000\000"; + eol[j] = "\000\000"; + } + return; + case '"': + if (!quotes) { + space = FALSE; + buf[j++] = *cmd; + break; + } + quote = !quote; + break; + case ' ': + if (quote) { + space = FALSE; + buf[j++] = *cmd; + break; + } + if (space) + break; + buf[j++] = 0; + word[wordcount] = &buf[j]; + eol[wordcount++] = cmd + 1; + if (wordcount == PDIWORDS - 1) + *cmd-- = 0; + space = TRUE; + break; + default: + space = FALSE; + buf[j++] = *cmd; + } + cmd++; + } +} - return m; +static void handle_005(struct gaim_connection *gc, char *word[], char *word_eol[]) +{ + int w = 4; + struct irc_data *id = gc->proto_data; + + while (w < PDIWORDS && *word[w]) { + if (!strncmp(word[w], "MODES=", 5)) { + if (atoi(word[w] + 6) >= 6) + id->six_modes = TRUE; + } else if (!strncmp(word[w], "CHANTYPES=", 10)) { + g_free(id->chantypes); + id->chantypes = g_strdup(word[w] + 10); + } else if (!strncmp(word[w], "CHANMODES=", 10)) { + g_free(id->chanmodes); + id->chanmodes = g_strdup(word[w] + 10); + } else if (!strncmp(word[w], "PREFIX=", 7)) { + char *pre = strchr(word[w] + 7, ')'); + if (pre) { + *pre = 0; + g_free(id->nickmodes); + id->nickmodes = g_strdup(word[w] + 8); + } + } + w++; + } } -static void irc_join_chat(struct gaim_connection *gc, GList *data) +static char *int_to_col(int c) { - struct irc_data *idata = (struct irc_data *)gc->proto_data; - gchar *buf, *name; - - if (!data) - return; - name = data->data; - - buf = (gchar *) g_malloc(IRC_BUF_LEN + 1); - - g_snprintf(buf, IRC_BUF_LEN, "JOIN %s\n", name); - write(idata->fd, buf, strlen(buf)); - write(idata->fd, buf, strlen(buf)); - - g_free(buf); + switch(c) { + case 1: + return "#ffffff"; + case 2: + return "#000066"; + case 3: + return "#006600"; + case 4: + return "#ff0000"; + case 5: + return "#660000"; + case 6: + return "#660066"; + case 7: + return "#666600"; + case 8: + return "#cccc00"; + case 9: + return "#33cc33"; + case 10: + return "#00acac"; + case 11: + return "#00ccac"; + case 12: + return "#0000ff"; + case 13: + return "#cc00cc"; + case 14: + return "#666666"; + case 15: + return "#00ccac"; + default: + return "#000000"; + } } -static void irc_update_user(struct gaim_connection *gc, char *name, int status) +static GString *decode_html(char *msg) { - struct irc_data *idata = (struct irc_data *)gc->proto_data; - struct irc_channel *u; - GSList *temp = idata->templist; - - /* Loop through our list */ + GString /* oo la la */ *str = g_string_new(""); + char *cur = msg, *end = msg; + gboolean bold = FALSE, underline = FALSE, fg = FALSE, bg = FALSE; + int fore, back; + while (*end) { + switch (*end) { + case 02: /* ^B */ + *end = 0; + str = g_string_append(str, cur); + if (bold) + str = g_string_append(str, "</B>"); + else + str = g_string_append(str, "<B>"); + bold = !bold; + cur = end + 1; + break; + case 03: /* ^C */ + *end++ = 0; + str = g_string_append(str, cur); + fore = back = -1; + if (isdigit(*end)) { + fore = *end++ - '0'; + if (isdigit(*end)) { + fore *= 10; + fore += *end++ - '0'; + } + if (*end == ',' && isdigit(end[1])) { + end++; + back = *end++ - '0'; + if (isdigit(*end)) { + back *= 10; + back += *end++ - '0'; + } + } + } + if (fore == -1) { + if (fg) + str = g_string_append(str, "</FONT>"); + if (bg) + str = g_string_append(str, "</FONT>"); + fg = bg = FALSE; + } else { + fore %= 16; + if (fg) + str = g_string_append(str, "</FONT>"); + if (back != -1) { + if (bg) + str = g_string_append(str, "</FONT>"); + back %= 16; + str = g_string_append(str, "<FONT BACK="); + str = g_string_append(str, int_to_col(back)); + str = g_string_append_c(str, '>'); + bg = TRUE; + } + str = g_string_append(str, "<FONT COLOR="); + str = g_string_append(str, int_to_col(fore)); + str = g_string_append_c(str, '>'); + fg = TRUE; + } + cur = end--; + break; + case 017: /* ^O */ + if (!bold && !underline && !fg && !bg) + break; + *end = 0; + str = g_string_append(str, cur); + if (bold) + str = g_string_append(str, "</B>"); + if (underline) + str = g_string_append(str, "</U>"); + if (fg) + str = g_string_append(str, "</FONT>"); + if (bg) + str = g_string_append(str, "</FONT>"); + bold = underline = fg = bg = FALSE; + cur = end + 1; + break; + case 037: /* ^_ */ + *end = 0; + str = g_string_append(str, cur); + if (underline) + str = g_string_append(str, "</U>"); + else + str = g_string_append(str, "<U>"); + underline = !underline; + cur = end + 1; + break; + } + end++; + } + if (*cur) + str = g_string_append(str, cur); + return str; +} - while (temp) { - u = (struct irc_channel *)temp->data; - if (g_strcasecmp(u->name, name) == 0) { - u->id = status; - return; +static void irc_got_im(struct gaim_connection *gc, char *who, char *what, int flags, time_t t) +{ + GString *str = decode_html(what); + serv_got_im(gc, who, str->str, flags, t); + g_string_free(str, TRUE); +} + +static void irc_got_chat_in(struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t t) +{ + GString *str = decode_html(msg); + serv_got_chat_in(gc, id, who, whisper, str->str, t); + g_string_free(str, TRUE); +} + +static void handle_list(struct gaim_connection *gc, char *list) +{ + struct irc_data *id = gc->proto_data; + GSList *gr; + + id->str = g_string_append_c(id->str, ' '); + id->str = g_string_append(id->str, list); + id->bc--; + if (id->bc) + return; + + g_strdown(id->str->str); + gr = gc->groups; + while (gr) { + GSList *m = ((struct group *)gr->data)->members; + while (m) { + struct buddy *b = m->data; + char *tmp = g_strdup(b->name); + g_strdown(tmp); + if (strstr(id->str->str, tmp)) + serv_got_update(gc, b->name, 1, 0, 0, 0, 0, 0); + else + serv_got_update(gc, b->name, 0, 0, 0, 0, 0, 0); + g_free(tmp); + m = m->next; } - - temp = g_slist_next(temp); + gr = gr->next; } - return; + g_string_free(id->str, TRUE); + id->str = g_string_new(""); } static gboolean irc_request_buddy_update(gpointer data) { struct gaim_connection *gc = data; - struct irc_data *idata = (struct irc_data *)gc->proto_data; - GSList *grp = gc->groups; - GSList *person; - struct group *g; - struct buddy *b; - struct irc_channel *u; + struct irc_data *id = gc->proto_data; + char buf[500]; + int n = g_snprintf(buf, sizeof(buf), "ISON"); - if (idata->templist != NULL) + GSList *gr = gc->groups; + if (!gr || id->bc) return TRUE; - idata->recblocks = 0; - idata->totalblocks = 1; - - /* First, let's check to see if we have anyone on our buddylist */ - if (!grp) { - return TRUE; + while (gr) { + struct group *g = gr->data; + GSList *m = g->members; + while (m) { + struct buddy *b = m->data; + if (n + strlen(b->name) + 2 > sizeof(buf)) { + g_snprintf(buf + n, sizeof(buf) - n, "\r\n"); + irc_write(id->fd, buf, n); + id->bc++; + n = g_snprintf(buf, sizeof(buf), "ISON"); + } + n += g_snprintf(buf + n, sizeof(buf) - n, " %s", b->name); + m = m->next; + } + gr = gr->next; } - - /* Send the first part of our request */ - write(idata->fd, "ISON", 4); - - /* Step through our list of groups */ - while (grp) { - - g = (struct group *)grp->data; - person = g->members; - - while (person) { - b = (struct buddy *)person->data; - - /* We will store our buddy info here. I know, this is cheap - * but hey, its the exact same data structure. Why should we - * bother with making another one */ - - u = g_new0(struct irc_channel, 1); - u->id = 0; /* Assume by default that they're offline */ - u->name = strdup(b->name); - - write(idata->fd, " ", 1); - write(idata->fd, u->name, strlen(u->name)); - idata->templist = g_slist_append(idata->templist, u); - - person = person->next; - } - - grp = g_slist_next(grp); - } - write(idata->fd, "\n", 1); + g_snprintf(buf + n, sizeof(buf) - n, "\r\n"); + irc_write(id->fd, buf, strlen(buf)); + id->bc++; return TRUE; } - -static int irc_send_im(struct gaim_connection *gc, char *who, char *message, int flags) +static void handle_names(struct gaim_connection *gc, char *chan, char *names) { - - struct irc_data *idata = (struct irc_data *)gc->proto_data; - gchar *buf = (gchar *) g_malloc(IRC_BUF_LEN + 1); - - if (who[0] == '@' || who[0] == '+') { - - /* If the user trys to msg an op or a voice from the channel, the convo will try - * to send it to @nick or +nick... needless to say, this is undesirable. - */ - who++; - } - - /* Before we actually send this, we should check to see if they're trying - * To issue a command and handle it properly. */ - - if (message[0] == '/') { - /* I'll change the implementation of this a little later :-) */ - if ((g_strncasecmp(message, "/me ", 4) == 0) && (strlen(message) > 4)) { - /* We have /me!! We have /me!! :-) */ - - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 4); - g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG %s :%cACTION %s%c\n", who, '\001', temp, - '\001'); - g_free(temp); - } else if (!g_strncasecmp(message, "/whois ", 7) && (strlen(message) > 7)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 7); - irc_get_info(gc, temp); - g_free(temp); - - return 0; - } - - } else { - g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG %s :%s\n", who, message); - } - - write(idata->fd, buf, strlen(buf)); - - g_free(buf); - return 0; -} - -static int find_id_by_name(struct gaim_connection *gc, char *name) -{ - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - GList *templist; - struct irc_channel *channel; - - templist = ((struct irc_data *)gc->proto_data)->channels; - - while (templist) { - channel = (struct irc_channel *)templist->data; - - g_snprintf(temp, IRC_BUF_LEN, "#%s", channel->name); - - if (g_strcasecmp(temp, name) == 0) { - g_free(temp); - return channel->id; - } - - templist = templist->next; - } - - g_free(temp); - - /* Return -1 if we have no ID */ - return -1; + struct conversation *c = irc_find_chat(gc, chan); + char **buf, **tmp; + if (!c) return; + if (*names == ':') names++; + buf = g_strsplit(names, " ", -1); + for (tmp = buf; *tmp; tmp++) + add_chat_buddy(c, *tmp); + g_strfreev(buf); } -static struct irc_channel *find_channel_by_name(struct gaim_connection *gc, char *name) +static void handle_topic(struct gaim_connection *gc, char *text) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - GList *templist; - struct irc_channel *channel; - - templist = ((struct irc_data *)gc->proto_data)->channels; - - while (templist) { - channel = (struct irc_channel *)templist->data; - - g_snprintf(temp, IRC_BUF_LEN, "%s", channel->name); + struct conversation *c; + char *po = strchr(text, ' '); - if (g_strcasecmp(temp, name) == 0) { - g_free(temp); - return channel; - } + if (!po) + return; - templist = templist->next; - } + *po = 0; + po += 2; - g_free(temp); - - /* If we found nothing, return nothing :-) */ - return NULL; + if ((c = irc_find_chat(gc, text))) + chat_set_topic(c, NULL, po); } -static struct irc_channel *find_channel_by_id(struct gaim_connection *gc, int id) -{ - struct irc_data *idata = (struct irc_data *)gc->proto_data; - struct irc_channel *channel; - - GList *temp; - - temp = idata->channels; - - while (temp) { - channel = (struct irc_channel *)temp->data; - - if (channel->id == id) { - /* We've found our man */ - return channel; - } - - temp = temp->next; - } - - - /* If we didnt find one, return NULL */ - return NULL; -} - -static struct conversation *find_chat(struct gaim_connection *gc, char *name) +static gboolean mode_has_arg(struct gaim_connection *gc, char sign, char mode) { - GSList *bcs = gc->buddy_chats; - struct conversation *b = NULL; - char *chat = g_strdup(normalize(name)); + struct irc_data *id = gc->proto_data; + char *cm = id->chanmodes; + int type = 0; - while (bcs) { - b = bcs->data; - if (!strcasecmp(normalize(b->name), chat)) - break; - b = NULL; - bcs = bcs->next; - } - - g_free(chat); - return b; -} + if (strchr(id->nickmodes, mode)) + return TRUE; -static void irc_chat_leave(struct gaim_connection *gc, int id); -static int irc_chat_send(struct gaim_connection *gc, int id, char *message) -{ - - struct irc_data *idata = (struct irc_data *)gc->proto_data; - struct irc_channel *channel = NULL; - gchar *buf = (gchar *) g_malloc(IRC_BUF_LEN + 1); - char **kick; - gboolean is_command = FALSE; - /* First lets get our current channel */ - channel = find_channel_by_id(gc, id); - - - if (!channel) { - /* If for some reason we've lost our channel, let's bolt */ - g_free(buf); - return -EINVAL; + while (*cm) { + if (*cm == ',') + type++; + else if (*cm == mode) { + switch (type) { + case 0: + case 1: + return TRUE; + case 2: + if (sign == '+') + return TRUE; + case 3: + return FALSE; + } + } + cm++; } - - /* Before we actually send this, we should check to see if they're trying - * To issue a command and handle it properly. */ - - if (message[0] == '/') { - - if ((g_strncasecmp(message, "/me ", 4) == 0) && (strlen(message) > 4)) { - /* We have /me!! We have /me!! :-) */ - - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 4); - - g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG #%s :%cACTION %s%c\n", channel->name, - '\001', temp, '\001'); - g_free(temp); - } else if ((g_strncasecmp(message, "/op ", 4) == 0) && (strlen(message) > 4)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 4); - - g_snprintf(buf, IRC_BUF_LEN, "MODE #%s +o %s\n", channel->name, temp); - - g_free(temp); - is_command = TRUE; - - } else if ((g_strncasecmp(message, "/deop ", 6) == 0) && (strlen(message) > 6)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 6); - g_snprintf(buf, IRC_BUF_LEN, "MODE #%s -o %s\n", channel->name, temp); - - g_free(temp); - is_command = TRUE; - } - - else if ((g_strncasecmp(message, "/voice ", 7) == 0) && (strlen(message) > 7)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 7); - - g_snprintf(buf, IRC_BUF_LEN, "MODE #%s +v %s\n", channel->name, temp); - - g_free(temp); - is_command = TRUE; - - } else if ((g_strncasecmp(message, "/devoice ", 9) == 0) && (strlen(message) > 9)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 6); - g_snprintf(buf, IRC_BUF_LEN, "MODE #%s -v %s\n", channel->name, temp); + return FALSE; +} - g_free(temp); - is_command = TRUE; - } else if ((g_strncasecmp(message, "/mode ", 6) == 0) && (strlen(message) > 6)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 6); - g_snprintf(buf, IRC_BUF_LEN, "MODE #%s %s\n", channel->name, temp); - g_free(temp); - is_command = TRUE; - } - - else if (!g_strncasecmp(message, "/whois ", 7) && (strlen(message) > 7)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - - strcpy(temp, message + 7); - irc_get_info(gc, temp); - g_free(temp); - is_command = TRUE; - - } - - else if (!g_strncasecmp(message, "/topic ", 7) && (strlen(message) > 7)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 7); +static void irc_user_mode(struct gaim_connection *gc, char *room, char sign, char mode, char *nick) +{ + struct conversation *c = irc_find_chat(gc, room); + GList *r; - /* Send the chat topic change request */ - serv_chat_set_topic(gc, id, temp); - - g_free(temp); - is_command = TRUE; - } - - else if (!g_strncasecmp(message, "/part", 5) && (strlen(message) == 5)) { + if (mode != 'o' && mode != 'v') + return; - /* If I'm not mistaken, the chat_leave command was coded under the - * pretense that it would only occur when someone closed the window. - * For this reason, the /part command will not close the window. Nor - * will the window close when the user is /kicked. I'll let you decide - * the best way to fix it--I'd imagine it'd just be a little line like - * if (convo) close (convo), but I'll let you decide where to put it. - */ - - irc_chat_leave(gc, id); - is_command = TRUE; - return 0; - - - } - - else if (!g_strncasecmp(message, "/join ", 6) && (strlen(message) > 6)) { - - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - GList *m = g_list_append(NULL, temp); + if (!c) + return; - strcpy(temp, message + 6); - - - irc_join_chat(gc, m); - g_free(temp); - g_list_free(m); - is_command = TRUE; - return 0; + r = c->in_room; + while (r) { + gboolean op = FALSE, voice = FALSE; + char *who = r->data; + if (*who == '@') { + op = TRUE; + who++; } - - else if (!g_strncasecmp(message, "/raw ", 5) && (strlen(message) > 5)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 5); - g_snprintf(buf, IRC_BUF_LEN, "%s\r\n", temp); - g_free(temp); - is_command = TRUE; + if (*who == '+') { + voice = TRUE; + who++; } - - else if (!g_strncasecmp(message, "/quote ", 7) && (strlen(message) > 7)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 7); - g_snprintf(buf, IRC_BUF_LEN, "%s\r\n", temp); - g_free(temp); - is_command = TRUE; + if (!strcmp(who, nick)) { + char *tmp, buf[IRC_BUF_LEN]; + if (mode == 'o') { + if (sign == '-') + op = FALSE; + else + op = TRUE; + } + if (mode == 'v') { + if (sign == '-') + voice = FALSE; + else + voice = TRUE; + } + tmp = g_strdup(r->data); + g_snprintf(buf, sizeof(buf), "%s%s%s", op ? "@" : "", + voice ? "+" : "", nick); + rename_chat_buddy(c, tmp, buf); + g_free(tmp); + return; } - - else if (!g_strncasecmp(message, "/kick ", 6) && (strlen(message) > 6)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 6); - kick = g_strsplit(temp, " ", 2); - g_snprintf(buf, IRC_BUF_LEN, "KICK #%s %s :%s\r\n", channel->name, kick[0], - kick[1]); - g_free(temp); - is_command = TRUE; - } - -/* FIXME: I'll go back in and grab this later. -- Rob */ -/* -I THOUGHT THIS WOULD WORK, BUT I WAS WRONG. WOULD SOMEONE KINDLY FIX IT? + r = r->next; + } +} - - else if (!g_strncasecmp(message, "/help", 5)) { - gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); - strcpy(temp, message + 5); - if (temp == "") { - - serv_got_chat_in(gc, id, "gAIM", 0, "Available Commands:"); - serv_got_chat_in(gc, id, "gAIM", 0, " "); - serv_got_chat_in(gc, id, "gAIM", 0, "<b>op voice kick </b>"); - serv_got_chat_in(gc, id, "gAIM", 0, "<b>deop devoice whois</b>"); - serv_got_chat_in(gc, id, "gAIM", 0, "<b>me raw quote</b>"); - serv_got_chat_in(gc, id, "gAIM", 0, "<b>mode</b>"); - } - else { - serv_got_chat_in(gc, id, "gAIM", 0, "Usage: "); - if (temp == "op") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/op <nick></b> - Gives operator status to user."); - else if (temp == "deop") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/deop <nick></b> - Removes operator status from user."); - else if (temp == "me") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/me <action></b> - Sends an action to the channel."); - else if (temp == "mode") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/mode {[+|-}|o|p|s|i|t|n|b|v} [<limit][<nick>][<ban mask]</b> - Changes channel and user modes."); - else if (temp == "voice") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/voice <nick></b> - Gives voice status to user."); - else if (temp == "devoice") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/devoice <nick></b> - Removes voice status from user."); - else if (temp == "raw") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/raw <text></b> - Sends raw text to the server."); - else if (temp == "kick") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/kick [<comment>]</b> - Kicks a user out of the channel."); - else if (temp == "whois") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/whois <nick></b> - Gets information about user."); - else if (temp == "quote") - serv_got_chat_in(gc, id, "gAIM", 0, "<b>/raw <text></b> - Sends raw text to the server."); - else - serv_got_chat_in(gc, id, "gAIM", 0, "No such command."); - } - - g_free(temp); - is_command = TRUE; - } -*/ +static void handle_mode(struct gaim_connection *gc, char *word[], char *word_eol[], gboolean n324) +{ + struct irc_data *id = gc->proto_data; + int offset = n324 ? 4 : 3; + char *chan = word[offset]; + struct conversation *c = irc_find_chat(gc, chan); + char *modes = word[offset + 1]; + int len = strlen(word_eol[offset]) - 1; + char sign = *modes++; + int arg = 1; + char *argstr; + + if (!c) + return; + + if (word_eol[offset][len] == ' ') + word_eol[offset][len] = 0; - } - - else { - g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG #%s :%s\n", channel->name, message); - + while (TRUE) { + switch (*modes) { + case 0: + return; + case '+': + case '-': + sign = *modes; + break; + default: + if (mode_has_arg(gc, sign, *modes)) + argstr = word[++arg + offset]; + else + argstr = ""; + if (strchr(id->nickmodes, *modes)) + irc_user_mode(gc, chan, sign, *modes, argstr); + } + modes++; } - - - write(idata->fd, buf, strlen(buf)); - - /* Since AIM expects us to receive the message we send, we gotta fake it */ - if (is_command == FALSE) - serv_got_chat_in(gc, id, gc->username, 0, message, time((time_t) NULL)); - - g_free(buf); - - return 0; } -static struct conversation *find_conversation_by_id(struct gaim_connection *gc, int id) +static void process_numeric(struct gaim_connection *gc, char *word[], char *word_eol[]) { - GSList *bc = gc->buddy_chats; - struct conversation *b = NULL; + struct irc_data *id = gc->proto_data; + char *text = word_eol[3]; + int n = atoi(word[2]); + + if (!g_strncasecmp(gc->displayname, text, strlen(gc->displayname))) + text += strlen(gc->displayname) + 1; + if (*text == ':') + text++; - while (bc) { - b = (struct conversation *)bc->data; - if (id == b->id) { - break; - } - bc = bc->next; - b = NULL; + switch (n) { + case 4: + if (!strncmp(word[5], "u2.10", 5)) + id->six_modes = TRUE; + else + id->six_modes = FALSE; + break; + case 5: + handle_005(gc, word, word_eol); + break; + case 301: + irc_got_im(gc, word[4], word[5], IM_FLAG_AWAY, time(NULL)); + break; + case 303: + handle_list(gc, &word_eol[4][1]); + break; + case 324: + handle_mode(gc, word, word_eol, TRUE); + break; + case 332: + handle_topic(gc, text); + break; + case 353: + handle_names(gc, word[5], word_eol[6]); + break; + case 376: + irc_request_buddy_update(gc); + break; } +} - if (!b) { - return NULL; - } - - return b; +static gboolean is_channel(struct gaim_connection *gc, char *name) +{ + struct irc_data *id = gc->proto_data; + if (strchr(id->chantypes, *name)) + return TRUE; + return FALSE; } -static struct conversation *find_conversation_by_name(struct gaim_connection *gc, char *name) +static void irc_rem_chat_bud(struct gaim_connection *gc, char *nick) { - GSList *bc = gc->buddy_chats; - struct conversation *b = NULL; + GSList *bcs = gc->buddy_chats; - while (bc) { - b = (struct conversation *)bc->data; + while (bcs) { + struct conversation *b = bcs->data; - if (g_strcasecmp(name, b->name) == 0) { - break; + GList *r = b->in_room; + while (r) { + char *who = r->data; + if (*who == '@') + who++; + if (*who == '+') + who++; + if (!g_strcasecmp(who, nick)) { + char *tmp = g_strdup(r->data); + remove_chat_buddy(b, r->data); + g_free(tmp); + break; + } + r = r->next; } - bc = bc->next; - b = NULL; + bcs = bcs->next; } - - if (!b) { - return NULL; - } - - return b; } +static void irc_change_name(struct gaim_connection *gc, char *old, char *new) +{ + GSList *bcs = gc->buddy_chats; + char buf[IRC_BUF_LEN]; + int n = 0; + while (bcs) { + struct conversation *b = bcs->data; + + GList *r = b->in_room; + while (r) { + char *who = r->data; + if (*who == '@') + buf[n++] = *who++; + if (*who == '+') + buf[n++] = *who++; + g_snprintf(buf + n, sizeof(buf) - n, "%s", new); + if (!g_strcasecmp(who, old)) { + char *tmp = g_strdup(r->data); + rename_chat_buddy(b, tmp, buf); + r = b->in_room; + g_free(tmp); + } else + r = r->next; + } + bcs = bcs->next; + } +} static void irc_callback(gpointer data, gint source, GaimInputCondition condition) { struct gaim_connection *gc = data; + struct irc_data *idata = gc->proto_data; int i = 0; - gchar buf[4096]; - gchar **buf2; - struct irc_data *idata; + gchar d[IRC_BUF_LEN], *buf = d; + gchar outbuf[IRC_BUF_LEN]; + char *word[PDIWORDS], *word_eol[PDIWORDS]; + char pdibuf[522]; + char *ex, ip[128], nick[128]; + char *cmd; - idata = (struct irc_data *)gc->proto_data; + if (!idata->online) { + /* Now lets sign ourselves on */ + account_online(gc); + serv_finish_login(gc); + if (bud_list_cache_exists(gc)) + do_import(NULL, gc); + + /* we don't call this now because otherwise some IRC servers might not like us */ + idata->timer = g_timeout_add(20000, irc_request_buddy_update, gc); + idata->online = TRUE; + } do { - if (read(idata->fd, buf + i, 1) < 0) { + if (read(idata->fd, buf + i, 1) <= 0) { hide_login_progress(gc, "Read error"); signoff(gc); return; @@ -612,1304 +669,167 @@ buf[--i] = '\0'; g_strchomp(buf); - g_print("%s\n", buf); + debug_printf("IRC S: %s\n", buf); /* Check for errors */ - if (((strstr(buf, "ERROR :") && (!strstr(buf, "PRIVMSG ")) && - (!strstr(buf, "NOTICE ")) && (strlen(buf) > 7)))) { - - /* - * The ERROR command is for use by servers when reporting a serious or - * fatal error to its operators. It may also be sent from one server to - * another but must not be accepted from any normal unknown clients. - * - * An ERROR message is for use for reporting errors which occur with a - * server-to-server link only. An ERROR message is sent to the server - * at the other end (which sends it to all of its connected operators) - * and to all operators currently connected. It is not to be passed - * onto any other servers by a server if it is received from a server. - * - * When a server sends a received ERROR message to its operators, the - * message should be encapsulated inside a NOTICE message, indicating - * that the client was not responsible for the error. - * - * - * Basically, ignore this. - * - gchar *u_errormsg; - - * Let's get our error message * - u_errormsg = g_strdup(buf + 7); - - * We got our error message. Now, let's reaise an - * error dialog * - - do_error_dialog(u_errormsg, "Gaim: IRC Error"); - - * And our necessary garbage collection * - g_free(u_errormsg); - return; - - */ - } - - /* This should be a whois response. I only care about the first (311) one. I might do - * the other's later. They're boring. */ - - if (((strstr(buf, " 311 ")) && (!strstr(buf, "PRIVMSG")) && (!strstr(buf, "NOTICE")))) { - char **res; - - res = g_strsplit(buf, " ", 7); - - if (!strcmp(res[1], "311")) { - char buf[8192]; - - g_snprintf(buf, 4096, "<b>Nick:</b> %s<br>" - "<b>Host:</b> %s@%s<br>" - "<b>Name:</b> %s<br>", res[3], res[4], res[5], res[7] + 1); - - g_show_info_text(buf, NULL); + if (*buf != ':') { + if (!strncmp(buf, "NOTICE ", 7)) + buf += 7; + if (!strncmp(buf, "PING ", 5)) { + g_snprintf(outbuf, sizeof(outbuf), "PONG %s\r\n", buf + 5); + if (irc_write(idata->fd, outbuf, strlen(outbuf)) < 0) { + hide_login_progress(gc, _("Unable to write")); + signoff(gc); + } + return; } - - g_strfreev(res); - return; - } - - /* Autoresponse to an away message */ - if (((strstr(buf, " 301 ")) && (!strstr(buf, "PRIVMSG")) && (!strstr(buf, "NOTICE")))) { - char **res; - - res = g_strsplit(buf, " ", 5); - - if (!strcmp(res[1], "301")) - serv_got_im(gc, res[3], res[4] + 1, IM_FLAG_AWAY, time((time_t) NULL)); - - g_strfreev(res); + /* XXX doesn't handle ERROR */ return; } - /* Parse the list of names that we receive when we first sign on to - * a channel */ - - if (((strstr(buf, " 353 ")) && (!strstr(buf, "PRIVMSG")) && (!strstr(buf, "NOTICE")))) { - gchar u_host[255]; - gchar u_command[32]; - gchar u_channel[128]; - gchar u_names[IRC_BUF_LEN + 1]; - struct conversation *convo = NULL; - int j; - - for (j = 0, i = 0; buf[i] != ' '; j++, i++) { - u_host[j] = buf[i]; - } - - u_host[j] = '\0'; - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_command[j] = buf[i]; - } - - u_command[j] = '\0'; - i++; - - for (j = 0; buf[i] != '#'; j++, i++) { - } - i++; - - for (j = 0; buf[i] != ':'; j++, i++) { - u_channel[j] = buf[i]; - } - - u_channel[j - 1] = '\0'; - i++; - - while ((buf[i] == ' ') || (buf[i] == ':')) { - i++; - } - - strcpy(u_names, buf + i); - - buf2 = g_strsplit(u_names, " ", 0); - - /* Let's get our conversation window */ - convo = find_conversation_by_name(gc, u_channel); - - if (!convo) { - return; - } - - /* Now that we've parsed the hell out of this big - * mess, let's try to split up the names properly */ - - for (i = 0; buf2[i] != NULL; i++) - add_chat_buddy(convo, buf2[i]); - - /* And free our pointers */ - g_strfreev(buf2); - - return; - - } - - /* Receive a list of users that are currently online */ - - if (((strstr(buf, " 303 ")) && (!strstr(buf, "PRIVMSG")) && (!strstr(buf, "NOTICE")))) { - gchar u_host[255]; - gchar u_command[32]; - gchar u_names[IRC_BUF_LEN + 1]; - int j; - - for (j = 0, i = 0; buf[i] != ' '; j++, i++) { - u_host[j] = buf[i]; - } - - u_host[j] = '\0'; - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_command[j] = buf[i]; - } - - u_command[j] = '\0'; - i++; - - for (j = 0; buf[i] != ':'; j++, i++) { - /* My Nick */ - } - i++; - - strcpy(u_names, buf + i); - - buf2 = g_strsplit(u_names, " ", 0); - - /* Now that we've parsed the hell out of this big - * mess, let's try to split up the names properly */ - - for (i = 0; buf2[i] != NULL; i++) { - /* If we have a name here then our buddy is online. We should - * update our temporary gslist accordingly. When we achieve our maximum - * list of names then we should force an update */ - - irc_update_user(gc, buf2[i], 1); - } - - /* Increase our received blocks counter */ - idata->recblocks++; - - /* If we have our total number of blocks */ - if (idata->recblocks == idata->totalblocks) { - GSList *temp; - struct irc_channel *u; - - /* Let's grab our list of people and bring them all on or off line */ - temp = idata->templist; - - /* Loop */ - while (temp) { - - u = temp->data; - - /* Tell Gaim to bring the person on or off line */ - serv_got_update(gc, u->name, u->id, 0, 0, 0, 0, 0); - - /* Grab the next entry */ - temp = g_slist_next(temp); - } - - /* And now, let's delete all of our entries */ - temp = idata->templist; - while (temp) { - u = temp->data; - g_free(u->name); - temp = g_slist_remove(temp, u); - } + buf++; - /* Reset our list */ - idata->totalblocks = 0; - idata->recblocks = 0; - - idata->templist = NULL; - - return; - } - - /* And free our pointers */ - g_strfreev(buf2); - - return; - - } - - - if ((strstr(buf, " MODE ")) && (strstr(buf, "!")) - && (strstr(buf, "+v") || strstr(buf, "-v") || strstr(buf, "-o") || strstr(buf, "+o")) - && (buf[0] == ':') && (!strstr(buf, " NOTICE "))) { - - gchar u_channel[128]; - gchar u_nick[128]; - - gchar u_mode[5]; - char **people; - gchar *temp, *temp_new; - - - struct irc_channel *channel; - int j; - temp = NULL; - temp_new = NULL; - - - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - u_nick[j] = buf[i]; - } - u_nick[j] = '\0'; - i++; - - for (j = 0; buf[i] != '#'; j++, i++) { - } - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_channel[j] = buf[i]; - } - - u_channel[j] = '\0'; - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_mode[j] = buf[i]; - } - u_mode[j] = '\0'; - i++; - - - - - people = g_strsplit(buf + i, " ", 3); - - - - channel = find_channel_by_name(gc, u_channel); - - if (!channel) { - return; - } - - for (j = 0; j < strlen(u_mode) - 1; j++) { - - - struct conversation *convo = NULL; - convo = find_conversation_by_id(gc, channel->id); - - - - temp = (gchar *) g_malloc(strlen(people[j]) + 3); - temp_new = (gchar *) g_malloc(strlen(people[j]) + 3); - g_snprintf(temp, strlen(people[j]) + 2, "@%s", people[j]); - - if (u_mode[1] == 'v' && u_mode[0] == '+') { - g_snprintf(temp_new, strlen(people[j]) + 2, "+%s", people[j]); - } else if (u_mode[1] == 'o' && u_mode[0] == '+') { - g_snprintf(temp_new, strlen(people[j]) + 2, "@%s", people[j]); - } - - else if (u_mode[0] == '-') { - g_snprintf(temp_new, strlen(people[j]) + 1, "%s", people[j]); - } - - - - rename_chat_buddy(convo, temp, temp_new); - g_snprintf(temp, strlen(people[j]) + 2, "+%s", people[j]); - rename_chat_buddy(convo, temp, temp_new); - - rename_chat_buddy(convo, people[j], temp_new); - - - - - - } - if (temp) - g_free(temp); - if (temp_new) - g_free(temp_new); - - return; - } - - - if ((strstr(buf, " KICK ")) && (strstr(buf, "!")) && (buf[0] == ':') - && (!strstr(buf, " NOTICE "))) { - gchar u_channel[128]; - gchar u_nick[128]; - gchar u_comment[128]; - gchar u_who[128]; - - int id; - - gchar *temp; - - - - struct irc_channel *channel; - int j; - - temp = NULL; - - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - u_nick[j] = buf[i]; - } - u_nick[j] = '\0'; - i++; + process_data_init(pdibuf, buf, word, word_eol, FALSE); - for (j = 0; buf[i] != '#'; j++, i++) { - } - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_channel[j] = buf[i]; - } - - u_channel[j] = '\0'; - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_who[j] = buf[i]; - } - u_who[j] = '\0'; - i++; - i++; - strcpy(u_comment, buf + i); - g_strchomp(u_comment); - - channel = find_channel_by_name(gc, u_channel); - - if (!channel) { - return; - } - - - id = find_id_by_name(gc, u_channel); - - - if (g_strcasecmp(u_nick, gc->username) == 0) { - - /* It looks like you've been naughty! */ - - serv_got_chat_left(gc, channel->id); - - idata->channels = g_list_remove(idata->channels, channel); - } else { - struct conversation *convo = NULL; - - /* Find their conversation window */ - convo = find_conversation_by_id(gc, channel->id); - - if (!convo) { - /* Some how the window doesn't exist. - * Let's get out of here */ - return; - } - - /* And remove their name */ - /* If the person is an op or voice, this won't work. - * so we'll just do a nice hack and remove nick and - * @nick and +nick. Truly wasteful. - */ - - temp = (gchar *) g_malloc(strlen(u_who) + 3); - g_snprintf(temp, strlen(u_who) + 2, "@%s", u_who); - remove_chat_buddy(convo, temp); - g_free(temp); - temp = (gchar *) g_malloc(strlen(u_who) + 3); - g_snprintf(temp, strlen(u_who) + 2, "+%s", u_who); - remove_chat_buddy(convo, temp); - remove_chat_buddy(convo, u_who); - - g_free(temp); - - } - - /* Go Home! */ - return; - } - - if ((strstr(buf, " TOPIC ")) && (buf[0] == ':') && (!strstr(buf, " NOTICE "))) { - - gchar u_channel[128]; - gchar u_nick[128]; - gchar u_topic[128]; - int j; - struct conversation *chatroom = NULL; - - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - u_nick[j] = buf[i]; - } - u_nick[j] = 0; - i++; - - for (j = 0; buf[i] != '#'; j++, i++) { - } - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - if (buf[i] == '\0') - break; - - u_channel[j] = buf[i]; - } - - for (j = 0; buf[i] != ':'; j++, i++) { - } - i++; - - strcpy(u_topic, buf + i); - g_strchomp(u_topic); - - chatroom = find_chat(gc, u_channel); - - if (!chatroom) - return; - - chat_set_topic(chatroom, u_nick, u_topic); - - return; - } - - - if ((strstr(buf, " JOIN ")) && (strstr(buf, "!")) && (buf[0] == ':') - && (!strstr(buf, " NOTICE "))) { - - gchar u_channel[128]; - gchar u_nick[128]; - - struct irc_channel *channel; - int j; - - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - u_nick[j] = buf[i]; - } - - u_nick[j] = '\0'; - i++; - - for (j = 0; buf[i] != '#'; j++, i++) { - } - - i++; - - strcpy(u_channel, buf + i); - - g_strchomp(u_channel); - - /* Looks like we're going to join the channel for real - * now. Let's create a valid channel structure and add - * it to our list. Let's make sure that - * we are not already in a channel first */ - - channel = find_channel_by_name(gc, u_channel); - - if (!channel) { - - chat_id++; - - channel = g_new0(struct irc_channel, 1); - - channel->id = chat_id; - channel->name = strdup(u_channel); - - idata->channels = g_list_append(idata->channels, channel); - - serv_got_joined_chat(gc, chat_id, u_channel); - } else { - struct conversation *convo = NULL; - - /* Someone else joined. Find their conversation - * window */ - convo = find_conversation_by_id(gc, channel->id); - - /* And add their name to it */ - add_chat_buddy(convo, u_nick); - - } - - return; - } - - if ((strstr(buf, " NICK ")) && (strstr(buf, "!")) && (buf[0] == ':') - && (!strstr(buf, " NOTICE "))) { - - gchar old[128]; - gchar new[128]; - - GList *templist; - gchar *temp, *temp_new; - struct irc_channel *channel; - int j; - temp = temp_new = NULL; - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - old[j] = buf[i]; - } - - old[j] = '\0'; - i++; - - for (j = 0; buf[i] != ':'; j++, i++) { - } - - i++; - strcpy(new, buf + i); - - g_strchomp(new); - - templist = ((struct irc_data *)gc->proto_data)->channels; - - while (templist) { - struct conversation *convo = NULL; - channel = templist->data; - - convo = find_conversation_by_id(gc, channel->id); - - /* If the person is an op or voice, this won't work. - * so we'll just do a nice hack and rename nick and - * @nick and +nick. Truly wasteful. - */ - - temp = (gchar *) g_malloc(strlen(old) + 5); - temp_new = (gchar *) g_malloc(strlen(new) + 5); - g_snprintf(temp_new, strlen(new) + 2, "@%s", new); - g_snprintf(temp, strlen(old) + 2, "@%s", old); - rename_chat_buddy(convo, temp, temp_new); - g_snprintf(temp, strlen(old) + 2, "+%s", old); - g_snprintf(temp_new, strlen(new) + 2, "+%s", new); - rename_chat_buddy(convo, temp, temp_new); - rename_chat_buddy(convo, old, new); - if (temp) - g_free(temp); - if (temp_new) - g_free(temp_new); - - templist = templist->next; - } - return; - } - - - if ((strstr(buf, "QUIT ")) && (buf[0] == ':') && (strstr(buf, "!")) - && (!strstr(buf, " NOTICE "))) { - - gchar u_nick[128]; - gchar *temp; - GList *templist; - - struct irc_channel *channel; - int j; - - - temp = NULL; - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - u_nick[j] = buf[i]; - } - - u_nick[j] = '\0'; - - templist = ((struct irc_data *)gc->proto_data)->channels; - - while (templist) { - struct conversation *convo = NULL; - channel = templist->data; - - convo = find_conversation_by_id(gc, channel->id); - - /* If the person is an op or voice, this won't work. - * so we'll just do a nice hack and remove nick and - * @nick and +nick. Truly wasteful. - */ - - temp = (gchar *) g_malloc(strlen(u_nick) + 2); - g_snprintf(temp, strlen(u_nick) + 2, "@%s", u_nick); - remove_chat_buddy(convo, temp); - g_free(temp); - temp = (gchar *) g_malloc(strlen(u_nick) + 2); - g_snprintf(temp, strlen(u_nick) + 2, "+%s", u_nick); - remove_chat_buddy(convo, temp); - remove_chat_buddy(convo, u_nick); - - - - templist = templist->next; - } - - g_free(temp); - + if (atoi(word[2])) { + if (*word_eol[3]) + process_numeric(gc, word, word_eol); return; } - - - if ((strstr(buf, " PART ")) && (strstr(buf, "!")) && (buf[0] == ':') - && (!strstr(buf, " NOTICE "))) { - - gchar u_channel[128]; - gchar u_nick[128]; - gchar *temp; - struct irc_channel *channel; - int j; - temp = NULL; - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - u_nick[j] = buf[i]; - } - u_nick[j] = '\0'; - - i++; - - for (j = 0; buf[i] != '#'; j++, i++) { - } - - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - if (buf[i] == '\0') { - break; - } - u_channel[j] = buf[i]; - } - u_channel[j] = '\0'; - - /* Now, lets check to see if it was US that was leaving. - * If so, do the correct thing by closing up all of our - * old channel stuff. Otherwise, - * we should just print that someone left */ - - channel = find_channel_by_name(gc, u_channel); - - if (!channel) { - return; - } + cmd = word[2]; - if (g_strcasecmp(u_nick, gc->username) == 0) { - - /* Looks like we're going to leave the channel for - * real now. Let's create a valid channel structure - * and add it to our list */ - - serv_got_chat_left(gc, channel->id); - - idata->channels = g_list_remove(idata->channels, channel); - } else { - struct conversation *convo = NULL; - - /* Find their conversation window */ - convo = find_conversation_by_id(gc, channel->id); - - if (!convo) { - /* Some how the window doesn't exist. - * Let's get out of here */ - return; - } - - /* And remove their name */ - /* If the person is an op or voice, this won't work. - * so we'll just do a nice hack and remove nick and - * @nick and +nick. Truly wasteful. - */ - - temp = (gchar *) g_malloc(strlen(u_nick) + 3); - g_snprintf(temp, strlen(u_nick) + 2, "@%s", u_nick); - remove_chat_buddy(convo, temp); - g_free(temp); - temp = (gchar *) g_malloc(strlen(u_nick) + 3); - g_snprintf(temp, strlen(u_nick) + 2, "+%s", u_nick); - remove_chat_buddy(convo, temp); - g_free(temp); - remove_chat_buddy(convo, u_nick); - - - } - - /* Go Home! */ - return; + ex = strchr(pdibuf, '!'); + if (!ex) { + strncpy(ip, pdibuf, sizeof(ip)); + ip[sizeof(ip)-1] = 0; + strncpy(nick, pdibuf, sizeof(nick)); + nick[sizeof(nick)-1] = 0; + } else { + strncpy(ip, ex + 1, sizeof(ip)); + ip[sizeof(ip)-1] = 0; + strncpy(nick, pdibuf, sizeof(nick)); + nick[sizeof(nick)-1] = 0; + if ((ex - pdibuf) < sizeof (nick)) + nick[ex - pdibuf] = 0; /* cut the buffer at the '!' */ } - if ((strstr(buf, " NOTICE ")) && (buf[0] == ':')) { - gchar u_nick[128]; - gchar u_host[255]; - gchar u_command[32]; - gchar u_channel[128]; - gchar u_message[IRC_BUF_LEN]; - int j; - - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - u_nick[j] = buf[i]; - } - - u_nick[j] = '\0'; - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_host[j] = buf[i]; - } - - u_host[j] = '\0'; - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_command[j] = buf[i]; - } - - u_command[j] = '\0'; - i++; - - for (j = 0; buf[i] != ':'; j++, i++) { - u_channel[j] = buf[i]; + if (!strcmp(cmd, "INVITE")) { /* */ + } else if (!strcmp(cmd, "JOIN")) { + char *chan = *word[3] == ':' ? word[3] + 1 : word[3]; + if (!g_strcasecmp(gc->displayname, nick)) { + static int id = 1; + serv_got_joined_chat(gc, id++, chan); + } else { + struct conversation *c = irc_find_chat(gc, chan); + if (c) + add_chat_buddy(c, nick); } - - u_channel[j - 1] = '\0'; - i++; - - - /* Now that everything is parsed, the rest of this baby must be our message */ - strncpy(u_message, buf + i, IRC_BUF_LEN); - - /* Now, lets check the message to see if there's anything special in it */ - if (u_message[0] == '\001') { - if ((g_strncasecmp(u_message, "\001PING ", 6) == 0) && (strlen(u_message) > 6)) { - /* Someone's triyng to ping us. Let's respond */ - gchar u_arg[24]; - gchar u_buf[200]; - unsigned long tend = time((time_t *) NULL); - unsigned long tstart; - - printf("LA: %s\n", buf); - - strcpy(u_arg, u_message + 6); - u_arg[strlen(u_arg) - 1] = '\0'; - - tstart = atol(u_arg); - - g_snprintf(u_buf, sizeof(u_buf), "Ping Reply From %s: [%ld seconds]", - u_nick, tend - tstart); - - do_error_dialog(u_buf, "Gaim IRC - Ping Reply"); - + } else if (!strcmp(cmd, "KICK")) { + if (!strcmp(gc->displayname, word[4])) { + struct conversation *c = irc_find_chat(gc, word[3]); + if (!c) return; - } + gc->buddy_chats = g_slist_remove(gc->buddy_chats, c); + c->gc = NULL; + g_snprintf(outbuf, sizeof(outbuf), _("You have been kicked from %s: %s"), + word[3], *word_eol[5] == ':' ? word_eol[5] + 1: word_eol[5]); + do_error_dialog(outbuf, _("IRC Error")); + } else + irc_rem_chat_bud(gc, nick); + } else if (!strcmp(cmd, "KILL")) { /* */ + } else if (!strcmp(cmd, "MODE")) { + handle_mode(gc, word, word_eol, FALSE); + } else if (!strcmp(cmd, "NICK")) { + char *new = *word_eol[3] == ':' ? word_eol[3] + 1 : word_eol[3]; + if (!strcmp(gc->displayname, nick)) + g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", new); + irc_change_name(gc, nick, new); + } else if (!strcmp(cmd, "NOTICE")) { + if (*word_eol[4] == ':') word_eol[4]++; + if (ex) + irc_got_im(gc, nick, word_eol[4], 0, time(NULL)); + } else if (!strcmp(cmd, "PART")) { + char *chan = cmd + 5; + struct conversation *c; + GList *r; + if (*chan == ':') + chan++; + if (!(c = irc_find_chat(gc, chan))) + return; + if (!strcmp(nick, gc->displayname)) { + serv_got_chat_left(gc, c->id); + return; } - - } - - - if ((strstr(buf, " PRIVMSG ")) && (buf[0] == ':')) { - gchar u_nick[128]; - gchar u_host[255]; - gchar u_command[32]; - gchar u_channel[128]; - gchar u_message[IRC_BUF_LEN]; - gboolean is_closing; - - int j; - - - for (j = 0, i = 1; buf[i] != '!'; j++, i++) { - u_nick[j] = buf[i]; - } - - u_nick[j] = '\0'; - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_host[j] = buf[i]; - } - - u_host[j] = '\0'; - i++; - - for (j = 0; buf[i] != ' '; j++, i++) { - u_command[j] = buf[i]; - } - - u_command[j] = '\0'; - i++; - - for (j = 0; buf[i] != ':'; j++, i++) { - u_channel[j] = buf[i]; + r = c->in_room; + while (r) { + char *who = r->data; + if (*who == '@') + who++; + if (*who == '+') + who++; + if (!g_strcasecmp(who, nick)) { + char *tmp = g_strdup(r->data); + remove_chat_buddy(c, r->data); + g_free(tmp); + break; + } + r = r->next; } - - u_channel[j - 1] = '\0'; - i++; - - - /* Now that everything is parsed, the rest of this baby must be our message */ - strncpy(u_message, buf + i, IRC_BUF_LEN); - - /* Now, lets check the message to see if there's anything special in it */ - if (u_message[0] == '\001') { - if (g_strncasecmp(u_message, "\001VERSION", 8) == 0) { - /* Looks like we have a version request. Let - * us handle it thusly */ - - g_snprintf(buf, IRC_BUF_LEN, - "NOTICE %s :%cVERSION GAIM %s:The Pimpin Penguin AIM Clone:%s%c\n", - u_nick, '\001', VERSION, WEBSITE, '\001'); - - write(idata->fd, buf, strlen(buf)); - - /* And get the heck out of dodge */ - return; + } else if (!strcmp(cmd, "PRIVMSG")) { + char *to, *msg; + if (!*word[3]) + return; + to = word[3]; + msg = *word_eol[4] == ':' ? word_eol[4] + 1 : word_eol[4]; + if (msg[0] == 1 && msg[strlen (msg) - 1] == 1) { /* ctcp */ + if (!g_strncasecmp(msg + 1, "ACTION", 6)) { + char *po = strchr(msg + 7, 1); + if (po) *po = 0; + to = g_strconcat("/me", msg + 7, NULL); + irc_got_im(gc, nick, to, 0, time(NULL)); + g_free(to); } - - if ((g_strncasecmp(u_message, "\001PING ", 6) == 0) && (strlen(u_message) > 6)) { - /* Someone's triyng to ping us. Let's respond */ - gchar u_arg[24]; - - strcpy(u_arg, u_message + 6); - u_arg[strlen(u_arg) - 1] = '\0'; - - g_snprintf(buf, IRC_BUF_LEN, "NOTICE %s :%cPING %s%c\n", u_nick, '\001', - u_arg, '\001'); - - write(idata->fd, buf, strlen(buf)); - - /* And get the heck out of dodge */ - return; - } - - if (g_strncasecmp(u_message, "\001ACTION ", 8) == 0) { - /* Looks like we have an action. Let's parse it a little */ - strcpy(buf, u_message); - - strcpy(u_message, "/me "); - for (j = 4, i = 8; buf[i] != '\001'; i++, j++) { - u_message[j] = buf[i]; + } else { + if (is_channel(gc, to)) { + struct conversation *c = irc_find_chat(gc, to); + if (!c) + return; + irc_got_chat_in(gc, c->id, nick, 0, msg, time(NULL)); + } else { + to = g_malloc(strlen(nick) + 2); + g_snprintf(to, strlen(nick) + 2, "@%s", nick); + if (find_conversation(to)) + irc_got_im(gc, to, msg, 0, time(NULL)); + else { + *to = '+'; + if (find_conversation(to)) + irc_got_im(gc, to, msg, 0, time(NULL)); + else + irc_got_im(gc, nick, msg, 0, time(NULL)); } - u_message[j] = '\0'; + g_free(to); } } - - - /* OK, It is a chat or IM message. Here, let's translate the IRC formatting into - * good ol' fashioned imhtml style hypertext markup. */ - - - is_closing = FALSE; - - while (strchr(u_message, '\002')) { /* \002 = ^B */ - gchar *current; - gchar *temp, *free_here; - - - temp = g_strdup(strchr(u_message, '\002')); - free_here = temp; - temp++; - - current = strchr(u_message, '\002'); - *current = '<'; - current++; - if (is_closing) { - *current = '/'; - current++; - } - *current = 'b'; - current++; - *current = '>'; - current++; - - - while (*temp != '\0') { - *current = *temp; - current++; - temp++; - } - *current = '\0'; - g_free(free_here); - - is_closing = !is_closing; - } - - is_closing = FALSE; - while (strchr(u_message, '\037')) { /* \037 = ^_ */ - gchar *current; - gchar *temp, *free_here; - - - temp = g_strdup(strchr(u_message, '\037')); - free_here = temp; - temp++; - - current = strchr(u_message, '\037'); - *current = '<'; - current++; - if (is_closing) { - *current = '/'; - current++; - } - *current = 'u'; - current++; - *current = '>'; - current++; - - - while (*temp != '\0') { - *current = *temp; - current++; - temp++; - } - *current = '\0'; - g_free(free_here); - is_closing = !is_closing; - - } - - while (strchr(u_message, '\003')) { /* \003 = ^C */ - - /* This is color formatting. IRC uses its own weird little system - * that we must translate to HTML. */ - - - /* The format is something like this: - * ^C5 or ^C5,3 - * The number before the comma is the foreground color, after is the - * background color. Either number can be 1 or two digits. - */ - - gchar *current; - gchar *temp, *free_here; - gchar *font_tag, *body_tag; - int fg_color, bg_color; - - temp = g_strdup(strchr(u_message, '\003')); - free_here = temp; - temp++; - - fg_color = bg_color = -1; - body_tag = font_tag = ""; - - /* Parsing the color information: */ - do { - if (!isdigit(*temp)) - break; /* This translates to </font> */ - fg_color = (int)(*temp - 48); - temp++; - if (isdigit(*temp)) { - fg_color = (fg_color * 10) + (int)(*temp - 48); - temp++; - } - if (*temp != ',') - break; - temp++; - if (!isdigit(*temp)) - break; /* This translates to </font> */ - bg_color = (int)(*temp - 48); - temp++; - if (isdigit(*temp)) { - bg_color = (bg_color * 10) + (int)(*temp - 48); - temp++; - } - } while (FALSE); - - if (fg_color > 15) - fg_color = fg_color % 16; - if (bg_color > 15) - bg_color = bg_color % 16; - - switch (fg_color) { - case -1: - font_tag = "</font></body>"; - break; - case 0: /* WHITE */ - font_tag = "<font color=\"#ffffff\">"; - /* If no background color is specified, we're going to make it black anyway. - * That's probably what the sender anticipated the background color to be. - * White on white would be illegible. - */ - if (bg_color == -1) { - body_tag = "<body bgcolor=\"#000000\">"; - } - break; - case 1: /* BLACK */ - font_tag = "<font color=\"#000000\">"; - break; - case 2: /* NAVY BLUE */ - font_tag = "<font color=\"#000066\">"; - break; - case 3: /* GREEN */ - font_tag = "<font color=\"#006600\">"; - break; - case 4: /* RED */ - font_tag = "<font color=\"#ff0000\">"; - break; - case 5: /* MAROON */ - font_tag = "<font color=\"#660000\">"; - break; - case 6: /* PURPLE */ - font_tag = "<font color=\"#660066\">"; - break; - case 7: /* DISGUSTING PUKE COLOR */ - font_tag = "<font color=\"#666600\">"; - break; - case 8: /* YELLOW */ - font_tag = "<font color=\"#cccc00\">"; - break; - case 9: /* LIGHT GREEN */ - font_tag = "<font color=\"#33cc33\">"; - break; - case 10: /* TEAL */ - font_tag = "<font color=\"#00acac\">"; - break; - case 11: /* CYAN */ - font_tag = "<font color=\"#00ccac\">"; - break; - case 12: /* BLUE */ - font_tag = "<font color=\"#0000ff\">"; - break; - case 13: /* PINK */ - font_tag = "<font color=\"#cc00cc\">"; - break; - case 14: /* GREY */ - font_tag = "<font color=\"#666666\">"; - break; - case 15: /* SILVER */ - font_tag = "<font color=\"#00ccac\">"; - break; - } - - switch (bg_color) { - case 0: /* WHITE */ - body_tag = "<body bgcolor=\"#ffffff\">"; - break; - case 1: /* BLACK */ - body_tag = "<body bgcolor=\"#000000\">"; - break; - case 2: /* NAVY BLUE */ - body_tag = "<body bgcolor=\"#000066\">"; - break; - case 3: /* GREEN */ - body_tag = "<body bgcolor=\"#006600\">"; - break; - case 4: /* RED */ - body_tag = "<body bgcolor=\"#ff0000\">"; - break; - case 5: /* MAROON */ - body_tag = "<body bgcolor=\"#660000\">"; - break; - case 6: /* PURPLE */ - body_tag = "<body bgcolor=\"#660066\">"; - break; - case 7: /* DISGUSTING PUKE COLOR */ - body_tag = "<body bgcolor=\"#666600\">"; - break; - case 8: /* YELLOW */ - body_tag = "<body bgcolor=\"#cccc00\">"; - break; - case 9: /* LIGHT GREEN */ - body_tag = "<body bgcolor=\"#33cc33\">"; - break; - case 10: /* TEAL */ - body_tag = "<body bgcolor=\"#00acac\">"; - break; - case 11: /* CYAN */ - body_tag = "<body bgcolor=\"#00ccac\">"; - break; - case 12: /* BLUE */ - body_tag = "<body bgcolor=\"#0000ff\">"; - break; - case 13: /* PINK */ - body_tag = "<body bgcolor=\"#cc00cc\">"; - break; - case 14: /* GREY */ - body_tag = "<body bgcolor=\"#666666\">"; - break; - case 15: /* SILVER */ - body_tag = "<body bgcolor=\"#00ccac\">"; - break; - } - - current = strchr(u_message, '\003'); - - while (*body_tag != '\0') { - *current = *body_tag; - current++; - body_tag++; - } - - while (*font_tag != '\0') { - *current = *font_tag; - current++; - font_tag++; - } - - while (*temp != '\0') { - *current = *temp; - current++; - temp++; - } - *current = '\0'; - g_free(free_here); - is_closing = !is_closing; - - } - - while (strchr(u_message, '\017')) { /* \017 = ^O */ - gchar *current; - gchar *temp, *free_here; - - - temp = g_strdup(strchr(u_message, '\017')); - free_here = temp; - temp++; - - current = strchr(u_message, '\017'); - *current = '<'; - current++; - *current = '/'; - current++; - *current = 'b'; - current++; - *current = '>'; - current++; - *current = '<'; - current++; - *current = '/'; - current++; - *current = 'u'; - current++; - *current = '>'; - current++; - - while (*temp != '\0') { - *current = *temp; - current++; - temp++; - } - *current = '\0'; - g_free(free_here); - } - - /* Let's check to see if we have a channel on our hands */ - if (u_channel[0] == '#') { - /* Yup. We have a channel */ - int id; - - id = find_id_by_name(gc, u_channel); - if (id != -1) { - serv_got_chat_in(gc, id, u_nick, 0, u_message, time((time_t) NULL)); - - } - - } else { - /* Nope. Let's treat it as a private message */ - - gchar *temp; - temp = NULL; - - temp = (gchar *) g_malloc(strlen(u_nick) + 5); - g_snprintf(temp, strlen(u_nick) + 2, "@%s", u_nick); - - - /* If I get a message from SeanEgn, and I already have a window - * open for him as @SeanEgn or +SeanEgn, this will keep it in the - * same window. Unfortunately, if SeanEgn loses his op status - * (a sad thing indeed), the messages will still appear to come from - * @SeanEgn, until that convo is closed. - */ - - if (find_conversation(temp)) { - serv_got_im(gc, temp, u_message, 0, time((time_t) NULL)); - g_free(temp); - return; - } else { - g_snprintf(temp, strlen(u_nick) + 2, "+%s", u_nick); - if (find_conversation(temp)) { - serv_got_im(gc, temp, u_message, 0, time((time_t) NULL)); - g_free(temp); - return; - } else { - g_free(temp); - serv_got_im(gc, u_nick, u_message, 0, time((time_t) NULL)); - return; - } - } - } - - return; + } else if (!strcmp(cmd, "PONG")) { /* */ + } else if (!strcmp(cmd, "QUIT")) { + irc_rem_chat_bud(gc, nick); + } else if (!strcmp(cmd, "TOPIC")) { + struct conversation *c = irc_find_chat(gc, word[3]); + char *topic = *word_eol[4] == ':' ? word_eol[4] + 1 : word_eol[4]; + if (c) + chat_set_topic(c, nick, topic); + } else if (!strcmp(cmd, "WALLOPS")) { /* */ } - - /* Let's parse PING requests so that we wont get booted for inactivity */ - - if (strncmp(buf, "PING :", 6) == 0) { - buf2 = g_strsplit(buf, ":", 1); - - /* Let's build a new response */ - g_snprintf(buf, IRC_BUF_LEN, "PONG :%s\n", buf2[1]); - write(idata->fd, buf, strlen(buf)); - - /* And clean up after ourselves */ - g_strfreev(buf2); - - return; - } - -} - -static void irc_close(struct gaim_connection *gc) -{ - struct irc_data *idata = (struct irc_data *)gc->proto_data; - GList *chats = idata->channels; - struct irc_channel *cc; - - gchar *buf = (gchar *) g_malloc(IRC_BUF_LEN); - - g_snprintf(buf, IRC_BUF_LEN, "QUIT :Download GAIM [%s]\n", WEBSITE); - write(idata->fd, buf, strlen(buf)); - - g_free(buf); - - if (idata->timer) - g_source_remove(idata->timer); - - while (chats) { - cc = (struct irc_channel *)chats->data; - g_free(cc->name); - chats = g_list_remove(chats, cc); - g_free(cc); - } - - if (gc->inpa) - gaim_input_remove(gc->inpa); - - if (idata->inpa) - gaim_input_remove(idata->inpa); - - close(idata->fd); - g_free(gc->proto_data); -} - -static void irc_chat_leave(struct gaim_connection *gc, int id) -{ - struct irc_data *idata = (struct irc_data *)gc->proto_data; - struct irc_channel *channel; - gchar *buf = (gchar *) g_malloc(IRC_BUF_LEN + 1); - - channel = find_channel_by_id(gc, id); - - if (!channel) { - return; - } - - g_snprintf(buf, IRC_BUF_LEN, "PART #%s\n", channel->name); - write(idata->fd, buf, strlen(buf)); - - g_free(buf); } static void irc_login_callback(gpointer data, gint source, GaimInputCondition condition) { struct gaim_connection *gc = data; struct irc_data *idata; - char buf[4096]; + char hostname[256]; + char buf[IRC_BUF_LEN]; if (!g_slist_find(connections, gc)) { close(source); @@ -1927,38 +847,45 @@ if (idata->fd != source) idata->fd = source; - g_snprintf(buf, 4096, "NICK %s\n USER %s localhost %s :GAIM (%s)\n", - gc->username, g_get_user_name(), gc->user->proto_opt[USEROPT_SERV], WEBSITE); + g_snprintf(buf, sizeof(buf), "NICK %s\r\n", gc->username); + if (irc_write(idata->fd, buf, strlen(buf)) < 0) { + hide_login_progress(gc, "Write error"); + signoff(gc); + return; + } - if (write(idata->fd, buf, strlen(buf)) < 0) { + gethostname(hostname, sizeof(hostname) - 1); + hostname[sizeof(hostname) - 1] = 0; + if (!*hostname) + g_snprintf(hostname, sizeof(hostname), "localhost"); + g_snprintf(buf, sizeof(buf), "USER %s %s %s :GAIM (%s)\r\n", + g_get_user_name(), hostname, gc->user->proto_opt[USEROPT_SERV], WEBSITE); + if (irc_write(idata->fd, buf, strlen(buf)) < 0) { hide_login_progress(gc, "Write error"); signoff(gc); return; } - idata->inpa = gaim_input_add(idata->fd, GAIM_INPUT_READ, irc_callback, gc); - - /* Now lets sign ourselves on */ - account_online(gc); - serv_finish_login(gc); - - if (bud_list_cache_exists(gc)) - do_import(NULL, gc); - - /* we don't call this now because otherwise some IRC servers might not like us */ - idata->timer = g_timeout_add(20000, irc_request_buddy_update, gc); + gc->inpa = gaim_input_add(idata->fd, GAIM_INPUT_READ, irc_callback, gc); } static void irc_login(struct aim_user *user) { - char buf[4096]; + char buf[IRC_BUF_LEN]; struct gaim_connection *gc = new_gaim_conn(user); struct irc_data *idata = gc->proto_data = g_new0(struct irc_data, 1); + g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", gc->username); + g_snprintf(buf, sizeof(buf), "Signon: %s", gc->username); set_login_progress(gc, 2, buf); + idata->chantypes = g_strdup("#&!+"); + idata->chanmodes = g_strdup("beI,k,l"); + idata->nickmodes = g_strdup("ohv"); + idata->str = g_string_new(""); + idata->fd = proxy_connect(user->proto_opt[USEROPT_SERV], user->proto_opt[USEROPT_PORT][0] ? atoi(user-> proto_opt[USEROPT_PORT]) : @@ -1970,6 +897,30 @@ } } +static void irc_close(struct gaim_connection *gc) +{ + struct irc_data *idata = (struct irc_data *)gc->proto_data; + gchar buf[IRC_BUF_LEN]; + + g_snprintf(buf, sizeof(buf), "QUIT :Download GAIM [%s]\r\n", WEBSITE); + irc_write(idata->fd, buf, strlen(buf)); + + g_free(idata->chantypes); + g_free(idata->chanmodes); + g_free(idata->nickmodes); + + g_string_free(idata->str, TRUE); + + if (idata->timer) + g_source_remove(idata->timer); + + if (gc->inpa) + gaim_input_remove(gc->inpa); + + close(idata->fd); + g_free(gc->proto_data); +} + static GList *irc_user_opts() { GList *m = NULL; @@ -1990,94 +941,314 @@ return m; } -static char **irc_list_icon(int uc) +static void set_mode_3(struct gaim_connection *gc, char *who, int sign, int mode, + int start, int end, char *word[]) { - return free_icon_xpm; + struct irc_data *id = gc->proto_data; + char buf[IRC_BUF_LEN]; + int left; + int i = start; + + while (1) { + left = end - i; + switch (left) { + case 0: + return; + case 1: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c %s\r\n", + who, sign, mode, word[i]); + i += 1; + break; + case 2: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c %s %s\r\n", + who, sign, mode, mode, word[i], word[i + 1]); + i += 2; + break; + default: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c %s %s %s\r\n", + who, sign, mode, mode, mode, + word[i], word[i + 1], word[i + 2]); + i += 2; + break; + } + irc_write(id->fd, buf, strlen(buf)); + if (left < 3) + return; + } } -/* Send out a ping request to the specified user */ -static void irc_send_ping(struct gaim_connection *gc, char *who) +static void set_mode_6(struct gaim_connection *gc, char *who, int sign, int mode, + int start, int end, char *word[]) { - struct irc_data *idata = (struct irc_data *)gc->proto_data; - char buf[BUF_LEN]; + struct irc_data *id = gc->proto_data; + char buf[IRC_BUF_LEN]; + int left; + int i = start; - g_snprintf(buf, BUF_LEN, "PRIVMSG %s :%cPING %ld%c\n", who, '\001', time((time_t *) NULL), - '\001'); + while (1) { + left = end - i; + switch (left) { + case 0: + return; + case 1: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c %s\r\n", + who, sign, mode, word[i]); + i += 1; + break; + case 2: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c %s %s\r\n", + who, sign, mode, mode, word[i], word[i + 1]); + i += 2; + break; + case 3: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c %s %s %s\r\n", + who, sign, mode, mode, mode, + word[i], word[i + 1], word[i + 2]); + i += 3; + break; + case 4: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c%c %s %s %s %s\r\n", + who, sign, mode, mode, mode, mode, + word[i], word[i + 1], word[i + 2], word[i + 3]); + i += 4; + break; + case 5: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c%c%c %s %s %s %s %s\r\n", + who, sign, mode, mode, mode, mode, mode, + word[i], word[i + 1], word[i + 2], + word[i + 3], word[i + 4]); + i += 5; + break; + default: + g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c%c%c%c %s %s %s %s %s %s\r\n", + who, sign, mode, mode, mode, mode, mode, mode, + word[i], word[i + 1], word[i + 2], + word[i + 3], word[i + 4], word[i + 5]); + i += 6; + break; + } + irc_write(id->fd, buf, strlen(buf)); + if (left < 6) + return; + } +} - write(idata->fd, buf, strlen(buf)); +static void set_mode(struct gaim_connection *gc, char *who, int sign, int mode, char *word[]) +{ + struct irc_data *id = gc->proto_data; + int i = 2; + + while (1) { + if (!*word[i]) { + if (i == 2) + return; + if (id->six_modes) + set_mode_6(gc, who, sign, mode, 2, i, word); + else + set_mode_3(gc, who, sign, mode, 2, i, word); + return; + } + i++; + } } -/* Do a whois check on someone :-) */ -static void irc_get_info(struct gaim_connection *gc, char *who) +static void handle_command(struct gaim_connection *gc, char *who, char *what) { - struct irc_data *idata = (struct irc_data *)gc->proto_data; - char buf[BUF_LEN]; + char buf[IRC_BUF_LEN]; + char pdibuf[IRC_BUF_LEN]; + char *word[PDIWORDS], *word_eol[PDIWORDS]; + struct irc_data *id = gc->proto_data; + if (*what != '/') { + unsigned int max = 440 - strlen(who); + char t; + while (strlen(what) > max) { + t = what[max]; + what[max] = 0; + g_snprintf(buf, sizeof(buf), "PRIVMSG %s :%s\r\n", who, what); + irc_write(id->fd, buf, strlen(buf)); + what[max] = t; + what = what + max; + } + g_snprintf(buf, sizeof(buf), "PRIVMSG %s :%s\r\n", who, what); + irc_write(id->fd, buf, strlen(buf)); + return; + } + + what++; + process_data_init(pdibuf, what, word, word_eol, TRUE); - if (((who[0] == '@') || (who[0] == '+')) && (strlen(who) > 1)) - g_snprintf(buf, BUF_LEN, "WHOIS %s\n", who + 1); - else - g_snprintf(buf, BUF_LEN, "WHOIS %s\n", who); - write(idata->fd, buf, strlen(buf)); + if (!g_strcasecmp(pdibuf, "ME")) { + g_snprintf(buf, sizeof(buf), "PRIVMSG %s :\001ACTION %s\001\r\n", who, word_eol[2]); + irc_write(id->fd, buf, strlen(buf)); + } else if (!g_strcasecmp(pdibuf, "TOPIC")) { + if (!*word_eol[2]) + return; + g_snprintf(buf, sizeof(buf), "TOPIC %s :%s\r\n", who, word_eol[2]); + irc_write(id->fd, buf, strlen(buf)); + } else if (!g_strcasecmp(pdibuf, "NICK")) { + if (!*word_eol[2]) + return; + g_snprintf(buf, sizeof(buf), "NICK %s\r\n", word_eol[2]); + irc_write(id->fd, buf, strlen(buf)); + } else if (!g_strcasecmp(pdibuf, "OP")) { + set_mode(gc, who, '+', 'o', word); + } else if (!g_strcasecmp(pdibuf, "DEOP")) { + set_mode(gc, who, '-', 'o', word); + } else if (!g_strcasecmp(pdibuf, "VOICE")) { + set_mode(gc, who, '+', 'v', word); + } else if (!g_strcasecmp(pdibuf, "DEVOICE")) { + set_mode(gc, who, '-', 'v', word); + } else if (!g_strcasecmp(pdibuf, "QUOTE")) { + if (!*word_eol[2]) + return; + g_snprintf(buf, sizeof(buf), "%s\r\n", word_eol[2]); + irc_write(id->fd, buf, strlen(buf)); + } else if (!g_strcasecmp(pdibuf, "KICK")) { + if (!*word[2]) + return; + if (*word_eol[3]) + g_snprintf(buf, sizeof(buf), "KICK %s %s :%s", who, word[2], word_eol[3]); + else + g_snprintf(buf, sizeof(buf), "KICK %s %s", who, word[2]); + irc_write(id->fd, buf, strlen(buf)); + } else if (!g_strcasecmp(pdibuf, "BAN")) { + } else if (!g_strcasecmp(pdibuf, "KICKBAN")) { + } else if (!g_strcasecmp(pdibuf, "JOIN")) { + if (!*word[2]) + return; + if (*word[3]) + g_snprintf(buf, sizeof(buf), "JOIN %s %s\r\n", word[2], word[3]); + else + g_snprintf(buf, sizeof(buf), "JOIN %s\r\n", word[2]); + irc_write(id->fd, buf, strlen(buf)); + } else if (!g_strcasecmp(pdibuf, "PART")) { + char *chan = *word[2] ? word[2] : who; + char *reason = word_eol[3]; + struct conversation *c; + if (!is_channel(gc, chan)) + return; + c = irc_find_chat(gc, chan); + g_snprintf(buf, sizeof(buf), "PART %s%s%s\r\n", chan, + *reason ? " :" : "", + *reason ? reason : ""); + irc_write(id->fd, buf, strlen(buf)); + if (c) { + gc->buddy_chats = g_slist_remove(gc->buddy_chats, c); + c->gc = NULL; + g_snprintf(buf, sizeof(buf), _("You have left %s"), chan); + do_error_dialog(buf, _("IRC Part")); + } + } } -static GList *irc_buddy_menu(struct gaim_connection *gc, char *who) +static void send_msg(struct gaim_connection *gc, char *who, char *what) +{ + char *cr = strchr(what, '\n'); + if (cr) { + while (TRUE) { + if (cr) + *cr = 0; + handle_command(gc, who, what); + if (!cr) + break; + what = cr + 1; + if (!*what) + break; + cr = strchr(what, '\n'); + } + } else + handle_command(gc, who, what); +} + +static int irc_send_im(struct gaim_connection *gc, char *who, char *what, int flags) +{ + if (*who == '@' || *who == '+') + send_msg(gc, who + 1, what); + else + send_msg(gc, who, what); + return 0; +} + +/* IRC doesn't have a buddy list, but we can still figure out who's online with ISON */ +static void irc_fake_buddy(struct gaim_connection *gc, char *who) {} + +static GList *irc_chat_info(struct gaim_connection *gc) { GList *m = NULL; - struct proto_buddy_menu *pbm; + struct proto_chat_entry *pce; - pbm = g_new0(struct proto_buddy_menu, 1); - pbm->label = _("Ping"); - pbm->callback = irc_send_ping; - pbm->gc = gc; - m = g_list_append(m, pbm); + pce = g_new0(struct proto_chat_entry, 1); + pce->label = _("Room:"); + m = g_list_append(m, pce); - pbm = g_new0(struct proto_buddy_menu, 1); - pbm->label = _("Whois"); - pbm->callback = irc_get_info; - pbm->gc = gc; - m = g_list_append(m, pbm); + pce = g_new0(struct proto_chat_entry, 1); + pce->label = _("Password:"); + m = g_list_append(m, pce); return m; } +static void irc_join_chat(struct gaim_connection *gc, GList *data) +{ + struct irc_data *id = gc->proto_data; + char buf[IRC_BUF_LEN]; + char *name, *pass; + + if (!data) + return; + name = data->data; + if (data->next) + pass = data->next->data; + + if (data->next) + g_snprintf(buf, sizeof(buf), "JOIN %s %s\r\n", name, pass); + else + g_snprintf(buf, sizeof(buf), "JOIN %s\r\n", name); + irc_write(id->fd, buf, strlen(buf)); +} + +static void irc_chat_leave(struct gaim_connection *gc, int id) +{ + struct irc_data *idata = gc->proto_data; + struct conversation *c = irc_find_chat_by_id(gc, id); + char buf[IRC_BUF_LEN]; + + if (!c) return; + + g_snprintf(buf, sizeof(buf), "PART %s\r\n", c->name); + irc_write(idata->fd, buf, strlen(buf)); +} + +static int irc_chat_send(struct gaim_connection *gc, int id, char *what) +{ + struct conversation *c = irc_find_chat_by_id(gc, id); + if (!c) + return -EINVAL; + send_msg(gc, c->name, what); + serv_got_chat_in(gc, c->id, gc->displayname, 0, what, time(NULL)); + return 0; +} + +static GList *irc_away_states() +{ + return g_list_append(NULL, GAIM_AWAY_CUSTOM); +} static void irc_set_away(struct gaim_connection *gc, char *state, char *msg) { - struct irc_data *idata = (struct irc_data *)gc->proto_data; - char buf[BUF_LEN]; + struct irc_data *idata = gc->proto_data; + char buf[IRC_BUF_LEN]; if (msg) - g_snprintf(buf, BUF_LEN, "AWAY :%s\n", msg); + g_snprintf(buf, sizeof(buf), "AWAY :%s\r\n", msg); else - g_snprintf(buf, BUF_LEN, "AWAY\n"); - - write(idata->fd, buf, strlen(buf)); -} - -static void irc_fake_buddy(struct gaim_connection *gc, char *who) -{ - /* Heh, there is no buddy list. We fake it. - * I just need this here so the add and remove buttons will - * show up */ + g_snprintf(buf, sizeof(buf), "AWAY\r\n"); + irc_write(idata->fd, buf, strlen(buf)); } -static void irc_chat_set_topic(struct gaim_connection *gc, int id, char *topic) +static char **irc_list_icon(int uc) { - struct irc_channel *ic = NULL; - struct irc_data *idata = (struct irc_data *)gc->proto_data; - char buf[BUF_LEN]; - - ic = find_channel_by_id(gc, id); - - /* If we ain't in no channel, foo, gets outta da kitchen beeyotch */ - if (!ic) - return; - - /* Prepare our command */ - g_snprintf(buf, BUF_LEN, "TOPIC #%s :%s\n", ic->name, topic); - - /* And send it */ - write(idata->fd, buf, strlen(buf)); + return irc_icon_xpm; } static struct prpl *my_protocol = NULL; @@ -2087,21 +1258,19 @@ ret->protocol = PROTO_IRC; ret->options = OPT_PROTO_CHAT_TOPIC | OPT_PROTO_NO_PASSWORD; ret->name = irc_name; + ret->user_opts = irc_user_opts; ret->list_icon = irc_list_icon; - ret->buddy_menu = irc_buddy_menu; - ret->user_opts = irc_user_opts; ret->login = irc_login; ret->close = irc_close; ret->send_im = irc_send_im; + ret->add_buddy = irc_fake_buddy; + ret->remove_buddy = irc_fake_buddy; ret->chat_info = irc_chat_info; ret->join_chat = irc_join_chat; ret->chat_leave = irc_chat_leave; ret->chat_send = irc_chat_send; - ret->get_info = irc_get_info; + ret->away_states = irc_away_states; ret->set_away = irc_set_away; - ret->add_buddy = irc_fake_buddy; - ret->remove_buddy = irc_fake_buddy; - ret->chat_set_topic = irc_chat_set_topic; my_protocol = ret; }
--- a/src/protocols/jabber/jabber.c Sun Sep 16 18:30:44 2001 +0000 +++ b/src/protocols/jabber/jabber.c Mon Sep 17 05:00:56 2001 +0000 @@ -1517,7 +1517,17 @@ g_free(chatname); xmlnode_put_attrib(x, "type", "groupchat"); - if (message && strlen(message)) { + if (message && strlen(message) > strlen("/topic ") && + !g_strncasecmp(message, "/topic ", strlen("/topic "))) { + char buf[8192]; + char *utf8 = str_to_utf8(message + strlen("/topic ")); + y = xmlnode_insert_tag(x, "subject"); + xmlnode_insert_cdata(y, utf8, -1); + y = xmlnode_insert_tag(x, "body"); + g_snprintf(buf, sizeof(buf), "/me has changed the subject to: %s", utf8); + xmlnode_insert_cdata(y, buf, -1); + g_free(utf8); + } else if (message && strlen(message)) { char *utf8 = str_to_utf8(message); y = xmlnode_insert_tag(x, "body"); xmlnode_insert_cdata(y, utf8, -1); @@ -1529,56 +1539,6 @@ return 0; } -static void jabber_chat_set_topic(struct gaim_connection *gc, int id, char *topic) -{ - GSList *bcs = gc->buddy_chats; - struct conversation *b = NULL; - struct jabber_data *jd = gc->proto_data; - xmlnode x, y; - struct jabber_chat *jc = NULL; - char *chatname; - char buf[8192]; - - while (bcs) { - b = bcs->data; - if (id == b->id) - break; - bcs = bcs->next; - } - if (!bcs) - return; - - bcs = jd->existing_chats; - while (bcs) { - jc = bcs->data; - if (jc->b == b) - break; - bcs = bcs->next; - } - if (!bcs) - return; - - x = xmlnode_new_tag("message"); - xmlnode_put_attrib(x, "from", jid_full(jc->Jid)); - chatname = g_strdup_printf("%s@%s", jc->Jid->user, jc->Jid->server); - xmlnode_put_attrib(x, "to", chatname); - g_free(chatname); - xmlnode_put_attrib(x, "type", "groupchat"); - - if (topic && strlen(topic)) { - char *utf8 = str_to_utf8(topic); - y = xmlnode_insert_tag(x, "subject"); - xmlnode_insert_cdata(y, utf8, -1); - y = xmlnode_insert_tag(x, "body"); - g_snprintf(buf, sizeof(buf), "/me has changed the subject to: %s", utf8); - xmlnode_insert_cdata(y, buf, -1); - g_free(utf8); - } - - gjab_send(((struct jabber_data *)gc->proto_data)->jc, x); - xmlnode_free(x); -} - static void jabber_chat_whisper(struct gaim_connection *gc, int id, char *who, char *message) { GSList *bcs = gc->buddy_chats; @@ -1808,7 +1768,6 @@ ret->chat_invite = jabber_chat_invite; ret->chat_leave = jabber_chat_leave; ret->chat_whisper = jabber_chat_whisper; - ret->chat_set_topic = jabber_chat_set_topic; ret->chat_send = jabber_chat_send; ret->keepalive = jabber_keepalive; ret->normalize = jabber_normalize;
--- a/src/prpl.h Sun Sep 16 18:30:44 2001 +0000 +++ b/src/prpl.h Mon Sep 17 05:00:56 2001 +0000 @@ -129,7 +129,6 @@ void (* chat_whisper) (struct gaim_connection *, int id, char *who, char *message); int (* chat_send) (struct gaim_connection *, int id, char *message); void (* keepalive) (struct gaim_connection *); - void (* chat_set_topic) (struct gaim_connection *, int id, char *topic); void (* convo_closed) (struct gaim_connection *, char *who);
--- a/src/server.c Sun Sep 16 18:30:44 2001 +0000 +++ b/src/server.c Mon Sep 17 05:00:56 2001 +0000 @@ -315,12 +315,6 @@ (*g->prpl->chat_whisper)(g, id, who, message); } -void serv_chat_set_topic(struct gaim_connection *g, int id, char *topic) -{ - if (g->prpl && g->prpl->chat_set_topic) - (*g->prpl->chat_set_topic)(g, id, topic); -} - int serv_chat_send(struct gaim_connection *g, int id, char *message) { int val = -EINVAL;