Mercurial > pidgin
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 |