comparison src/protocols/irc/irc.c @ 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 0b5c3338fa3d
children 23c06449ae8e
comparison
equal deleted inserted replaced
2288:b41c88001ab5 2289:38e156136896
21 */ 21 */
22 22
23 #include <config.h> 23 #include <config.h>
24 24
25 25
26 #include <netdb.h>
27 #include <unistd.h> 26 #include <unistd.h>
28 #include <errno.h> 27 #include <errno.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <fcntl.h>
32 #include <string.h> 28 #include <string.h>
33 #include <stdlib.h> 29 #include <stdlib.h>
34 #include <stdio.h> 30 #include <stdio.h>
35 #include <time.h> 31 #include <time.h>
36 #include <sys/socket.h>
37 #include <sys/stat.h> 32 #include <sys/stat.h>
38 #include <ctype.h> 33 #include <ctype.h>
39 #include "multi.h" 34 #include "multi.h"
40 #include "prpl.h" 35 #include "prpl.h"
41 #include "gaim.h" 36 #include "gaim.h"
42 #include "proxy.h" 37 #include "proxy.h"
43 38
44 #include "pixmaps/free_icon.xpm" 39 #include "pixmaps/irc_icon.xpm"
45 40
46 #define IRC_BUF_LEN 4096 41 #define IRC_BUF_LEN 4096
47 42 #define PDIWORDS 32
48 43
49 #define USEROPT_SERV 0 44 #define USEROPT_SERV 0
50 #define USEROPT_PORT 1 45 #define USEROPT_PORT 1
51 46
52 static int chat_id = 0;
53
54 struct irc_channel {
55 int id;
56 gchar *name;
57 };
58
59 struct irc_data { 47 struct irc_data {
60 int fd; 48 int fd;
61 int inpa; /* used for non-block logins */ 49 gboolean online;
62 50 guint32 timer;
63 int timer; 51
64 52 GString *str;
65 int totalblocks; 53 int bc;
66 int recblocks; 54
67 55 char *chantypes;
68 GSList *templist; 56 char *chanmodes;
69 GList *channels; 57 char *nickmodes;
58 gboolean six_modes;
70 }; 59 };
71 60
72 static char *irc_name() 61 static char *irc_name()
73 { 62 {
74 return "IRC"; 63 return "IRC";
75 } 64 }
76 65
77 static void irc_get_info(struct gaim_connection *gc, char *who); 66 static int irc_write(int fd, char *data, int len)
78 67 {
79 static GList *irc_chat_info(struct gaim_connection *gc) 68 debug_printf("IRC C: %s", data);
80 { 69 return write(fd, data, len);
81 GList *m = NULL; 70 }
82 struct proto_chat_entry *pce; 71
83 72 static struct conversation *irc_find_chat(struct gaim_connection *gc, char *name)
84 pce = g_new0(struct proto_chat_entry, 1); 73 {
85 pce->label = _("Room:"); 74 GSList *bcs = gc->buddy_chats;
86 m = g_list_append(m, pce); 75
87 76 while (bcs) {
88 return m; 77 struct conversation *b = bcs->data;
89 } 78 if (!strcmp(b->name, name))
90 79 return b;
91 static void irc_join_chat(struct gaim_connection *gc, GList *data) 80 bcs = bcs->next;
92 { 81 }
93 struct irc_data *idata = (struct irc_data *)gc->proto_data; 82 return NULL;
94 gchar *buf, *name; 83 }
95 84
96 if (!data) 85 static struct conversation *irc_find_chat_by_id(struct gaim_connection *gc, int id)
86 {
87 GSList *bcs = gc->buddy_chats;
88
89 while (bcs) {
90 struct conversation *b = bcs->data;
91 if (b->id == id)
92 return b;
93 bcs = bcs->next;
94 }
95 return NULL;
96 }
97
98 static void process_data_init(char *buf, char *cmd, char *word[], char *eol[], gboolean quotes)
99 {
100 int wordcount = 2;
101 gboolean space = FALSE;
102 gboolean quote = FALSE;
103 int j = 0;
104
105 word[1] = cmd;
106 eol[1] = buf;
107
108 while (TRUE) {
109 switch (*cmd) {
110 case 0:
111 buf[j] = 0;
112 for (j = wordcount; j < PDIWORDS; j++) {
113 word[j] = "\000\000";
114 eol[j] = "\000\000";
115 }
116 return;
117 case '"':
118 if (!quotes) {
119 space = FALSE;
120 buf[j++] = *cmd;
121 break;
122 }
123 quote = !quote;
124 break;
125 case ' ':
126 if (quote) {
127 space = FALSE;
128 buf[j++] = *cmd;
129 break;
130 }
131 if (space)
132 break;
133 buf[j++] = 0;
134 word[wordcount] = &buf[j];
135 eol[wordcount++] = cmd + 1;
136 if (wordcount == PDIWORDS - 1)
137 *cmd-- = 0;
138 space = TRUE;
139 break;
140 default:
141 space = FALSE;
142 buf[j++] = *cmd;
143 }
144 cmd++;
145 }
146 }
147
148 static void handle_005(struct gaim_connection *gc, char *word[], char *word_eol[])
149 {
150 int w = 4;
151 struct irc_data *id = gc->proto_data;
152
153 while (w < PDIWORDS && *word[w]) {
154 if (!strncmp(word[w], "MODES=", 5)) {
155 if (atoi(word[w] + 6) >= 6)
156 id->six_modes = TRUE;
157 } else if (!strncmp(word[w], "CHANTYPES=", 10)) {
158 g_free(id->chantypes);
159 id->chantypes = g_strdup(word[w] + 10);
160 } else if (!strncmp(word[w], "CHANMODES=", 10)) {
161 g_free(id->chanmodes);
162 id->chanmodes = g_strdup(word[w] + 10);
163 } else if (!strncmp(word[w], "PREFIX=", 7)) {
164 char *pre = strchr(word[w] + 7, ')');
165 if (pre) {
166 *pre = 0;
167 g_free(id->nickmodes);
168 id->nickmodes = g_strdup(word[w] + 8);
169 }
170 }
171 w++;
172 }
173 }
174
175 static char *int_to_col(int c)
176 {
177 switch(c) {
178 case 1:
179 return "#ffffff";
180 case 2:
181 return "#000066";
182 case 3:
183 return "#006600";
184 case 4:
185 return "#ff0000";
186 case 5:
187 return "#660000";
188 case 6:
189 return "#660066";
190 case 7:
191 return "#666600";
192 case 8:
193 return "#cccc00";
194 case 9:
195 return "#33cc33";
196 case 10:
197 return "#00acac";
198 case 11:
199 return "#00ccac";
200 case 12:
201 return "#0000ff";
202 case 13:
203 return "#cc00cc";
204 case 14:
205 return "#666666";
206 case 15:
207 return "#00ccac";
208 default:
209 return "#000000";
210 }
211 }
212
213 static GString *decode_html(char *msg)
214 {
215 GString /* oo la la */ *str = g_string_new("");
216 char *cur = msg, *end = msg;
217 gboolean bold = FALSE, underline = FALSE, fg = FALSE, bg = FALSE;
218 int fore, back;
219 while (*end) {
220 switch (*end) {
221 case 02: /* ^B */
222 *end = 0;
223 str = g_string_append(str, cur);
224 if (bold)
225 str = g_string_append(str, "</B>");
226 else
227 str = g_string_append(str, "<B>");
228 bold = !bold;
229 cur = end + 1;
230 break;
231 case 03: /* ^C */
232 *end++ = 0;
233 str = g_string_append(str, cur);
234 fore = back = -1;
235 if (isdigit(*end)) {
236 fore = *end++ - '0';
237 if (isdigit(*end)) {
238 fore *= 10;
239 fore += *end++ - '0';
240 }
241 if (*end == ',' && isdigit(end[1])) {
242 end++;
243 back = *end++ - '0';
244 if (isdigit(*end)) {
245 back *= 10;
246 back += *end++ - '0';
247 }
248 }
249 }
250 if (fore == -1) {
251 if (fg)
252 str = g_string_append(str, "</FONT>");
253 if (bg)
254 str = g_string_append(str, "</FONT>");
255 fg = bg = FALSE;
256 } else {
257 fore %= 16;
258 if (fg)
259 str = g_string_append(str, "</FONT>");
260 if (back != -1) {
261 if (bg)
262 str = g_string_append(str, "</FONT>");
263 back %= 16;
264 str = g_string_append(str, "<FONT BACK=");
265 str = g_string_append(str, int_to_col(back));
266 str = g_string_append_c(str, '>');
267 bg = TRUE;
268 }
269 str = g_string_append(str, "<FONT COLOR=");
270 str = g_string_append(str, int_to_col(fore));
271 str = g_string_append_c(str, '>');
272 fg = TRUE;
273 }
274 cur = end--;
275 break;
276 case 017: /* ^O */
277 if (!bold && !underline && !fg && !bg)
278 break;
279 *end = 0;
280 str = g_string_append(str, cur);
281 if (bold)
282 str = g_string_append(str, "</B>");
283 if (underline)
284 str = g_string_append(str, "</U>");
285 if (fg)
286 str = g_string_append(str, "</FONT>");
287 if (bg)
288 str = g_string_append(str, "</FONT>");
289 bold = underline = fg = bg = FALSE;
290 cur = end + 1;
291 break;
292 case 037: /* ^_ */
293 *end = 0;
294 str = g_string_append(str, cur);
295 if (underline)
296 str = g_string_append(str, "</U>");
297 else
298 str = g_string_append(str, "<U>");
299 underline = !underline;
300 cur = end + 1;
301 break;
302 }
303 end++;
304 }
305 if (*cur)
306 str = g_string_append(str, cur);
307 return str;
308 }
309
310 static void irc_got_im(struct gaim_connection *gc, char *who, char *what, int flags, time_t t)
311 {
312 GString *str = decode_html(what);
313 serv_got_im(gc, who, str->str, flags, t);
314 g_string_free(str, TRUE);
315 }
316
317 static void irc_got_chat_in(struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t t)
318 {
319 GString *str = decode_html(msg);
320 serv_got_chat_in(gc, id, who, whisper, str->str, t);
321 g_string_free(str, TRUE);
322 }
323
324 static void handle_list(struct gaim_connection *gc, char *list)
325 {
326 struct irc_data *id = gc->proto_data;
327 GSList *gr;
328
329 id->str = g_string_append_c(id->str, ' ');
330 id->str = g_string_append(id->str, list);
331 id->bc--;
332 if (id->bc)
97 return; 333 return;
98 name = data->data; 334
99 335 g_strdown(id->str->str);
100 buf = (gchar *) g_malloc(IRC_BUF_LEN + 1); 336 gr = gc->groups;
101 337 while (gr) {
102 g_snprintf(buf, IRC_BUF_LEN, "JOIN %s\n", name); 338 GSList *m = ((struct group *)gr->data)->members;
103 write(idata->fd, buf, strlen(buf)); 339 while (m) {
104 write(idata->fd, buf, strlen(buf)); 340 struct buddy *b = m->data;
105 341 char *tmp = g_strdup(b->name);
106 g_free(buf); 342 g_strdown(tmp);
107 } 343 if (strstr(id->str->str, tmp))
108 344 serv_got_update(gc, b->name, 1, 0, 0, 0, 0, 0);
109 static void irc_update_user(struct gaim_connection *gc, char *name, int status) 345 else
110 { 346 serv_got_update(gc, b->name, 0, 0, 0, 0, 0, 0);
111 struct irc_data *idata = (struct irc_data *)gc->proto_data; 347 g_free(tmp);
112 struct irc_channel *u; 348 m = m->next;
113 GSList *temp = idata->templist; 349 }
114 350 gr = gr->next;
115 /* Loop through our list */ 351 }
116 352 g_string_free(id->str, TRUE);
117 while (temp) { 353 id->str = g_string_new("");
118 u = (struct irc_channel *)temp->data;
119 if (g_strcasecmp(u->name, name) == 0) {
120 u->id = status;
121 return;
122 }
123
124 temp = g_slist_next(temp);
125 }
126 return;
127 } 354 }
128 355
129 static gboolean irc_request_buddy_update(gpointer data) 356 static gboolean irc_request_buddy_update(gpointer data)
130 { 357 {
131 struct gaim_connection *gc = data; 358 struct gaim_connection *gc = data;
132 struct irc_data *idata = (struct irc_data *)gc->proto_data; 359 struct irc_data *id = gc->proto_data;
133 GSList *grp = gc->groups; 360 char buf[500];
134 GSList *person; 361 int n = g_snprintf(buf, sizeof(buf), "ISON");
135 struct group *g; 362
136 struct buddy *b; 363 GSList *gr = gc->groups;
137 struct irc_channel *u; 364 if (!gr || id->bc)
138
139 if (idata->templist != NULL)
140 return TRUE; 365 return TRUE;
141 366
142 idata->recblocks = 0; 367 while (gr) {
143 idata->totalblocks = 1; 368 struct group *g = gr->data;
144 369 GSList *m = g->members;
145 /* First, let's check to see if we have anyone on our buddylist */ 370 while (m) {
146 if (!grp) { 371 struct buddy *b = m->data;
372 if (n + strlen(b->name) + 2 > sizeof(buf)) {
373 g_snprintf(buf + n, sizeof(buf) - n, "\r\n");
374 irc_write(id->fd, buf, n);
375 id->bc++;
376 n = g_snprintf(buf, sizeof(buf), "ISON");
377 }
378 n += g_snprintf(buf + n, sizeof(buf) - n, " %s", b->name);
379 m = m->next;
380 }
381 gr = gr->next;
382 }
383 g_snprintf(buf + n, sizeof(buf) - n, "\r\n");
384 irc_write(id->fd, buf, strlen(buf));
385 id->bc++;
386 return TRUE;
387 }
388
389 static void handle_names(struct gaim_connection *gc, char *chan, char *names)
390 {
391 struct conversation *c = irc_find_chat(gc, chan);
392 char **buf, **tmp;
393 if (!c) return;
394 if (*names == ':') names++;
395 buf = g_strsplit(names, " ", -1);
396 for (tmp = buf; *tmp; tmp++)
397 add_chat_buddy(c, *tmp);
398 g_strfreev(buf);
399 }
400
401 static void handle_topic(struct gaim_connection *gc, char *text)
402 {
403 struct conversation *c;
404 char *po = strchr(text, ' ');
405
406 if (!po)
407 return;
408
409 *po = 0;
410 po += 2;
411
412 if ((c = irc_find_chat(gc, text)))
413 chat_set_topic(c, NULL, po);
414 }
415
416 static gboolean mode_has_arg(struct gaim_connection *gc, char sign, char mode)
417 {
418 struct irc_data *id = gc->proto_data;
419 char *cm = id->chanmodes;
420 int type = 0;
421
422 if (strchr(id->nickmodes, mode))
147 return TRUE; 423 return TRUE;
148 } 424
149 425 while (*cm) {
150 /* Send the first part of our request */ 426 if (*cm == ',')
151 write(idata->fd, "ISON", 4); 427 type++;
152 428 else if (*cm == mode) {
153 /* Step through our list of groups */ 429 switch (type) {
154 while (grp) { 430 case 0:
155 431 case 1:
156 g = (struct group *)grp->data; 432 return TRUE;
157 person = g->members; 433 case 2:
158 434 if (sign == '+')
159 while (person) { 435 return TRUE;
160 b = (struct buddy *)person->data; 436 case 3:
161 437 return FALSE;
162 /* We will store our buddy info here. I know, this is cheap 438 }
163 * but hey, its the exact same data structure. Why should we 439 }
164 * bother with making another one */ 440 cm++;
165 441 }
166 u = g_new0(struct irc_channel, 1); 442
167 u->id = 0; /* Assume by default that they're offline */ 443 return FALSE;
168 u->name = strdup(b->name); 444 }
169 445
170 write(idata->fd, " ", 1); 446 static void irc_user_mode(struct gaim_connection *gc, char *room, char sign, char mode, char *nick)
171 write(idata->fd, u->name, strlen(u->name)); 447 {
172 idata->templist = g_slist_append(idata->templist, u); 448 struct conversation *c = irc_find_chat(gc, room);
173 449 GList *r;
174 person = person->next; 450
175 } 451 if (mode != 'o' && mode != 'v')
176 452 return;
177 grp = g_slist_next(grp); 453
178 } 454 if (!c)
179 write(idata->fd, "\n", 1); 455 return;
180 return TRUE; 456
181 } 457 r = c->in_room;
182 458 while (r) {
183 459 gboolean op = FALSE, voice = FALSE;
184 static int irc_send_im(struct gaim_connection *gc, char *who, char *message, int flags) 460 char *who = r->data;
185 { 461 if (*who == '@') {
186 462 op = TRUE;
187 struct irc_data *idata = (struct irc_data *)gc->proto_data; 463 who++;
188 gchar *buf = (gchar *) g_malloc(IRC_BUF_LEN + 1); 464 }
189 465 if (*who == '+') {
190 if (who[0] == '@' || who[0] == '+') { 466 voice = TRUE;
191 467 who++;
192 /* If the user trys to msg an op or a voice from the channel, the convo will try 468 }
193 * to send it to @nick or +nick... needless to say, this is undesirable. 469 if (!strcmp(who, nick)) {
194 */ 470 char *tmp, buf[IRC_BUF_LEN];
195 who++; 471 if (mode == 'o') {
196 } 472 if (sign == '-')
197 473 op = FALSE;
198 /* Before we actually send this, we should check to see if they're trying 474 else
199 * To issue a command and handle it properly. */ 475 op = TRUE;
200 476 }
201 if (message[0] == '/') { 477 if (mode == 'v') {
202 /* I'll change the implementation of this a little later :-) */ 478 if (sign == '-')
203 if ((g_strncasecmp(message, "/me ", 4) == 0) && (strlen(message) > 4)) { 479 voice = FALSE;
204 /* We have /me!! We have /me!! :-) */ 480 else
205 481 voice = TRUE;
206 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); 482 }
207 strcpy(temp, message + 4); 483 tmp = g_strdup(r->data);
208 g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG %s :%cACTION %s%c\n", who, '\001', temp, 484 g_snprintf(buf, sizeof(buf), "%s%s%s", op ? "@" : "",
209 '\001'); 485 voice ? "+" : "", nick);
210 g_free(temp); 486 rename_chat_buddy(c, tmp, buf);
211 } else if (!g_strncasecmp(message, "/whois ", 7) && (strlen(message) > 7)) { 487 g_free(tmp);
212 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); 488 return;
213 strcpy(temp, message + 7); 489 }
214 irc_get_info(gc, temp); 490 r = r->next;
215 g_free(temp); 491 }
216 492 }
217 return 0; 493
218 } 494 static void handle_mode(struct gaim_connection *gc, char *word[], char *word_eol[], gboolean n324)
219 495 {
220 } else { 496 struct irc_data *id = gc->proto_data;
221 g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG %s :%s\n", who, message); 497 int offset = n324 ? 4 : 3;
222 } 498 char *chan = word[offset];
223 499 struct conversation *c = irc_find_chat(gc, chan);
224 write(idata->fd, buf, strlen(buf)); 500 char *modes = word[offset + 1];
225 501 int len = strlen(word_eol[offset]) - 1;
226 g_free(buf); 502 char sign = *modes++;
227 return 0; 503 int arg = 1;
228 } 504 char *argstr;
229 505
230 static int find_id_by_name(struct gaim_connection *gc, char *name) 506 if (!c)
231 { 507 return;
232 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); 508
233 GList *templist; 509 if (word_eol[offset][len] == ' ')
234 struct irc_channel *channel; 510 word_eol[offset][len] = 0;
235 511
236 templist = ((struct irc_data *)gc->proto_data)->channels; 512 while (TRUE) {
237 513 switch (*modes) {
238 while (templist) { 514 case 0:
239 channel = (struct irc_channel *)templist->data; 515 return;
240 516 case '+':
241 g_snprintf(temp, IRC_BUF_LEN, "#%s", channel->name); 517 case '-':
242 518 sign = *modes;
243 if (g_strcasecmp(temp, name) == 0) { 519 break;
244 g_free(temp); 520 default:
245 return channel->id; 521 if (mode_has_arg(gc, sign, *modes))
246 } 522 argstr = word[++arg + offset];
247 523 else
248 templist = templist->next; 524 argstr = "";
249 } 525 if (strchr(id->nickmodes, *modes))
250 526 irc_user_mode(gc, chan, sign, *modes, argstr);
251 g_free(temp); 527 }
252 528 modes++;
253 /* Return -1 if we have no ID */ 529 }
254 return -1; 530 }
255 } 531
256 532 static void process_numeric(struct gaim_connection *gc, char *word[], char *word_eol[])
257 static struct irc_channel *find_channel_by_name(struct gaim_connection *gc, char *name) 533 {
258 { 534 struct irc_data *id = gc->proto_data;
259 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1); 535 char *text = word_eol[3];
260 GList *templist; 536 int n = atoi(word[2]);
261 struct irc_channel *channel; 537
262 538 if (!g_strncasecmp(gc->displayname, text, strlen(gc->displayname)))
263 templist = ((struct irc_data *)gc->proto_data)->channels; 539 text += strlen(gc->displayname) + 1;
264 540 if (*text == ':')
265 while (templist) { 541 text++;
266 channel = (struct irc_channel *)templist->data; 542
267 543 switch (n) {
268 g_snprintf(temp, IRC_BUF_LEN, "%s", channel->name); 544 case 4:
269 545 if (!strncmp(word[5], "u2.10", 5))
270 if (g_strcasecmp(temp, name) == 0) { 546 id->six_modes = TRUE;
271 g_free(temp); 547 else
272 return channel; 548 id->six_modes = FALSE;
273 } 549 break;
274 550 case 5:
275 templist = templist->next; 551 handle_005(gc, word, word_eol);
276 } 552 break;
277 553 case 301:
278 g_free(temp); 554 irc_got_im(gc, word[4], word[5], IM_FLAG_AWAY, time(NULL));
279 555 break;
280 /* If we found nothing, return nothing :-) */ 556 case 303:
281 return NULL; 557 handle_list(gc, &word_eol[4][1]);
282 } 558 break;
283 559 case 324:
284 static struct irc_channel *find_channel_by_id(struct gaim_connection *gc, int id) 560 handle_mode(gc, word, word_eol, TRUE);
285 { 561 break;
286 struct irc_data *idata = (struct irc_data *)gc->proto_data; 562 case 332:
287 struct irc_channel *channel; 563 handle_topic(gc, text);
288 564 break;
289 GList *temp; 565 case 353:
290 566 handle_names(gc, word[5], word_eol[6]);
291 temp = idata->channels; 567 break;
292 568 case 376:
293 while (temp) { 569 irc_request_buddy_update(gc);
294 channel = (struct irc_channel *)temp->data; 570 break;
295 571 }
296 if (channel->id == id) { 572 }
297 /* We've found our man */ 573
298 return channel; 574 static gboolean is_channel(struct gaim_connection *gc, char *name)
299 } 575 {
300 576 struct irc_data *id = gc->proto_data;
301 temp = temp->next; 577 if (strchr(id->chantypes, *name))
302 } 578 return TRUE;
303 579 return FALSE;
304 580 }
305 /* If we didnt find one, return NULL */ 581
306 return NULL; 582 static void irc_rem_chat_bud(struct gaim_connection *gc, char *nick)
307 }
308
309 static struct conversation *find_chat(struct gaim_connection *gc, char *name)
310 { 583 {
311 GSList *bcs = gc->buddy_chats; 584 GSList *bcs = gc->buddy_chats;
312 struct conversation *b = NULL;
313 char *chat = g_strdup(normalize(name));
314 585
315 while (bcs) { 586 while (bcs) {
316 b = bcs->data; 587 struct conversation *b = bcs->data;
317 if (!strcasecmp(normalize(b->name), chat)) 588
318 break; 589 GList *r = b->in_room;
319 b = NULL; 590 while (r) {
591 char *who = r->data;
592 if (*who == '@')
593 who++;
594 if (*who == '+')
595 who++;
596 if (!g_strcasecmp(who, nick)) {
597 char *tmp = g_strdup(r->data);
598 remove_chat_buddy(b, r->data);
599 g_free(tmp);
600 break;
601 }
602 r = r->next;
603 }
320 bcs = bcs->next; 604 bcs = bcs->next;
321 } 605 }
322 606 }
323 g_free(chat); 607
324 return b; 608 static void irc_change_name(struct gaim_connection *gc, char *old, char *new)
325 } 609 {
326 610 GSList *bcs = gc->buddy_chats;
327 static void irc_chat_leave(struct gaim_connection *gc, int id); 611 char buf[IRC_BUF_LEN];
328 static int irc_chat_send(struct gaim_connection *gc, int id, char *message) 612 int n = 0;
329 { 613
330 614 while (bcs) {
331 struct irc_data *idata = (struct irc_data *)gc->proto_data; 615 struct conversation *b = bcs->data;
332 struct irc_channel *channel = NULL; 616
333 gchar *buf = (gchar *) g_malloc(IRC_BUF_LEN + 1); 617 GList *r = b->in_room;
334 char **kick; 618 while (r) {
335 gboolean is_command = FALSE; 619 char *who = r->data;
336 /* First lets get our current channel */ 620 if (*who == '@')
337 channel = find_channel_by_id(gc, id); 621 buf[n++] = *who++;
338 622 if (*who == '+')
339 623 buf[n++] = *who++;
340 if (!channel) { 624 g_snprintf(buf + n, sizeof(buf) - n, "%s", new);
341 /* If for some reason we've lost our channel, let's bolt */ 625 if (!g_strcasecmp(who, old)) {
342 g_free(buf); 626 char *tmp = g_strdup(r->data);
343 return -EINVAL; 627 rename_chat_buddy(b, tmp, buf);
344 } 628 r = b->in_room;
345 629 g_free(tmp);
346 630 } else
347 /* Before we actually send this, we should check to see if they're trying 631 r = r->next;
348 * To issue a command and handle it properly. */ 632 }
349 633 bcs = bcs->next;
350 if (message[0] == '/') { 634 }
351 635 }
352 if ((g_strncasecmp(message, "/me ", 4) == 0) && (strlen(message) > 4)) {
353 /* We have /me!! We have /me!! :-) */
354
355 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
356 strcpy(temp, message + 4);
357
358 g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG #%s :%cACTION %s%c\n", channel->name,
359 '\001', temp, '\001');
360 g_free(temp);
361 } else if ((g_strncasecmp(message, "/op ", 4) == 0) && (strlen(message) > 4)) {
362 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
363 strcpy(temp, message + 4);
364
365 g_snprintf(buf, IRC_BUF_LEN, "MODE #%s +o %s\n", channel->name, temp);
366
367 g_free(temp);
368 is_command = TRUE;
369
370 } else if ((g_strncasecmp(message, "/deop ", 6) == 0) && (strlen(message) > 6)) {
371 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
372 strcpy(temp, message + 6);
373 g_snprintf(buf, IRC_BUF_LEN, "MODE #%s -o %s\n", channel->name, temp);
374
375 g_free(temp);
376 is_command = TRUE;
377 }
378
379 else if ((g_strncasecmp(message, "/voice ", 7) == 0) && (strlen(message) > 7)) {
380 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
381 strcpy(temp, message + 7);
382
383 g_snprintf(buf, IRC_BUF_LEN, "MODE #%s +v %s\n", channel->name, temp);
384
385 g_free(temp);
386 is_command = TRUE;
387
388 } else if ((g_strncasecmp(message, "/devoice ", 9) == 0) && (strlen(message) > 9)) {
389 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
390 strcpy(temp, message + 6);
391 g_snprintf(buf, IRC_BUF_LEN, "MODE #%s -v %s\n", channel->name, temp);
392
393 g_free(temp);
394 is_command = TRUE;
395 } else if ((g_strncasecmp(message, "/mode ", 6) == 0) && (strlen(message) > 6)) {
396 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
397 strcpy(temp, message + 6);
398 g_snprintf(buf, IRC_BUF_LEN, "MODE #%s %s\n", channel->name, temp);
399 g_free(temp);
400 is_command = TRUE;
401 }
402
403 else if (!g_strncasecmp(message, "/whois ", 7) && (strlen(message) > 7)) {
404 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
405
406 strcpy(temp, message + 7);
407 irc_get_info(gc, temp);
408 g_free(temp);
409 is_command = TRUE;
410
411 }
412
413 else if (!g_strncasecmp(message, "/topic ", 7) && (strlen(message) > 7)) {
414 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
415 strcpy(temp, message + 7);
416
417 /* Send the chat topic change request */
418 serv_chat_set_topic(gc, id, temp);
419
420 g_free(temp);
421 is_command = TRUE;
422 }
423
424 else if (!g_strncasecmp(message, "/part", 5) && (strlen(message) == 5)) {
425
426 /* If I'm not mistaken, the chat_leave command was coded under the
427 * pretense that it would only occur when someone closed the window.
428 * For this reason, the /part command will not close the window. Nor
429 * will the window close when the user is /kicked. I'll let you decide
430 * the best way to fix it--I'd imagine it'd just be a little line like
431 * if (convo) close (convo), but I'll let you decide where to put it.
432 */
433
434 irc_chat_leave(gc, id);
435 is_command = TRUE;
436 return 0;
437
438
439 }
440
441 else if (!g_strncasecmp(message, "/join ", 6) && (strlen(message) > 6)) {
442
443 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
444 GList *m = g_list_append(NULL, temp);
445
446 strcpy(temp, message + 6);
447
448
449 irc_join_chat(gc, m);
450 g_free(temp);
451 g_list_free(m);
452 is_command = TRUE;
453 return 0;
454 }
455
456 else if (!g_strncasecmp(message, "/raw ", 5) && (strlen(message) > 5)) {
457 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
458 strcpy(temp, message + 5);
459 g_snprintf(buf, IRC_BUF_LEN, "%s\r\n", temp);
460 g_free(temp);
461 is_command = TRUE;
462 }
463
464 else if (!g_strncasecmp(message, "/quote ", 7) && (strlen(message) > 7)) {
465 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
466 strcpy(temp, message + 7);
467 g_snprintf(buf, IRC_BUF_LEN, "%s\r\n", temp);
468 g_free(temp);
469 is_command = TRUE;
470 }
471
472 else if (!g_strncasecmp(message, "/kick ", 6) && (strlen(message) > 6)) {
473 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
474 strcpy(temp, message + 6);
475 kick = g_strsplit(temp, " ", 2);
476 g_snprintf(buf, IRC_BUF_LEN, "KICK #%s %s :%s\r\n", channel->name, kick[0],
477 kick[1]);
478 g_free(temp);
479 is_command = TRUE;
480 }
481
482 /* FIXME: I'll go back in and grab this later. -- Rob */
483 /*
484 I THOUGHT THIS WOULD WORK, BUT I WAS WRONG. WOULD SOMEONE KINDLY FIX IT?
485
486
487 else if (!g_strncasecmp(message, "/help", 5)) {
488 gchar *temp = (gchar *) g_malloc(IRC_BUF_LEN + 1);
489 strcpy(temp, message + 5);
490 if (temp == "") {
491
492 serv_got_chat_in(gc, id, "gAIM", 0, "Available Commands:");
493 serv_got_chat_in(gc, id, "gAIM", 0, " ");
494 serv_got_chat_in(gc, id, "gAIM", 0, "<b>op voice kick </b>");
495 serv_got_chat_in(gc, id, "gAIM", 0, "<b>deop devoice whois</b>");
496 serv_got_chat_in(gc, id, "gAIM", 0, "<b>me raw quote</b>");
497 serv_got_chat_in(gc, id, "gAIM", 0, "<b>mode</b>");
498 }
499 else {
500 serv_got_chat_in(gc, id, "gAIM", 0, "Usage: ");
501 if (temp == "op")
502 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/op <nick></b> - Gives operator status to user.");
503 else if (temp == "deop")
504 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/deop <nick></b> - Removes operator status from user.");
505 else if (temp == "me")
506 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/me <action></b> - Sends an action to the channel.");
507 else if (temp == "mode")
508 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.");
509 else if (temp == "voice")
510 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/voice <nick></b> - Gives voice status to user.");
511 else if (temp == "devoice")
512 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/devoice <nick></b> - Removes voice status from user.");
513 else if (temp == "raw")
514 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/raw <text></b> - Sends raw text to the server.");
515 else if (temp == "kick")
516 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/kick [<comment>]</b> - Kicks a user out of the channel.");
517 else if (temp == "whois")
518 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/whois <nick></b> - Gets information about user.");
519 else if (temp == "quote")
520 serv_got_chat_in(gc, id, "gAIM", 0, "<b>/raw <text></b> - Sends raw text to the server.");
521 else
522 serv_got_chat_in(gc, id, "gAIM", 0, "No such command.");
523 }
524
525 g_free(temp);
526 is_command = TRUE;
527 }
528 */
529
530 }
531
532 else {
533 g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG #%s :%s\n", channel->name, message);
534
535 }
536
537
538 write(idata->fd, buf, strlen(buf));
539
540 /* Since AIM expects us to receive the message we send, we gotta fake it */
541 if (is_command == FALSE)
542 serv_got_chat_in(gc, id, gc->username, 0, message, time((time_t) NULL));
543
544 g_free(buf);
545
546 return 0;
547 }
548
549 static struct conversation *find_conversation_by_id(struct gaim_connection *gc, int id)
550 {
551 GSList *bc = gc->buddy_chats;
552 struct conversation *b = NULL;
553
554 while (bc) {
555 b = (struct conversation *)bc->data;
556 if (id == b->id) {
557 break;
558 }
559 bc = bc->next;
560 b = NULL;
561 }
562
563 if (!b) {
564 return NULL;
565 }
566
567 return b;
568 }
569
570 static struct conversation *find_conversation_by_name(struct gaim_connection *gc, char *name)
571 {
572 GSList *bc = gc->buddy_chats;
573 struct conversation *b = NULL;
574
575 while (bc) {
576 b = (struct conversation *)bc->data;
577
578 if (g_strcasecmp(name, b->name) == 0) {
579 break;
580 }
581 bc = bc->next;
582 b = NULL;
583 }
584
585 if (!b) {
586 return NULL;
587 }
588
589 return b;
590 }
591
592
593 636
594 static void irc_callback(gpointer data, gint source, GaimInputCondition condition) 637 static void irc_callback(gpointer data, gint source, GaimInputCondition condition)
595 { 638 {
596 struct gaim_connection *gc = data; 639 struct gaim_connection *gc = data;
640 struct irc_data *idata = gc->proto_data;
597 int i = 0; 641 int i = 0;
598 gchar buf[4096]; 642 gchar d[IRC_BUF_LEN], *buf = d;
599 gchar **buf2; 643 gchar outbuf[IRC_BUF_LEN];
600 struct irc_data *idata; 644 char *word[PDIWORDS], *word_eol[PDIWORDS];
601 645 char pdibuf[522];
602 idata = (struct irc_data *)gc->proto_data; 646 char *ex, ip[128], nick[128];
603 647 char *cmd;
648
649 if (!idata->online) {
650 /* Now lets sign ourselves on */
651 account_online(gc);
652 serv_finish_login(gc);
653
654 if (bud_list_cache_exists(gc))
655 do_import(NULL, gc);
656
657 /* we don't call this now because otherwise some IRC servers might not like us */
658 idata->timer = g_timeout_add(20000, irc_request_buddy_update, gc);
659 idata->online = TRUE;
660 }
604 661
605 do { 662 do {
606 if (read(idata->fd, buf + i, 1) < 0) { 663 if (read(idata->fd, buf + i, 1) <= 0) {
607 hide_login_progress(gc, "Read error"); 664 hide_login_progress(gc, "Read error");
608 signoff(gc); 665 signoff(gc);
609 return; 666 return;
610 } 667 }
611 } while (buf[i++] != '\n'); 668 } while (buf[i++] != '\n');
612 669
613 buf[--i] = '\0'; 670 buf[--i] = '\0';
614 g_strchomp(buf); 671 g_strchomp(buf);
615 g_print("%s\n", buf); 672 debug_printf("IRC S: %s\n", buf);
616 673
617 /* Check for errors */ 674 /* Check for errors */
618 675
619 if (((strstr(buf, "ERROR :") && (!strstr(buf, "PRIVMSG ")) && 676 if (*buf != ':') {
620 (!strstr(buf, "NOTICE ")) && (strlen(buf) > 7)))) { 677 if (!strncmp(buf, "NOTICE ", 7))
621 678 buf += 7;
622 /* 679 if (!strncmp(buf, "PING ", 5)) {
623 * The ERROR command is for use by servers when reporting a serious or 680 g_snprintf(outbuf, sizeof(outbuf), "PONG %s\r\n", buf + 5);
624 * fatal error to its operators. It may also be sent from one server to 681 if (irc_write(idata->fd, outbuf, strlen(outbuf)) < 0) {
625 * another but must not be accepted from any normal unknown clients. 682 hide_login_progress(gc, _("Unable to write"));
626 * 683 signoff(gc);
627 * An ERROR message is for use for reporting errors which occur with a 684 }
628 * server-to-server link only. An ERROR message is sent to the server 685 return;
629 * at the other end (which sends it to all of its connected operators) 686 }
630 * and to all operators currently connected. It is not to be passed 687 /* XXX doesn't handle ERROR */
631 * onto any other servers by a server if it is received from a server.
632 *
633 * When a server sends a received ERROR message to its operators, the
634 * message should be encapsulated inside a NOTICE message, indicating
635 * that the client was not responsible for the error.
636 *
637 *
638 * Basically, ignore this.
639 *
640 gchar *u_errormsg;
641
642 * Let's get our error message *
643 u_errormsg = g_strdup(buf + 7);
644
645 * We got our error message. Now, let's reaise an
646 * error dialog *
647
648 do_error_dialog(u_errormsg, "Gaim: IRC Error");
649
650 * And our necessary garbage collection *
651 g_free(u_errormsg);
652 return; 688 return;
653 689 }
654 */ 690
655 } 691 buf++;
656 692
657 /* This should be a whois response. I only care about the first (311) one. I might do 693 process_data_init(pdibuf, buf, word, word_eol, FALSE);
658 * the other's later. They're boring. */ 694
659 695 if (atoi(word[2])) {
660 if (((strstr(buf, " 311 ")) && (!strstr(buf, "PRIVMSG")) && (!strstr(buf, "NOTICE")))) { 696 if (*word_eol[3])
661 char **res; 697 process_numeric(gc, word, word_eol);
662
663 res = g_strsplit(buf, " ", 7);
664
665 if (!strcmp(res[1], "311")) {
666 char buf[8192];
667
668 g_snprintf(buf, 4096, "<b>Nick:</b> %s<br>"
669 "<b>Host:</b> %s@%s<br>"
670 "<b>Name:</b> %s<br>", res[3], res[4], res[5], res[7] + 1);
671
672 g_show_info_text(buf, NULL);
673 }
674
675 g_strfreev(res);
676 return; 698 return;
677 } 699 }
678 700
679 /* Autoresponse to an away message */ 701 cmd = word[2];
680 if (((strstr(buf, " 301 ")) && (!strstr(buf, "PRIVMSG")) && (!strstr(buf, "NOTICE")))) { 702
681 char **res; 703 ex = strchr(pdibuf, '!');
682 704 if (!ex) {
683 res = g_strsplit(buf, " ", 5); 705 strncpy(ip, pdibuf, sizeof(ip));
684 706 ip[sizeof(ip)-1] = 0;
685 if (!strcmp(res[1], "301")) 707 strncpy(nick, pdibuf, sizeof(nick));
686 serv_got_im(gc, res[3], res[4] + 1, IM_FLAG_AWAY, time((time_t) NULL)); 708 nick[sizeof(nick)-1] = 0;
687 709 } else {
688 g_strfreev(res); 710 strncpy(ip, ex + 1, sizeof(ip));
689 return; 711 ip[sizeof(ip)-1] = 0;
690 } 712 strncpy(nick, pdibuf, sizeof(nick));
691 713 nick[sizeof(nick)-1] = 0;
692 /* Parse the list of names that we receive when we first sign on to 714 if ((ex - pdibuf) < sizeof (nick))
693 * a channel */ 715 nick[ex - pdibuf] = 0; /* cut the buffer at the '!' */
694 716 }
695 if (((strstr(buf, " 353 ")) && (!strstr(buf, "PRIVMSG")) && (!strstr(buf, "NOTICE")))) { 717
696 gchar u_host[255]; 718 if (!strcmp(cmd, "INVITE")) { /* */
697 gchar u_command[32]; 719 } else if (!strcmp(cmd, "JOIN")) {
698 gchar u_channel[128]; 720 char *chan = *word[3] == ':' ? word[3] + 1 : word[3];
699 gchar u_names[IRC_BUF_LEN + 1]; 721 if (!g_strcasecmp(gc->displayname, nick)) {
700 struct conversation *convo = NULL; 722 static int id = 1;
701 int j; 723 serv_got_joined_chat(gc, id++, chan);
702 724 } else {
703 for (j = 0, i = 0; buf[i] != ' '; j++, i++) { 725 struct conversation *c = irc_find_chat(gc, chan);
704 u_host[j] = buf[i]; 726 if (c)
705 } 727 add_chat_buddy(c, nick);
706 728 }
707 u_host[j] = '\0'; 729 } else if (!strcmp(cmd, "KICK")) {
708 i++; 730 if (!strcmp(gc->displayname, word[4])) {
709 731 struct conversation *c = irc_find_chat(gc, word[3]);
710 for (j = 0; buf[i] != ' '; j++, i++) { 732 if (!c)
711 u_command[j] = buf[i]; 733 return;
712 } 734 gc->buddy_chats = g_slist_remove(gc->buddy_chats, c);
713 735 c->gc = NULL;
714 u_command[j] = '\0'; 736 g_snprintf(outbuf, sizeof(outbuf), _("You have been kicked from %s: %s"),
715 i++; 737 word[3], *word_eol[5] == ':' ? word_eol[5] + 1: word_eol[5]);
716 738 do_error_dialog(outbuf, _("IRC Error"));
717 for (j = 0; buf[i] != '#'; j++, i++) { 739 } else
718 } 740 irc_rem_chat_bud(gc, nick);
719 i++; 741 } else if (!strcmp(cmd, "KILL")) { /* */
720 742 } else if (!strcmp(cmd, "MODE")) {
721 for (j = 0; buf[i] != ':'; j++, i++) { 743 handle_mode(gc, word, word_eol, FALSE);
722 u_channel[j] = buf[i]; 744 } else if (!strcmp(cmd, "NICK")) {
723 } 745 char *new = *word_eol[3] == ':' ? word_eol[3] + 1 : word_eol[3];
724 746 if (!strcmp(gc->displayname, nick))
725 u_channel[j - 1] = '\0'; 747 g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", new);
726 i++; 748 irc_change_name(gc, nick, new);
727 749 } else if (!strcmp(cmd, "NOTICE")) {
728 while ((buf[i] == ' ') || (buf[i] == ':')) { 750 if (*word_eol[4] == ':') word_eol[4]++;
729 i++; 751 if (ex)
730 } 752 irc_got_im(gc, nick, word_eol[4], 0, time(NULL));
731 753 } else if (!strcmp(cmd, "PART")) {
732 strcpy(u_names, buf + i); 754 char *chan = cmd + 5;
733 755 struct conversation *c;
734 buf2 = g_strsplit(u_names, " ", 0); 756 GList *r;
735 757 if (*chan == ':')
736 /* Let's get our conversation window */ 758 chan++;
737 convo = find_conversation_by_name(gc, u_channel); 759 if (!(c = irc_find_chat(gc, chan)))
738 760 return;
739 if (!convo) { 761 if (!strcmp(nick, gc->displayname)) {
740 return; 762 serv_got_chat_left(gc, c->id);
741 } 763 return;
742 764 }
743 /* Now that we've parsed the hell out of this big 765 r = c->in_room;
744 * mess, let's try to split up the names properly */ 766 while (r) {
745 767 char *who = r->data;
746 for (i = 0; buf2[i] != NULL; i++) 768 if (*who == '@')
747 add_chat_buddy(convo, buf2[i]); 769 who++;
748 770 if (*who == '+')
749 /* And free our pointers */ 771 who++;
750 g_strfreev(buf2); 772 if (!g_strcasecmp(who, nick)) {
751 773 char *tmp = g_strdup(r->data);
752 return; 774 remove_chat_buddy(c, r->data);
753 775 g_free(tmp);
754 } 776 break;
755
756 /* Receive a list of users that are currently online */
757
758 if (((strstr(buf, " 303 ")) && (!strstr(buf, "PRIVMSG")) && (!strstr(buf, "NOTICE")))) {
759 gchar u_host[255];
760 gchar u_command[32];
761 gchar u_names[IRC_BUF_LEN + 1];
762 int j;
763
764 for (j = 0, i = 0; buf[i] != ' '; j++, i++) {
765 u_host[j] = buf[i];
766 }
767
768 u_host[j] = '\0';
769 i++;
770
771 for (j = 0; buf[i] != ' '; j++, i++) {
772 u_command[j] = buf[i];
773 }
774
775 u_command[j] = '\0';
776 i++;
777
778 for (j = 0; buf[i] != ':'; j++, i++) {
779 /* My Nick */
780 }
781 i++;
782
783 strcpy(u_names, buf + i);
784
785 buf2 = g_strsplit(u_names, " ", 0);
786
787 /* Now that we've parsed the hell out of this big
788 * mess, let's try to split up the names properly */
789
790 for (i = 0; buf2[i] != NULL; i++) {
791 /* If we have a name here then our buddy is online. We should
792 * update our temporary gslist accordingly. When we achieve our maximum
793 * list of names then we should force an update */
794
795 irc_update_user(gc, buf2[i], 1);
796 }
797
798 /* Increase our received blocks counter */
799 idata->recblocks++;
800
801 /* If we have our total number of blocks */
802 if (idata->recblocks == idata->totalblocks) {
803 GSList *temp;
804 struct irc_channel *u;
805
806 /* Let's grab our list of people and bring them all on or off line */
807 temp = idata->templist;
808
809 /* Loop */
810 while (temp) {
811
812 u = temp->data;
813
814 /* Tell Gaim to bring the person on or off line */
815 serv_got_update(gc, u->name, u->id, 0, 0, 0, 0, 0);
816
817 /* Grab the next entry */
818 temp = g_slist_next(temp);
819 } 777 }
820 778 r = r->next;
821 /* And now, let's delete all of our entries */ 779 }
822 temp = idata->templist; 780 } else if (!strcmp(cmd, "PRIVMSG")) {
823 while (temp) { 781 char *to, *msg;
824 u = temp->data; 782 if (!*word[3])
825 g_free(u->name); 783 return;
826 temp = g_slist_remove(temp, u); 784 to = word[3];
785 msg = *word_eol[4] == ':' ? word_eol[4] + 1 : word_eol[4];
786 if (msg[0] == 1 && msg[strlen (msg) - 1] == 1) { /* ctcp */
787 if (!g_strncasecmp(msg + 1, "ACTION", 6)) {
788 char *po = strchr(msg + 7, 1);
789 if (po) *po = 0;
790 to = g_strconcat("/me", msg + 7, NULL);
791 irc_got_im(gc, nick, to, 0, time(NULL));
792 g_free(to);
827 } 793 }
828 794 } else {
829 /* Reset our list */ 795 if (is_channel(gc, to)) {
830 idata->totalblocks = 0; 796 struct conversation *c = irc_find_chat(gc, to);
831 idata->recblocks = 0; 797 if (!c)
832 798 return;
833 idata->templist = NULL; 799 irc_got_chat_in(gc, c->id, nick, 0, msg, time(NULL));
834 800 } else {
835 return; 801 to = g_malloc(strlen(nick) + 2);
836 } 802 g_snprintf(to, strlen(nick) + 2, "@%s", nick);
837 803 if (find_conversation(to))
838 /* And free our pointers */ 804 irc_got_im(gc, to, msg, 0, time(NULL));
839 g_strfreev(buf2); 805 else {
840 806 *to = '+';
841 return; 807 if (find_conversation(to))
842 808 irc_got_im(gc, to, msg, 0, time(NULL));
843 } 809 else
844 810 irc_got_im(gc, nick, msg, 0, time(NULL));
845 811 }
846 if ((strstr(buf, " MODE ")) && (strstr(buf, "!")) 812 g_free(to);
847 && (strstr(buf, "+v") || strstr(buf, "-v") || strstr(buf, "-o") || strstr(buf, "+o"))
848 && (buf[0] == ':') && (!strstr(buf, " NOTICE "))) {
849
850 gchar u_channel[128];
851 gchar u_nick[128];
852
853 gchar u_mode[5];
854 char **people;
855 gchar *temp, *temp_new;
856
857
858 struct irc_channel *channel;
859 int j;
860 temp = NULL;
861 temp_new = NULL;
862
863
864 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
865 u_nick[j] = buf[i];
866 }
867 u_nick[j] = '\0';
868 i++;
869
870 for (j = 0; buf[i] != '#'; j++, i++) {
871 }
872 i++;
873
874 for (j = 0; buf[i] != ' '; j++, i++) {
875 u_channel[j] = buf[i];
876 }
877
878 u_channel[j] = '\0';
879 i++;
880
881 for (j = 0; buf[i] != ' '; j++, i++) {
882 u_mode[j] = buf[i];
883 }
884 u_mode[j] = '\0';
885 i++;
886
887
888
889
890 people = g_strsplit(buf + i, " ", 3);
891
892
893
894 channel = find_channel_by_name(gc, u_channel);
895
896 if (!channel) {
897 return;
898 }
899
900 for (j = 0; j < strlen(u_mode) - 1; j++) {
901
902
903 struct conversation *convo = NULL;
904 convo = find_conversation_by_id(gc, channel->id);
905
906
907
908 temp = (gchar *) g_malloc(strlen(people[j]) + 3);
909 temp_new = (gchar *) g_malloc(strlen(people[j]) + 3);
910 g_snprintf(temp, strlen(people[j]) + 2, "@%s", people[j]);
911
912 if (u_mode[1] == 'v' && u_mode[0] == '+') {
913 g_snprintf(temp_new, strlen(people[j]) + 2, "+%s", people[j]);
914 } else if (u_mode[1] == 'o' && u_mode[0] == '+') {
915 g_snprintf(temp_new, strlen(people[j]) + 2, "@%s", people[j]);
916 } 813 }
917 814 }
918 else if (u_mode[0] == '-') { 815 } else if (!strcmp(cmd, "PONG")) { /* */
919 g_snprintf(temp_new, strlen(people[j]) + 1, "%s", people[j]); 816 } else if (!strcmp(cmd, "QUIT")) {
920 } 817 irc_rem_chat_bud(gc, nick);
921 818 } else if (!strcmp(cmd, "TOPIC")) {
922 819 struct conversation *c = irc_find_chat(gc, word[3]);
923 820 char *topic = *word_eol[4] == ':' ? word_eol[4] + 1 : word_eol[4];
924 rename_chat_buddy(convo, temp, temp_new); 821 if (c)
925 g_snprintf(temp, strlen(people[j]) + 2, "+%s", people[j]); 822 chat_set_topic(c, nick, topic);
926 rename_chat_buddy(convo, temp, temp_new); 823 } else if (!strcmp(cmd, "WALLOPS")) { /* */
927 824 }
928 rename_chat_buddy(convo, people[j], temp_new);
929
930
931
932
933
934 }
935 if (temp)
936 g_free(temp);
937 if (temp_new)
938 g_free(temp_new);
939
940 return;
941 }
942
943
944 if ((strstr(buf, " KICK ")) && (strstr(buf, "!")) && (buf[0] == ':')
945 && (!strstr(buf, " NOTICE "))) {
946 gchar u_channel[128];
947 gchar u_nick[128];
948 gchar u_comment[128];
949 gchar u_who[128];
950
951 int id;
952
953 gchar *temp;
954
955
956
957 struct irc_channel *channel;
958 int j;
959
960 temp = NULL;
961
962 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
963 u_nick[j] = buf[i];
964 }
965 u_nick[j] = '\0';
966 i++;
967
968 for (j = 0; buf[i] != '#'; j++, i++) {
969 }
970 i++;
971
972 for (j = 0; buf[i] != ' '; j++, i++) {
973 u_channel[j] = buf[i];
974 }
975
976 u_channel[j] = '\0';
977 i++;
978
979 for (j = 0; buf[i] != ' '; j++, i++) {
980 u_who[j] = buf[i];
981 }
982 u_who[j] = '\0';
983 i++;
984 i++;
985 strcpy(u_comment, buf + i);
986 g_strchomp(u_comment);
987
988 channel = find_channel_by_name(gc, u_channel);
989
990 if (!channel) {
991 return;
992 }
993
994
995 id = find_id_by_name(gc, u_channel);
996
997
998 if (g_strcasecmp(u_nick, gc->username) == 0) {
999
1000 /* It looks like you've been naughty! */
1001
1002 serv_got_chat_left(gc, channel->id);
1003
1004 idata->channels = g_list_remove(idata->channels, channel);
1005 } else {
1006 struct conversation *convo = NULL;
1007
1008 /* Find their conversation window */
1009 convo = find_conversation_by_id(gc, channel->id);
1010
1011 if (!convo) {
1012 /* Some how the window doesn't exist.
1013 * Let's get out of here */
1014 return;
1015 }
1016
1017 /* And remove their name */
1018 /* If the person is an op or voice, this won't work.
1019 * so we'll just do a nice hack and remove nick and
1020 * @nick and +nick. Truly wasteful.
1021 */
1022
1023 temp = (gchar *) g_malloc(strlen(u_who) + 3);
1024 g_snprintf(temp, strlen(u_who) + 2, "@%s", u_who);
1025 remove_chat_buddy(convo, temp);
1026 g_free(temp);
1027 temp = (gchar *) g_malloc(strlen(u_who) + 3);
1028 g_snprintf(temp, strlen(u_who) + 2, "+%s", u_who);
1029 remove_chat_buddy(convo, temp);
1030 remove_chat_buddy(convo, u_who);
1031
1032 g_free(temp);
1033
1034 }
1035
1036 /* Go Home! */
1037 return;
1038 }
1039
1040 if ((strstr(buf, " TOPIC ")) && (buf[0] == ':') && (!strstr(buf, " NOTICE "))) {
1041
1042 gchar u_channel[128];
1043 gchar u_nick[128];
1044 gchar u_topic[128];
1045 int j;
1046 struct conversation *chatroom = NULL;
1047
1048 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
1049 u_nick[j] = buf[i];
1050 }
1051 u_nick[j] = 0;
1052 i++;
1053
1054 for (j = 0; buf[i] != '#'; j++, i++) {
1055 }
1056 i++;
1057
1058 for (j = 0; buf[i] != ' '; j++, i++) {
1059 if (buf[i] == '\0')
1060 break;
1061
1062 u_channel[j] = buf[i];
1063 }
1064
1065 for (j = 0; buf[i] != ':'; j++, i++) {
1066 }
1067 i++;
1068
1069 strcpy(u_topic, buf + i);
1070 g_strchomp(u_topic);
1071
1072 chatroom = find_chat(gc, u_channel);
1073
1074 if (!chatroom)
1075 return;
1076
1077 chat_set_topic(chatroom, u_nick, u_topic);
1078
1079 return;
1080 }
1081
1082
1083 if ((strstr(buf, " JOIN ")) && (strstr(buf, "!")) && (buf[0] == ':')
1084 && (!strstr(buf, " NOTICE "))) {
1085
1086 gchar u_channel[128];
1087 gchar u_nick[128];
1088
1089 struct irc_channel *channel;
1090 int j;
1091
1092 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
1093 u_nick[j] = buf[i];
1094 }
1095
1096 u_nick[j] = '\0';
1097 i++;
1098
1099 for (j = 0; buf[i] != '#'; j++, i++) {
1100 }
1101
1102 i++;
1103
1104 strcpy(u_channel, buf + i);
1105
1106 g_strchomp(u_channel);
1107
1108 /* Looks like we're going to join the channel for real
1109 * now. Let's create a valid channel structure and add
1110 * it to our list. Let's make sure that
1111 * we are not already in a channel first */
1112
1113 channel = find_channel_by_name(gc, u_channel);
1114
1115 if (!channel) {
1116
1117 chat_id++;
1118
1119 channel = g_new0(struct irc_channel, 1);
1120
1121 channel->id = chat_id;
1122 channel->name = strdup(u_channel);
1123
1124 idata->channels = g_list_append(idata->channels, channel);
1125
1126 serv_got_joined_chat(gc, chat_id, u_channel);
1127 } else {
1128 struct conversation *convo = NULL;
1129
1130 /* Someone else joined. Find their conversation
1131 * window */
1132 convo = find_conversation_by_id(gc, channel->id);
1133
1134 /* And add their name to it */
1135 add_chat_buddy(convo, u_nick);
1136
1137 }
1138
1139 return;
1140 }
1141
1142 if ((strstr(buf, " NICK ")) && (strstr(buf, "!")) && (buf[0] == ':')
1143 && (!strstr(buf, " NOTICE "))) {
1144
1145 gchar old[128];
1146 gchar new[128];
1147
1148 GList *templist;
1149 gchar *temp, *temp_new;
1150 struct irc_channel *channel;
1151 int j;
1152 temp = temp_new = NULL;
1153 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
1154 old[j] = buf[i];
1155 }
1156
1157 old[j] = '\0';
1158 i++;
1159
1160 for (j = 0; buf[i] != ':'; j++, i++) {
1161 }
1162
1163 i++;
1164 strcpy(new, buf + i);
1165
1166 g_strchomp(new);
1167
1168 templist = ((struct irc_data *)gc->proto_data)->channels;
1169
1170 while (templist) {
1171 struct conversation *convo = NULL;
1172 channel = templist->data;
1173
1174 convo = find_conversation_by_id(gc, channel->id);
1175
1176 /* If the person is an op or voice, this won't work.
1177 * so we'll just do a nice hack and rename nick and
1178 * @nick and +nick. Truly wasteful.
1179 */
1180
1181 temp = (gchar *) g_malloc(strlen(old) + 5);
1182 temp_new = (gchar *) g_malloc(strlen(new) + 5);
1183 g_snprintf(temp_new, strlen(new) + 2, "@%s", new);
1184 g_snprintf(temp, strlen(old) + 2, "@%s", old);
1185 rename_chat_buddy(convo, temp, temp_new);
1186 g_snprintf(temp, strlen(old) + 2, "+%s", old);
1187 g_snprintf(temp_new, strlen(new) + 2, "+%s", new);
1188 rename_chat_buddy(convo, temp, temp_new);
1189 rename_chat_buddy(convo, old, new);
1190 if (temp)
1191 g_free(temp);
1192 if (temp_new)
1193 g_free(temp_new);
1194
1195 templist = templist->next;
1196 }
1197 return;
1198 }
1199
1200
1201 if ((strstr(buf, "QUIT ")) && (buf[0] == ':') && (strstr(buf, "!"))
1202 && (!strstr(buf, " NOTICE "))) {
1203
1204 gchar u_nick[128];
1205 gchar *temp;
1206 GList *templist;
1207
1208 struct irc_channel *channel;
1209 int j;
1210
1211
1212 temp = NULL;
1213 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
1214 u_nick[j] = buf[i];
1215 }
1216
1217 u_nick[j] = '\0';
1218
1219 templist = ((struct irc_data *)gc->proto_data)->channels;
1220
1221 while (templist) {
1222 struct conversation *convo = NULL;
1223 channel = templist->data;
1224
1225 convo = find_conversation_by_id(gc, channel->id);
1226
1227 /* If the person is an op or voice, this won't work.
1228 * so we'll just do a nice hack and remove nick and
1229 * @nick and +nick. Truly wasteful.
1230 */
1231
1232 temp = (gchar *) g_malloc(strlen(u_nick) + 2);
1233 g_snprintf(temp, strlen(u_nick) + 2, "@%s", u_nick);
1234 remove_chat_buddy(convo, temp);
1235 g_free(temp);
1236 temp = (gchar *) g_malloc(strlen(u_nick) + 2);
1237 g_snprintf(temp, strlen(u_nick) + 2, "+%s", u_nick);
1238 remove_chat_buddy(convo, temp);
1239 remove_chat_buddy(convo, u_nick);
1240
1241
1242
1243 templist = templist->next;
1244 }
1245
1246 g_free(temp);
1247
1248 return;
1249 }
1250
1251
1252
1253 if ((strstr(buf, " PART ")) && (strstr(buf, "!")) && (buf[0] == ':')
1254 && (!strstr(buf, " NOTICE "))) {
1255
1256 gchar u_channel[128];
1257 gchar u_nick[128];
1258 gchar *temp;
1259 struct irc_channel *channel;
1260 int j;
1261 temp = NULL;
1262 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
1263 u_nick[j] = buf[i];
1264 }
1265 u_nick[j] = '\0';
1266
1267 i++;
1268
1269 for (j = 0; buf[i] != '#'; j++, i++) {
1270 }
1271
1272 i++;
1273
1274 for (j = 0; buf[i] != ' '; j++, i++) {
1275 if (buf[i] == '\0') {
1276 break;
1277 }
1278 u_channel[j] = buf[i];
1279 }
1280 u_channel[j] = '\0';
1281
1282 /* Now, lets check to see if it was US that was leaving.
1283 * If so, do the correct thing by closing up all of our
1284 * old channel stuff. Otherwise,
1285 * we should just print that someone left */
1286
1287 channel = find_channel_by_name(gc, u_channel);
1288
1289 if (!channel) {
1290 return;
1291 }
1292
1293 if (g_strcasecmp(u_nick, gc->username) == 0) {
1294
1295 /* Looks like we're going to leave the channel for
1296 * real now. Let's create a valid channel structure
1297 * and add it to our list */
1298
1299 serv_got_chat_left(gc, channel->id);
1300
1301 idata->channels = g_list_remove(idata->channels, channel);
1302 } else {
1303 struct conversation *convo = NULL;
1304
1305 /* Find their conversation window */
1306 convo = find_conversation_by_id(gc, channel->id);
1307
1308 if (!convo) {
1309 /* Some how the window doesn't exist.
1310 * Let's get out of here */
1311 return;
1312 }
1313
1314 /* And remove their name */
1315 /* If the person is an op or voice, this won't work.
1316 * so we'll just do a nice hack and remove nick and
1317 * @nick and +nick. Truly wasteful.
1318 */
1319
1320 temp = (gchar *) g_malloc(strlen(u_nick) + 3);
1321 g_snprintf(temp, strlen(u_nick) + 2, "@%s", u_nick);
1322 remove_chat_buddy(convo, temp);
1323 g_free(temp);
1324 temp = (gchar *) g_malloc(strlen(u_nick) + 3);
1325 g_snprintf(temp, strlen(u_nick) + 2, "+%s", u_nick);
1326 remove_chat_buddy(convo, temp);
1327 g_free(temp);
1328 remove_chat_buddy(convo, u_nick);
1329
1330
1331 }
1332
1333 /* Go Home! */
1334 return;
1335 }
1336
1337 if ((strstr(buf, " NOTICE ")) && (buf[0] == ':')) {
1338 gchar u_nick[128];
1339 gchar u_host[255];
1340 gchar u_command[32];
1341 gchar u_channel[128];
1342 gchar u_message[IRC_BUF_LEN];
1343 int j;
1344
1345 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
1346 u_nick[j] = buf[i];
1347 }
1348
1349 u_nick[j] = '\0';
1350 i++;
1351
1352 for (j = 0; buf[i] != ' '; j++, i++) {
1353 u_host[j] = buf[i];
1354 }
1355
1356 u_host[j] = '\0';
1357 i++;
1358
1359 for (j = 0; buf[i] != ' '; j++, i++) {
1360 u_command[j] = buf[i];
1361 }
1362
1363 u_command[j] = '\0';
1364 i++;
1365
1366 for (j = 0; buf[i] != ':'; j++, i++) {
1367 u_channel[j] = buf[i];
1368 }
1369
1370 u_channel[j - 1] = '\0';
1371 i++;
1372
1373
1374 /* Now that everything is parsed, the rest of this baby must be our message */
1375 strncpy(u_message, buf + i, IRC_BUF_LEN);
1376
1377 /* Now, lets check the message to see if there's anything special in it */
1378 if (u_message[0] == '\001') {
1379 if ((g_strncasecmp(u_message, "\001PING ", 6) == 0) && (strlen(u_message) > 6)) {
1380 /* Someone's triyng to ping us. Let's respond */
1381 gchar u_arg[24];
1382 gchar u_buf[200];
1383 unsigned long tend = time((time_t *) NULL);
1384 unsigned long tstart;
1385
1386 printf("LA: %s\n", buf);
1387
1388 strcpy(u_arg, u_message + 6);
1389 u_arg[strlen(u_arg) - 1] = '\0';
1390
1391 tstart = atol(u_arg);
1392
1393 g_snprintf(u_buf, sizeof(u_buf), "Ping Reply From %s: [%ld seconds]",
1394 u_nick, tend - tstart);
1395
1396 do_error_dialog(u_buf, "Gaim IRC - Ping Reply");
1397
1398 return;
1399 }
1400 }
1401
1402 }
1403
1404
1405 if ((strstr(buf, " PRIVMSG ")) && (buf[0] == ':')) {
1406 gchar u_nick[128];
1407 gchar u_host[255];
1408 gchar u_command[32];
1409 gchar u_channel[128];
1410 gchar u_message[IRC_BUF_LEN];
1411 gboolean is_closing;
1412
1413 int j;
1414
1415
1416 for (j = 0, i = 1; buf[i] != '!'; j++, i++) {
1417 u_nick[j] = buf[i];
1418 }
1419
1420 u_nick[j] = '\0';
1421 i++;
1422
1423 for (j = 0; buf[i] != ' '; j++, i++) {
1424 u_host[j] = buf[i];
1425 }
1426
1427 u_host[j] = '\0';
1428 i++;
1429
1430 for (j = 0; buf[i] != ' '; j++, i++) {
1431 u_command[j] = buf[i];
1432 }
1433
1434 u_command[j] = '\0';
1435 i++;
1436
1437 for (j = 0; buf[i] != ':'; j++, i++) {
1438 u_channel[j] = buf[i];
1439 }
1440
1441 u_channel[j - 1] = '\0';
1442 i++;
1443
1444
1445 /* Now that everything is parsed, the rest of this baby must be our message */
1446 strncpy(u_message, buf + i, IRC_BUF_LEN);
1447
1448 /* Now, lets check the message to see if there's anything special in it */
1449 if (u_message[0] == '\001') {
1450 if (g_strncasecmp(u_message, "\001VERSION", 8) == 0) {
1451 /* Looks like we have a version request. Let
1452 * us handle it thusly */
1453
1454 g_snprintf(buf, IRC_BUF_LEN,
1455 "NOTICE %s :%cVERSION GAIM %s:The Pimpin Penguin AIM Clone:%s%c\n",
1456 u_nick, '\001', VERSION, WEBSITE, '\001');
1457
1458 write(idata->fd, buf, strlen(buf));
1459
1460 /* And get the heck out of dodge */
1461 return;
1462 }
1463
1464 if ((g_strncasecmp(u_message, "\001PING ", 6) == 0) && (strlen(u_message) > 6)) {
1465 /* Someone's triyng to ping us. Let's respond */
1466 gchar u_arg[24];
1467
1468 strcpy(u_arg, u_message + 6);
1469 u_arg[strlen(u_arg) - 1] = '\0';
1470
1471 g_snprintf(buf, IRC_BUF_LEN, "NOTICE %s :%cPING %s%c\n", u_nick, '\001',
1472 u_arg, '\001');
1473
1474 write(idata->fd, buf, strlen(buf));
1475
1476 /* And get the heck out of dodge */
1477 return;
1478 }
1479
1480 if (g_strncasecmp(u_message, "\001ACTION ", 8) == 0) {
1481 /* Looks like we have an action. Let's parse it a little */
1482 strcpy(buf, u_message);
1483
1484 strcpy(u_message, "/me ");
1485 for (j = 4, i = 8; buf[i] != '\001'; i++, j++) {
1486 u_message[j] = buf[i];
1487 }
1488 u_message[j] = '\0';
1489 }
1490 }
1491
1492
1493 /* OK, It is a chat or IM message. Here, let's translate the IRC formatting into
1494 * good ol' fashioned imhtml style hypertext markup. */
1495
1496
1497 is_closing = FALSE;
1498
1499 while (strchr(u_message, '\002')) { /* \002 = ^B */
1500 gchar *current;
1501 gchar *temp, *free_here;
1502
1503
1504 temp = g_strdup(strchr(u_message, '\002'));
1505 free_here = temp;
1506 temp++;
1507
1508 current = strchr(u_message, '\002');
1509 *current = '<';
1510 current++;
1511 if (is_closing) {
1512 *current = '/';
1513 current++;
1514 }
1515 *current = 'b';
1516 current++;
1517 *current = '>';
1518 current++;
1519
1520
1521 while (*temp != '\0') {
1522 *current = *temp;
1523 current++;
1524 temp++;
1525 }
1526 *current = '\0';
1527 g_free(free_here);
1528
1529 is_closing = !is_closing;
1530 }
1531
1532 is_closing = FALSE;
1533 while (strchr(u_message, '\037')) { /* \037 = ^_ */
1534 gchar *current;
1535 gchar *temp, *free_here;
1536
1537
1538 temp = g_strdup(strchr(u_message, '\037'));
1539 free_here = temp;
1540 temp++;
1541
1542 current = strchr(u_message, '\037');
1543 *current = '<';
1544 current++;
1545 if (is_closing) {
1546 *current = '/';
1547 current++;
1548 }
1549 *current = 'u';
1550 current++;
1551 *current = '>';
1552 current++;
1553
1554
1555 while (*temp != '\0') {
1556 *current = *temp;
1557 current++;
1558 temp++;
1559 }
1560 *current = '\0';
1561 g_free(free_here);
1562 is_closing = !is_closing;
1563
1564 }
1565
1566 while (strchr(u_message, '\003')) { /* \003 = ^C */
1567
1568 /* This is color formatting. IRC uses its own weird little system
1569 * that we must translate to HTML. */
1570
1571
1572 /* The format is something like this:
1573 * ^C5 or ^C5,3
1574 * The number before the comma is the foreground color, after is the
1575 * background color. Either number can be 1 or two digits.
1576 */
1577
1578 gchar *current;
1579 gchar *temp, *free_here;
1580 gchar *font_tag, *body_tag;
1581 int fg_color, bg_color;
1582
1583 temp = g_strdup(strchr(u_message, '\003'));
1584 free_here = temp;
1585 temp++;
1586
1587 fg_color = bg_color = -1;
1588 body_tag = font_tag = "";
1589
1590 /* Parsing the color information: */
1591 do {
1592 if (!isdigit(*temp))
1593 break; /* This translates to </font> */
1594 fg_color = (int)(*temp - 48);
1595 temp++;
1596 if (isdigit(*temp)) {
1597 fg_color = (fg_color * 10) + (int)(*temp - 48);
1598 temp++;
1599 }
1600 if (*temp != ',')
1601 break;
1602 temp++;
1603 if (!isdigit(*temp))
1604 break; /* This translates to </font> */
1605 bg_color = (int)(*temp - 48);
1606 temp++;
1607 if (isdigit(*temp)) {
1608 bg_color = (bg_color * 10) + (int)(*temp - 48);
1609 temp++;
1610 }
1611 } while (FALSE);
1612
1613 if (fg_color > 15)
1614 fg_color = fg_color % 16;
1615 if (bg_color > 15)
1616 bg_color = bg_color % 16;
1617
1618 switch (fg_color) {
1619 case -1:
1620 font_tag = "</font></body>";
1621 break;
1622 case 0: /* WHITE */
1623 font_tag = "<font color=\"#ffffff\">";
1624 /* If no background color is specified, we're going to make it black anyway.
1625 * That's probably what the sender anticipated the background color to be.
1626 * White on white would be illegible.
1627 */
1628 if (bg_color == -1) {
1629 body_tag = "<body bgcolor=\"#000000\">";
1630 }
1631 break;
1632 case 1: /* BLACK */
1633 font_tag = "<font color=\"#000000\">";
1634 break;
1635 case 2: /* NAVY BLUE */
1636 font_tag = "<font color=\"#000066\">";
1637 break;
1638 case 3: /* GREEN */
1639 font_tag = "<font color=\"#006600\">";
1640 break;
1641 case 4: /* RED */
1642 font_tag = "<font color=\"#ff0000\">";
1643 break;
1644 case 5: /* MAROON */
1645 font_tag = "<font color=\"#660000\">";
1646 break;
1647 case 6: /* PURPLE */
1648 font_tag = "<font color=\"#660066\">";
1649 break;
1650 case 7: /* DISGUSTING PUKE COLOR */
1651 font_tag = "<font color=\"#666600\">";
1652 break;
1653 case 8: /* YELLOW */
1654 font_tag = "<font color=\"#cccc00\">";
1655 break;
1656 case 9: /* LIGHT GREEN */
1657 font_tag = "<font color=\"#33cc33\">";
1658 break;
1659 case 10: /* TEAL */
1660 font_tag = "<font color=\"#00acac\">";
1661 break;
1662 case 11: /* CYAN */
1663 font_tag = "<font color=\"#00ccac\">";
1664 break;
1665 case 12: /* BLUE */
1666 font_tag = "<font color=\"#0000ff\">";
1667 break;
1668 case 13: /* PINK */
1669 font_tag = "<font color=\"#cc00cc\">";
1670 break;
1671 case 14: /* GREY */
1672 font_tag = "<font color=\"#666666\">";
1673 break;
1674 case 15: /* SILVER */
1675 font_tag = "<font color=\"#00ccac\">";
1676 break;
1677 }
1678
1679 switch (bg_color) {
1680 case 0: /* WHITE */
1681 body_tag = "<body bgcolor=\"#ffffff\">";
1682 break;
1683 case 1: /* BLACK */
1684 body_tag = "<body bgcolor=\"#000000\">";
1685 break;
1686 case 2: /* NAVY BLUE */
1687 body_tag = "<body bgcolor=\"#000066\">";
1688 break;
1689 case 3: /* GREEN */
1690 body_tag = "<body bgcolor=\"#006600\">";
1691 break;
1692 case 4: /* RED */
1693 body_tag = "<body bgcolor=\"#ff0000\">";
1694 break;
1695 case 5: /* MAROON */
1696 body_tag = "<body bgcolor=\"#660000\">";
1697 break;
1698 case 6: /* PURPLE */
1699 body_tag = "<body bgcolor=\"#660066\">";
1700 break;
1701 case 7: /* DISGUSTING PUKE COLOR */
1702 body_tag = "<body bgcolor=\"#666600\">";
1703 break;
1704 case 8: /* YELLOW */
1705 body_tag = "<body bgcolor=\"#cccc00\">";
1706 break;
1707 case 9: /* LIGHT GREEN */
1708 body_tag = "<body bgcolor=\"#33cc33\">";
1709 break;
1710 case 10: /* TEAL */
1711 body_tag = "<body bgcolor=\"#00acac\">";
1712 break;
1713 case 11: /* CYAN */
1714 body_tag = "<body bgcolor=\"#00ccac\">";
1715 break;
1716 case 12: /* BLUE */
1717 body_tag = "<body bgcolor=\"#0000ff\">";
1718 break;
1719 case 13: /* PINK */
1720 body_tag = "<body bgcolor=\"#cc00cc\">";
1721 break;
1722 case 14: /* GREY */
1723 body_tag = "<body bgcolor=\"#666666\">";
1724 break;
1725 case 15: /* SILVER */
1726 body_tag = "<body bgcolor=\"#00ccac\">";
1727 break;
1728 }
1729
1730 current = strchr(u_message, '\003');
1731
1732 while (*body_tag != '\0') {
1733 *current = *body_tag;
1734 current++;
1735 body_tag++;
1736 }
1737
1738 while (*font_tag != '\0') {
1739 *current = *font_tag;
1740 current++;
1741 font_tag++;
1742 }
1743
1744 while (*temp != '\0') {
1745 *current = *temp;
1746 current++;
1747 temp++;
1748 }
1749 *current = '\0';
1750 g_free(free_here);
1751 is_closing = !is_closing;
1752
1753 }
1754
1755 while (strchr(u_message, '\017')) { /* \017 = ^O */
1756 gchar *current;
1757 gchar *temp, *free_here;
1758
1759
1760 temp = g_strdup(strchr(u_message, '\017'));
1761 free_here = temp;
1762 temp++;
1763
1764 current = strchr(u_message, '\017');
1765 *current = '<';
1766 current++;
1767 *current = '/';
1768 current++;
1769 *current = 'b';
1770 current++;
1771 *current = '>';
1772 current++;
1773 *current = '<';
1774 current++;
1775 *current = '/';
1776 current++;
1777 *current = 'u';
1778 current++;
1779 *current = '>';
1780 current++;
1781
1782 while (*temp != '\0') {
1783 *current = *temp;
1784 current++;
1785 temp++;
1786 }
1787 *current = '\0';
1788 g_free(free_here);
1789 }
1790
1791 /* Let's check to see if we have a channel on our hands */
1792 if (u_channel[0] == '#') {
1793 /* Yup. We have a channel */
1794 int id;
1795
1796 id = find_id_by_name(gc, u_channel);
1797 if (id != -1) {
1798 serv_got_chat_in(gc, id, u_nick, 0, u_message, time((time_t) NULL));
1799
1800 }
1801
1802 } else {
1803 /* Nope. Let's treat it as a private message */
1804
1805 gchar *temp;
1806 temp = NULL;
1807
1808 temp = (gchar *) g_malloc(strlen(u_nick) + 5);
1809 g_snprintf(temp, strlen(u_nick) + 2, "@%s", u_nick);
1810
1811
1812 /* If I get a message from SeanEgn, and I already have a window
1813 * open for him as @SeanEgn or +SeanEgn, this will keep it in the
1814 * same window. Unfortunately, if SeanEgn loses his op status
1815 * (a sad thing indeed), the messages will still appear to come from
1816 * @SeanEgn, until that convo is closed.
1817 */
1818
1819 if (find_conversation(temp)) {
1820 serv_got_im(gc, temp, u_message, 0, time((time_t) NULL));
1821 g_free(temp);
1822 return;
1823 } else {
1824 g_snprintf(temp, strlen(u_nick) + 2, "+%s", u_nick);
1825 if (find_conversation(temp)) {
1826 serv_got_im(gc, temp, u_message, 0, time((time_t) NULL));
1827 g_free(temp);
1828 return;
1829 } else {
1830 g_free(temp);
1831 serv_got_im(gc, u_nick, u_message, 0, time((time_t) NULL));
1832 return;
1833 }
1834 }
1835 }
1836
1837 return;
1838 }
1839
1840 /* Let's parse PING requests so that we wont get booted for inactivity */
1841
1842 if (strncmp(buf, "PING :", 6) == 0) {
1843 buf2 = g_strsplit(buf, ":", 1);
1844
1845 /* Let's build a new response */
1846 g_snprintf(buf, IRC_BUF_LEN, "PONG :%s\n", buf2[1]);
1847 write(idata->fd, buf, strlen(buf));
1848
1849 /* And clean up after ourselves */
1850 g_strfreev(buf2);
1851
1852 return;
1853 }
1854
1855 }
1856
1857 static void irc_close(struct gaim_connection *gc)
1858 {
1859 struct irc_data *idata = (struct irc_data *)gc->proto_data;
1860 GList *chats = idata->channels;
1861 struct irc_channel *cc;
1862
1863 gchar *buf = (gchar *) g_malloc(IRC_BUF_LEN);
1864
1865 g_snprintf(buf, IRC_BUF_LEN, "QUIT :Download GAIM [%s]\n", WEBSITE);
1866 write(idata->fd, buf, strlen(buf));
1867
1868 g_free(buf);
1869
1870 if (idata->timer)
1871 g_source_remove(idata->timer);
1872
1873 while (chats) {
1874 cc = (struct irc_channel *)chats->data;
1875 g_free(cc->name);
1876 chats = g_list_remove(chats, cc);
1877 g_free(cc);
1878 }
1879
1880 if (gc->inpa)
1881 gaim_input_remove(gc->inpa);
1882
1883 if (idata->inpa)
1884 gaim_input_remove(idata->inpa);
1885
1886 close(idata->fd);
1887 g_free(gc->proto_data);
1888 }
1889
1890 static void irc_chat_leave(struct gaim_connection *gc, int id)
1891 {
1892 struct irc_data *idata = (struct irc_data *)gc->proto_data;
1893 struct irc_channel *channel;
1894 gchar *buf = (gchar *) g_malloc(IRC_BUF_LEN + 1);
1895
1896 channel = find_channel_by_id(gc, id);
1897
1898 if (!channel) {
1899 return;
1900 }
1901
1902 g_snprintf(buf, IRC_BUF_LEN, "PART #%s\n", channel->name);
1903 write(idata->fd, buf, strlen(buf));
1904
1905 g_free(buf);
1906 } 825 }
1907 826
1908 static void irc_login_callback(gpointer data, gint source, GaimInputCondition condition) 827 static void irc_login_callback(gpointer data, gint source, GaimInputCondition condition)
1909 { 828 {
1910 struct gaim_connection *gc = data; 829 struct gaim_connection *gc = data;
1911 struct irc_data *idata; 830 struct irc_data *idata;
1912 char buf[4096]; 831 char hostname[256];
832 char buf[IRC_BUF_LEN];
1913 833
1914 if (!g_slist_find(connections, gc)) { 834 if (!g_slist_find(connections, gc)) {
1915 close(source); 835 close(source);
1916 return; 836 return;
1917 } 837 }
1925 } 845 }
1926 846
1927 if (idata->fd != source) 847 if (idata->fd != source)
1928 idata->fd = source; 848 idata->fd = source;
1929 849
1930 g_snprintf(buf, 4096, "NICK %s\n USER %s localhost %s :GAIM (%s)\n", 850 g_snprintf(buf, sizeof(buf), "NICK %s\r\n", gc->username);
1931 gc->username, g_get_user_name(), gc->user->proto_opt[USEROPT_SERV], WEBSITE); 851 if (irc_write(idata->fd, buf, strlen(buf)) < 0) {
1932
1933 if (write(idata->fd, buf, strlen(buf)) < 0) {
1934 hide_login_progress(gc, "Write error"); 852 hide_login_progress(gc, "Write error");
1935 signoff(gc); 853 signoff(gc);
1936 return; 854 return;
1937 } 855 }
1938 856
1939 idata->inpa = gaim_input_add(idata->fd, GAIM_INPUT_READ, irc_callback, gc); 857 gethostname(hostname, sizeof(hostname) - 1);
1940 858 hostname[sizeof(hostname) - 1] = 0;
1941 /* Now lets sign ourselves on */ 859 if (!*hostname)
1942 account_online(gc); 860 g_snprintf(hostname, sizeof(hostname), "localhost");
1943 serv_finish_login(gc); 861 g_snprintf(buf, sizeof(buf), "USER %s %s %s :GAIM (%s)\r\n",
1944 862 g_get_user_name(), hostname, gc->user->proto_opt[USEROPT_SERV], WEBSITE);
1945 if (bud_list_cache_exists(gc)) 863 if (irc_write(idata->fd, buf, strlen(buf)) < 0) {
1946 do_import(NULL, gc); 864 hide_login_progress(gc, "Write error");
1947 865 signoff(gc);
1948 /* we don't call this now because otherwise some IRC servers might not like us */ 866 return;
1949 idata->timer = g_timeout_add(20000, irc_request_buddy_update, gc); 867 }
868
869 gc->inpa = gaim_input_add(idata->fd, GAIM_INPUT_READ, irc_callback, gc);
1950 } 870 }
1951 871
1952 static void irc_login(struct aim_user *user) 872 static void irc_login(struct aim_user *user)
1953 { 873 {
1954 char buf[4096]; 874 char buf[IRC_BUF_LEN];
1955 875
1956 struct gaim_connection *gc = new_gaim_conn(user); 876 struct gaim_connection *gc = new_gaim_conn(user);
1957 struct irc_data *idata = gc->proto_data = g_new0(struct irc_data, 1); 877 struct irc_data *idata = gc->proto_data = g_new0(struct irc_data, 1);
1958 878
879 g_snprintf(gc->displayname, sizeof(gc->displayname), "%s", gc->username);
880
1959 g_snprintf(buf, sizeof(buf), "Signon: %s", gc->username); 881 g_snprintf(buf, sizeof(buf), "Signon: %s", gc->username);
1960 set_login_progress(gc, 2, buf); 882 set_login_progress(gc, 2, buf);
883
884 idata->chantypes = g_strdup("#&!+");
885 idata->chanmodes = g_strdup("beI,k,l");
886 idata->nickmodes = g_strdup("ohv");
887 idata->str = g_string_new("");
1961 888
1962 idata->fd = proxy_connect(user->proto_opt[USEROPT_SERV], 889 idata->fd = proxy_connect(user->proto_opt[USEROPT_SERV],
1963 user->proto_opt[USEROPT_PORT][0] ? atoi(user-> 890 user->proto_opt[USEROPT_PORT][0] ? atoi(user->
1964 proto_opt[USEROPT_PORT]) : 891 proto_opt[USEROPT_PORT]) :
1965 6667, irc_login_callback, gc); 892 6667, irc_login_callback, gc);
1968 signoff(gc); 895 signoff(gc);
1969 return; 896 return;
1970 } 897 }
1971 } 898 }
1972 899
900 static void irc_close(struct gaim_connection *gc)
901 {
902 struct irc_data *idata = (struct irc_data *)gc->proto_data;
903 gchar buf[IRC_BUF_LEN];
904
905 g_snprintf(buf, sizeof(buf), "QUIT :Download GAIM [%s]\r\n", WEBSITE);
906 irc_write(idata->fd, buf, strlen(buf));
907
908 g_free(idata->chantypes);
909 g_free(idata->chanmodes);
910 g_free(idata->nickmodes);
911
912 g_string_free(idata->str, TRUE);
913
914 if (idata->timer)
915 g_source_remove(idata->timer);
916
917 if (gc->inpa)
918 gaim_input_remove(gc->inpa);
919
920 close(idata->fd);
921 g_free(gc->proto_data);
922 }
923
1973 static GList *irc_user_opts() 924 static GList *irc_user_opts()
1974 { 925 {
1975 GList *m = NULL; 926 GList *m = NULL;
1976 struct proto_user_opt *puo; 927 struct proto_user_opt *puo;
1977 928
1988 m = g_list_append(m, puo); 939 m = g_list_append(m, puo);
1989 940
1990 return m; 941 return m;
1991 } 942 }
1992 943
944 static void set_mode_3(struct gaim_connection *gc, char *who, int sign, int mode,
945 int start, int end, char *word[])
946 {
947 struct irc_data *id = gc->proto_data;
948 char buf[IRC_BUF_LEN];
949 int left;
950 int i = start;
951
952 while (1) {
953 left = end - i;
954 switch (left) {
955 case 0:
956 return;
957 case 1:
958 g_snprintf(buf, sizeof(buf), "MODE %s %c%c %s\r\n",
959 who, sign, mode, word[i]);
960 i += 1;
961 break;
962 case 2:
963 g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c %s %s\r\n",
964 who, sign, mode, mode, word[i], word[i + 1]);
965 i += 2;
966 break;
967 default:
968 g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c %s %s %s\r\n",
969 who, sign, mode, mode, mode,
970 word[i], word[i + 1], word[i + 2]);
971 i += 2;
972 break;
973 }
974 irc_write(id->fd, buf, strlen(buf));
975 if (left < 3)
976 return;
977 }
978 }
979
980 static void set_mode_6(struct gaim_connection *gc, char *who, int sign, int mode,
981 int start, int end, char *word[])
982 {
983 struct irc_data *id = gc->proto_data;
984 char buf[IRC_BUF_LEN];
985 int left;
986 int i = start;
987
988 while (1) {
989 left = end - i;
990 switch (left) {
991 case 0:
992 return;
993 case 1:
994 g_snprintf(buf, sizeof(buf), "MODE %s %c%c %s\r\n",
995 who, sign, mode, word[i]);
996 i += 1;
997 break;
998 case 2:
999 g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c %s %s\r\n",
1000 who, sign, mode, mode, word[i], word[i + 1]);
1001 i += 2;
1002 break;
1003 case 3:
1004 g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c %s %s %s\r\n",
1005 who, sign, mode, mode, mode,
1006 word[i], word[i + 1], word[i + 2]);
1007 i += 3;
1008 break;
1009 case 4:
1010 g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c%c %s %s %s %s\r\n",
1011 who, sign, mode, mode, mode, mode,
1012 word[i], word[i + 1], word[i + 2], word[i + 3]);
1013 i += 4;
1014 break;
1015 case 5:
1016 g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c%c%c %s %s %s %s %s\r\n",
1017 who, sign, mode, mode, mode, mode, mode,
1018 word[i], word[i + 1], word[i + 2],
1019 word[i + 3], word[i + 4]);
1020 i += 5;
1021 break;
1022 default:
1023 g_snprintf(buf, sizeof(buf), "MODE %s %c%c%c%c%c%c%c %s %s %s %s %s %s\r\n",
1024 who, sign, mode, mode, mode, mode, mode, mode,
1025 word[i], word[i + 1], word[i + 2],
1026 word[i + 3], word[i + 4], word[i + 5]);
1027 i += 6;
1028 break;
1029 }
1030 irc_write(id->fd, buf, strlen(buf));
1031 if (left < 6)
1032 return;
1033 }
1034 }
1035
1036 static void set_mode(struct gaim_connection *gc, char *who, int sign, int mode, char *word[])
1037 {
1038 struct irc_data *id = gc->proto_data;
1039 int i = 2;
1040
1041 while (1) {
1042 if (!*word[i]) {
1043 if (i == 2)
1044 return;
1045 if (id->six_modes)
1046 set_mode_6(gc, who, sign, mode, 2, i, word);
1047 else
1048 set_mode_3(gc, who, sign, mode, 2, i, word);
1049 return;
1050 }
1051 i++;
1052 }
1053 }
1054
1055 static void handle_command(struct gaim_connection *gc, char *who, char *what)
1056 {
1057 char buf[IRC_BUF_LEN];
1058 char pdibuf[IRC_BUF_LEN];
1059 char *word[PDIWORDS], *word_eol[PDIWORDS];
1060 struct irc_data *id = gc->proto_data;
1061 if (*what != '/') {
1062 unsigned int max = 440 - strlen(who);
1063 char t;
1064 while (strlen(what) > max) {
1065 t = what[max];
1066 what[max] = 0;
1067 g_snprintf(buf, sizeof(buf), "PRIVMSG %s :%s\r\n", who, what);
1068 irc_write(id->fd, buf, strlen(buf));
1069 what[max] = t;
1070 what = what + max;
1071 }
1072 g_snprintf(buf, sizeof(buf), "PRIVMSG %s :%s\r\n", who, what);
1073 irc_write(id->fd, buf, strlen(buf));
1074 return;
1075 }
1076
1077 what++;
1078 process_data_init(pdibuf, what, word, word_eol, TRUE);
1079
1080 if (!g_strcasecmp(pdibuf, "ME")) {
1081 g_snprintf(buf, sizeof(buf), "PRIVMSG %s :\001ACTION %s\001\r\n", who, word_eol[2]);
1082 irc_write(id->fd, buf, strlen(buf));
1083 } else if (!g_strcasecmp(pdibuf, "TOPIC")) {
1084 if (!*word_eol[2])
1085 return;
1086 g_snprintf(buf, sizeof(buf), "TOPIC %s :%s\r\n", who, word_eol[2]);
1087 irc_write(id->fd, buf, strlen(buf));
1088 } else if (!g_strcasecmp(pdibuf, "NICK")) {
1089 if (!*word_eol[2])
1090 return;
1091 g_snprintf(buf, sizeof(buf), "NICK %s\r\n", word_eol[2]);
1092 irc_write(id->fd, buf, strlen(buf));
1093 } else if (!g_strcasecmp(pdibuf, "OP")) {
1094 set_mode(gc, who, '+', 'o', word);
1095 } else if (!g_strcasecmp(pdibuf, "DEOP")) {
1096 set_mode(gc, who, '-', 'o', word);
1097 } else if (!g_strcasecmp(pdibuf, "VOICE")) {
1098 set_mode(gc, who, '+', 'v', word);
1099 } else if (!g_strcasecmp(pdibuf, "DEVOICE")) {
1100 set_mode(gc, who, '-', 'v', word);
1101 } else if (!g_strcasecmp(pdibuf, "QUOTE")) {
1102 if (!*word_eol[2])
1103 return;
1104 g_snprintf(buf, sizeof(buf), "%s\r\n", word_eol[2]);
1105 irc_write(id->fd, buf, strlen(buf));
1106 } else if (!g_strcasecmp(pdibuf, "KICK")) {
1107 if (!*word[2])
1108 return;
1109 if (*word_eol[3])
1110 g_snprintf(buf, sizeof(buf), "KICK %s %s :%s", who, word[2], word_eol[3]);
1111 else
1112 g_snprintf(buf, sizeof(buf), "KICK %s %s", who, word[2]);
1113 irc_write(id->fd, buf, strlen(buf));
1114 } else if (!g_strcasecmp(pdibuf, "BAN")) {
1115 } else if (!g_strcasecmp(pdibuf, "KICKBAN")) {
1116 } else if (!g_strcasecmp(pdibuf, "JOIN")) {
1117 if (!*word[2])
1118 return;
1119 if (*word[3])
1120 g_snprintf(buf, sizeof(buf), "JOIN %s %s\r\n", word[2], word[3]);
1121 else
1122 g_snprintf(buf, sizeof(buf), "JOIN %s\r\n", word[2]);
1123 irc_write(id->fd, buf, strlen(buf));
1124 } else if (!g_strcasecmp(pdibuf, "PART")) {
1125 char *chan = *word[2] ? word[2] : who;
1126 char *reason = word_eol[3];
1127 struct conversation *c;
1128 if (!is_channel(gc, chan))
1129 return;
1130 c = irc_find_chat(gc, chan);
1131 g_snprintf(buf, sizeof(buf), "PART %s%s%s\r\n", chan,
1132 *reason ? " :" : "",
1133 *reason ? reason : "");
1134 irc_write(id->fd, buf, strlen(buf));
1135 if (c) {
1136 gc->buddy_chats = g_slist_remove(gc->buddy_chats, c);
1137 c->gc = NULL;
1138 g_snprintf(buf, sizeof(buf), _("You have left %s"), chan);
1139 do_error_dialog(buf, _("IRC Part"));
1140 }
1141 }
1142 }
1143
1144 static void send_msg(struct gaim_connection *gc, char *who, char *what)
1145 {
1146 char *cr = strchr(what, '\n');
1147 if (cr) {
1148 while (TRUE) {
1149 if (cr)
1150 *cr = 0;
1151 handle_command(gc, who, what);
1152 if (!cr)
1153 break;
1154 what = cr + 1;
1155 if (!*what)
1156 break;
1157 cr = strchr(what, '\n');
1158 }
1159 } else
1160 handle_command(gc, who, what);
1161 }
1162
1163 static int irc_send_im(struct gaim_connection *gc, char *who, char *what, int flags)
1164 {
1165 if (*who == '@' || *who == '+')
1166 send_msg(gc, who + 1, what);
1167 else
1168 send_msg(gc, who, what);
1169 return 0;
1170 }
1171
1172 /* IRC doesn't have a buddy list, but we can still figure out who's online with ISON */
1173 static void irc_fake_buddy(struct gaim_connection *gc, char *who) {}
1174
1175 static GList *irc_chat_info(struct gaim_connection *gc)
1176 {
1177 GList *m = NULL;
1178 struct proto_chat_entry *pce;
1179
1180 pce = g_new0(struct proto_chat_entry, 1);
1181 pce->label = _("Room:");
1182 m = g_list_append(m, pce);
1183
1184 pce = g_new0(struct proto_chat_entry, 1);
1185 pce->label = _("Password:");
1186 m = g_list_append(m, pce);
1187
1188 return m;
1189 }
1190
1191 static void irc_join_chat(struct gaim_connection *gc, GList *data)
1192 {
1193 struct irc_data *id = gc->proto_data;
1194 char buf[IRC_BUF_LEN];
1195 char *name, *pass;
1196
1197 if (!data)
1198 return;
1199 name = data->data;
1200 if (data->next)
1201 pass = data->next->data;
1202
1203 if (data->next)
1204 g_snprintf(buf, sizeof(buf), "JOIN %s %s\r\n", name, pass);
1205 else
1206 g_snprintf(buf, sizeof(buf), "JOIN %s\r\n", name);
1207 irc_write(id->fd, buf, strlen(buf));
1208 }
1209
1210 static void irc_chat_leave(struct gaim_connection *gc, int id)
1211 {
1212 struct irc_data *idata = gc->proto_data;
1213 struct conversation *c = irc_find_chat_by_id(gc, id);
1214 char buf[IRC_BUF_LEN];
1215
1216 if (!c) return;
1217
1218 g_snprintf(buf, sizeof(buf), "PART %s\r\n", c->name);
1219 irc_write(idata->fd, buf, strlen(buf));
1220 }
1221
1222 static int irc_chat_send(struct gaim_connection *gc, int id, char *what)
1223 {
1224 struct conversation *c = irc_find_chat_by_id(gc, id);
1225 if (!c)
1226 return -EINVAL;
1227 send_msg(gc, c->name, what);
1228 serv_got_chat_in(gc, c->id, gc->displayname, 0, what, time(NULL));
1229 return 0;
1230 }
1231
1232 static GList *irc_away_states()
1233 {
1234 return g_list_append(NULL, GAIM_AWAY_CUSTOM);
1235 }
1236
1237 static void irc_set_away(struct gaim_connection *gc, char *state, char *msg)
1238 {
1239 struct irc_data *idata = gc->proto_data;
1240 char buf[IRC_BUF_LEN];
1241
1242 if (msg)
1243 g_snprintf(buf, sizeof(buf), "AWAY :%s\r\n", msg);
1244 else
1245 g_snprintf(buf, sizeof(buf), "AWAY\r\n");
1246 irc_write(idata->fd, buf, strlen(buf));
1247 }
1248
1993 static char **irc_list_icon(int uc) 1249 static char **irc_list_icon(int uc)
1994 { 1250 {
1995 return free_icon_xpm; 1251 return irc_icon_xpm;
1996 }
1997
1998 /* Send out a ping request to the specified user */
1999 static void irc_send_ping(struct gaim_connection *gc, char *who)
2000 {
2001 struct irc_data *idata = (struct irc_data *)gc->proto_data;
2002 char buf[BUF_LEN];
2003
2004 g_snprintf(buf, BUF_LEN, "PRIVMSG %s :%cPING %ld%c\n", who, '\001', time((time_t *) NULL),
2005 '\001');
2006
2007 write(idata->fd, buf, strlen(buf));
2008 }
2009
2010 /* Do a whois check on someone :-) */
2011 static void irc_get_info(struct gaim_connection *gc, char *who)
2012 {
2013 struct irc_data *idata = (struct irc_data *)gc->proto_data;
2014 char buf[BUF_LEN];
2015
2016 if (((who[0] == '@') || (who[0] == '+')) && (strlen(who) > 1))
2017 g_snprintf(buf, BUF_LEN, "WHOIS %s\n", who + 1);
2018 else
2019 g_snprintf(buf, BUF_LEN, "WHOIS %s\n", who);
2020 write(idata->fd, buf, strlen(buf));
2021 }
2022
2023 static GList *irc_buddy_menu(struct gaim_connection *gc, char *who)
2024 {
2025 GList *m = NULL;
2026 struct proto_buddy_menu *pbm;
2027
2028 pbm = g_new0(struct proto_buddy_menu, 1);
2029 pbm->label = _("Ping");
2030 pbm->callback = irc_send_ping;
2031 pbm->gc = gc;
2032 m = g_list_append(m, pbm);
2033
2034 pbm = g_new0(struct proto_buddy_menu, 1);
2035 pbm->label = _("Whois");
2036 pbm->callback = irc_get_info;
2037 pbm->gc = gc;
2038 m = g_list_append(m, pbm);
2039
2040 return m;
2041 }
2042
2043
2044 static void irc_set_away(struct gaim_connection *gc, char *state, char *msg)
2045 {
2046 struct irc_data *idata = (struct irc_data *)gc->proto_data;
2047 char buf[BUF_LEN];
2048
2049 if (msg)
2050 g_snprintf(buf, BUF_LEN, "AWAY :%s\n", msg);
2051 else
2052 g_snprintf(buf, BUF_LEN, "AWAY\n");
2053
2054 write(idata->fd, buf, strlen(buf));
2055 }
2056
2057 static void irc_fake_buddy(struct gaim_connection *gc, char *who)
2058 {
2059 /* Heh, there is no buddy list. We fake it.
2060 * I just need this here so the add and remove buttons will
2061 * show up */
2062 }
2063
2064 static void irc_chat_set_topic(struct gaim_connection *gc, int id, char *topic)
2065 {
2066 struct irc_channel *ic = NULL;
2067 struct irc_data *idata = (struct irc_data *)gc->proto_data;
2068 char buf[BUF_LEN];
2069
2070 ic = find_channel_by_id(gc, id);
2071
2072 /* If we ain't in no channel, foo, gets outta da kitchen beeyotch */
2073 if (!ic)
2074 return;
2075
2076 /* Prepare our command */
2077 g_snprintf(buf, BUF_LEN, "TOPIC #%s :%s\n", ic->name, topic);
2078
2079 /* And send it */
2080 write(idata->fd, buf, strlen(buf));
2081 } 1252 }
2082 1253
2083 static struct prpl *my_protocol = NULL; 1254 static struct prpl *my_protocol = NULL;
2084 1255
2085 void irc_init(struct prpl *ret) 1256 void irc_init(struct prpl *ret)
2086 { 1257 {
2087 ret->protocol = PROTO_IRC; 1258 ret->protocol = PROTO_IRC;
2088 ret->options = OPT_PROTO_CHAT_TOPIC | OPT_PROTO_NO_PASSWORD; 1259 ret->options = OPT_PROTO_CHAT_TOPIC | OPT_PROTO_NO_PASSWORD;
2089 ret->name = irc_name; 1260 ret->name = irc_name;
1261 ret->user_opts = irc_user_opts;
2090 ret->list_icon = irc_list_icon; 1262 ret->list_icon = irc_list_icon;
2091 ret->buddy_menu = irc_buddy_menu;
2092 ret->user_opts = irc_user_opts;
2093 ret->login = irc_login; 1263 ret->login = irc_login;
2094 ret->close = irc_close; 1264 ret->close = irc_close;
2095 ret->send_im = irc_send_im; 1265 ret->send_im = irc_send_im;
1266 ret->add_buddy = irc_fake_buddy;
1267 ret->remove_buddy = irc_fake_buddy;
2096 ret->chat_info = irc_chat_info; 1268 ret->chat_info = irc_chat_info;
2097 ret->join_chat = irc_join_chat; 1269 ret->join_chat = irc_join_chat;
2098 ret->chat_leave = irc_chat_leave; 1270 ret->chat_leave = irc_chat_leave;
2099 ret->chat_send = irc_chat_send; 1271 ret->chat_send = irc_chat_send;
2100 ret->get_info = irc_get_info; 1272 ret->away_states = irc_away_states;
2101 ret->set_away = irc_set_away; 1273 ret->set_away = irc_set_away;
2102 ret->add_buddy = irc_fake_buddy;
2103 ret->remove_buddy = irc_fake_buddy;
2104 ret->chat_set_topic = irc_chat_set_topic;
2105 my_protocol = ret; 1274 my_protocol = ret;
2106 } 1275 }
2107 1276
2108 #ifndef STATIC 1277 #ifndef STATIC
2109 1278