Mercurial > pidgin
comparison plugins/irc.c @ 1011:4867280dbdc7
[gaim-migrate @ 1021]
The IRC pluggin is getting a little better. It is functional now.
It can send and receive messages. It can chat in a channel. That's about all
right now.
committer: Tailor Script <tailor@pidgin.im>
author | Rob Flynn <gaim@robflynn.com> |
---|---|
date | Fri, 20 Oct 2000 07:51:03 +0000 |
parents | 1b99caffcd98 |
children | 7e8dcc609b30 |
comparison
equal
deleted
inserted
replaced
1010:4dca3277ea15 | 1011:4867280dbdc7 |
---|---|
44 #include "gnome_applet_mgr.h" | 44 #include "gnome_applet_mgr.h" |
45 | 45 |
46 #include "pixmaps/cancel.xpm" | 46 #include "pixmaps/cancel.xpm" |
47 #include "pixmaps/ok.xpm" | 47 #include "pixmaps/ok.xpm" |
48 | 48 |
49 /* FIXME: We shouldn't have hard coded servers and ports :-) */ | |
50 #define IRC_SERVER "irc.mozilla.org" | |
51 #define IRC_PORT 6667 | |
52 | |
53 #define IRC_BUF_LEN 4096 | |
54 | |
55 static int chat_id = 0; | |
56 | |
57 struct irc_channel { | |
58 int id; | |
59 gchar *name; | |
60 }; | |
61 | |
62 struct irc_data { | |
63 int fd; | |
64 | |
65 GList *channels; | |
66 }; | |
67 | |
49 static char *irc_name() { | 68 static char *irc_name() { |
50 return "IRC"; | 69 return "IRC"; |
51 } | 70 } |
52 | 71 |
53 char *name() { | 72 char *name() { |
56 | 75 |
57 char *description() { | 76 char *description() { |
58 return "Allows gaim to use the IRC protocol"; | 77 return "Allows gaim to use the IRC protocol"; |
59 } | 78 } |
60 | 79 |
80 void irc_join_chat( struct gaim_connection *gc, int id, char *name) { | |
81 struct irc_data *idata = (struct irc_data *)gc->proto_data; | |
82 gchar *buf = (gchar *)g_malloc(IRC_BUF_LEN+1); | |
83 | |
84 g_snprintf(buf, IRC_BUF_LEN, "JOIN %s\n", name); | |
85 write(idata->fd, buf, strlen(buf)); | |
86 | |
87 g_free(buf); | |
88 } | |
89 | |
90 void irc_send_im( struct gaim_connection *gc, char *who, char *message, int away) { | |
91 | |
92 struct irc_data *idata = (struct irc_data *)gc->proto_data; | |
93 gchar *buf = (gchar *)g_malloc(IRC_BUF_LEN + 1); | |
94 | |
95 /* Before we actually send this, we should check to see if they're trying | |
96 * To issue a /me command and handle it properly. */ | |
97 | |
98 if ( (g_strncasecmp(message, "/me ", 4) == 0) && (strlen(message)>4)) { | |
99 /* We have /me!! We have /me!! :-) */ | |
100 | |
101 gchar *temp = (gchar *)g_malloc(IRC_BUF_LEN+1); | |
102 strcpy(temp, message+4); | |
103 g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG %s :%cACTION %s%c\n", who, '\001', temp, '\001'); | |
104 g_free(temp); | |
105 } | |
106 else | |
107 { | |
108 g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG %s :%s\n", who, message); | |
109 } | |
110 | |
111 write(idata->fd, buf, strlen(buf)); | |
112 | |
113 g_free(buf); | |
114 } | |
115 | |
116 int find_id_by_name(struct gaim_connection *gc, char *name) { | |
117 gchar *temp = (gchar *)g_malloc(IRC_BUF_LEN + 1); | |
118 GList *templist; | |
119 struct irc_channel *channel; | |
120 | |
121 templist = ((struct irc_data *)gc->proto_data)->channels; | |
122 | |
123 while (templist) { | |
124 channel = (struct irc_channel *)templist->data; | |
125 | |
126 g_snprintf(temp, IRC_BUF_LEN, "#%s", channel->name); | |
127 | |
128 if (g_strcasecmp(temp, name) == 0) { | |
129 g_free(temp); | |
130 return channel->id; | |
131 } | |
132 | |
133 templist = templist -> next; | |
134 } | |
135 | |
136 g_free(temp); | |
137 | |
138 /* Return -1 if we have no ID */ | |
139 return -1; | |
140 } | |
141 | |
142 struct irc_channel * find_channel_by_name(struct gaim_connection *gc, char *name) { | |
143 gchar *temp = (gchar *)g_malloc(IRC_BUF_LEN + 1); | |
144 GList *templist; | |
145 struct irc_channel *channel; | |
146 | |
147 templist = ((struct irc_data *)gc->proto_data)->channels; | |
148 | |
149 while (templist) { | |
150 channel = (struct irc_channel *)templist->data; | |
151 | |
152 g_snprintf(temp, IRC_BUF_LEN, "%s", channel->name); | |
153 | |
154 if (g_strcasecmp(temp, name) == 0) { | |
155 g_free(temp); | |
156 return channel; | |
157 } | |
158 | |
159 templist = templist -> next; | |
160 } | |
161 | |
162 g_free(temp); | |
163 | |
164 /* If we found nothing, return nothing :-) */ | |
165 return NULL; | |
166 } | |
167 | |
168 struct irc_channel * find_channel_by_id (struct gaim_connection *gc, int id) { | |
169 struct irc_data *idata = (struct irc_data *)gc->proto_data; | |
170 struct irc_channel *channel; | |
171 | |
172 GList *temp; | |
173 | |
174 temp = idata->channels; | |
175 | |
176 while (temp) { | |
177 channel = (struct irc_channel *)temp->data; | |
178 | |
179 if (channel->id == id) { | |
180 /* We've found our man */ | |
181 return channel; | |
182 } | |
183 | |
184 temp = temp->next; | |
185 } | |
186 | |
187 | |
188 /* If we didnt find one, return NULL */ | |
189 return NULL; | |
190 } | |
191 | |
192 void irc_chat_send( struct gaim_connection *gc, int id, char *message) { | |
193 | |
194 struct irc_data *idata = (struct irc_data *)gc->proto_data; | |
195 struct irc_channel *channel = g_new0(struct irc_channel, 1); | |
196 gchar *buf = (gchar *)g_malloc(IRC_BUF_LEN + 1); | |
197 | |
198 /* First lets get our current channel */ | |
199 channel = find_channel_by_id(gc, id); | |
200 | |
201 | |
202 if (!channel) { | |
203 /* If for some reason we've lost our channel, let's bolt */ | |
204 return; | |
205 } | |
206 | |
207 | |
208 /* Before we actually send this, we should check to see if they're trying | |
209 * To issue a /me command and handle it properly. */ | |
210 | |
211 if ( (g_strncasecmp(message, "/me ", 4) == 0) && (strlen(message)>4)) { | |
212 /* We have /me!! We have /me!! :-) */ | |
213 | |
214 gchar *temp = (gchar *)g_malloc(IRC_BUF_LEN+1); | |
215 strcpy(temp, message+4); | |
216 g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG #%s :%cACTION %s%c\n", channel->name, '\001', temp, '\001'); | |
217 g_free(temp); | |
218 } | |
219 else | |
220 { | |
221 g_snprintf(buf, IRC_BUF_LEN, "PRIVMSG #%s :%s\n", channel->name, message); | |
222 } | |
223 | |
224 write(idata->fd, buf, strlen(buf)); | |
225 | |
226 /* Since AIM expects us to receive the message we send, we gotta fake it */ | |
227 serv_got_chat_in(gc, id, gc->username, 0, message); | |
228 | |
229 g_free(buf); | |
230 } | |
231 | |
232 void irc_callback ( struct gaim_connection * gc ) { | |
233 | |
234 int i = 0; | |
235 char c; | |
236 gchar buf[4096]; | |
237 gchar **buf2; | |
238 int status; | |
239 struct irc_data *idata; | |
240 | |
241 idata = (struct irc_data *)gc->proto_data; | |
242 | |
243 do { | |
244 status = recv(idata->fd, &c, 1, 0); | |
245 | |
246 if (!status) | |
247 { | |
248 exit(1); | |
249 } | |
250 buf[i] = c; | |
251 i++; | |
252 } while (c != '\n'); | |
253 | |
254 buf[i] = '\0'; | |
255 | |
256 /* And remove that damned trailing \n */ | |
257 g_strchomp(buf); | |
258 | |
259 /* For now, lets display everything to the console too. Im such a bitch */ | |
260 printf("IRC:'%'s\n", buf); | |
261 | |
262 if ( (strstr(buf, " JOIN ")) && (buf[0] == ':') && (!strstr(buf, " NOTICE "))) { | |
263 | |
264 gchar u_channel[128]; | |
265 struct irc_channel *channel; | |
266 int id; | |
267 int j; | |
268 | |
269 for (j = 0, i = 1; buf[i] != '#'; j++, i++) { | |
270 } | |
271 | |
272 i++; | |
273 | |
274 strcpy(u_channel, buf+i); | |
275 | |
276 /* Looks like we're going to join the channel for real now. Let's create | |
277 * a valid channel structure and add it to our list. Let's make sure that | |
278 * we are not already in a channel first */ | |
279 | |
280 channel = find_channel_by_name(gc, u_channel); | |
281 | |
282 if (!channel) { | |
283 chat_id++; | |
284 | |
285 channel = g_new0(struct irc_channel, 1); | |
286 | |
287 channel->id = chat_id; | |
288 channel->name = strdup(u_channel); | |
289 | |
290 idata->channels = g_list_append(idata->channels, channel); | |
291 | |
292 serv_got_joined_chat(gc, chat_id, u_channel); | |
293 printf("IIII: I joined '%s' with a strlen() of '%d'\n", u_channel, strlen(u_channel)); | |
294 } else { | |
295 /* Someone else joined. */ | |
296 } | |
297 | |
298 return; | |
299 } | |
300 | |
301 if ( (strstr(buf, " PART ")) && (buf[0] == ':') && (!strstr(buf, " NOTICE "))) { | |
302 | |
303 gchar u_channel[128]; | |
304 gchar u_nick[128]; | |
305 | |
306 struct irc_channel *channel = g_new0(struct irc_channel, 1); | |
307 int id; | |
308 int j; | |
309 GList *test = NULL; | |
310 | |
311 for (j = 0, i = 1; buf[i] != '!'; j++, i++) { | |
312 u_nick[j] = buf[i]; | |
313 } | |
314 u_nick[j] = '\0'; | |
315 | |
316 i++; | |
317 | |
318 for (j = 0; buf[i] != '#'; j++, i++) { | |
319 } | |
320 | |
321 i++; | |
322 | |
323 strcpy(u_channel, buf+i); | |
324 | |
325 | |
326 /* Now, lets check to see if it was US that was leaving. If so, do the | |
327 * correct thing by closing up all of our old channel stuff. Otherwise, | |
328 * we should just print that someone left */ | |
329 | |
330 if (g_strcasecmp(u_nick, gc->username) == 0) { | |
331 | |
332 /* Looks like we're going to join the channel for real now. Let's create | |
333 * a valid channel structure and add it to our list */ | |
334 | |
335 channel = find_channel_by_name(gc, u_channel); | |
336 | |
337 if (!channel) { | |
338 return; | |
339 } | |
340 | |
341 serv_got_chat_left(gc, channel->id); | |
342 | |
343 idata->channels = g_list_remove(idata->channels, channel); | |
344 g_free(channel); | |
345 return; | |
346 } | |
347 | |
348 /* Otherwise, lets just say someone left */ | |
349 printf("%s has left #%s\n", u_nick, u_channel); | |
350 | |
351 return; | |
352 } | |
353 | |
354 if ( (strstr(buf, "PRIVMSG ")) && (buf[0] == ':')) { | |
355 gchar u_nick[128]; | |
356 gchar u_host[255]; | |
357 gchar u_command[32]; | |
358 gchar u_channel[128]; | |
359 gchar u_message[IRC_BUF_LEN]; | |
360 int j; | |
361 int msgcode = 0; | |
362 | |
363 for (j = 0, i = 1; buf[i] != '!'; j++, i++) { | |
364 u_nick[j] = buf[i]; | |
365 } | |
366 | |
367 u_nick[j] = '\0'; i++; | |
368 | |
369 for (j = 0; buf[i] != ' '; j++, i++) { | |
370 u_host[j] = buf[i]; | |
371 } | |
372 | |
373 u_host[j] = '\0'; i++; | |
374 | |
375 for (j = 0; buf[i] != ' '; j++, i++) { | |
376 u_command[j] = buf[i]; | |
377 } | |
378 | |
379 u_command[j] = '\0'; i++; | |
380 | |
381 for (j = 0; buf[i] != ':'; j++, i++) { | |
382 u_channel[j] = buf[i]; | |
383 } | |
384 | |
385 u_channel[j-1] = '\0'; i++; | |
386 | |
387 | |
388 /* Now that everything is parsed, the rest of this baby must be our message */ | |
389 strncpy(u_message, buf + i, IRC_BUF_LEN); | |
390 | |
391 /* Now, lets check the message to see if there's anything special in it */ | |
392 if (u_message[0] == '\001') { | |
393 if (g_strncasecmp(u_message, "\001ACTION ", 8) == 0) { | |
394 /* Looks like we have an action. Let's parse it a little */ | |
395 strcpy(buf, u_message); | |
396 | |
397 strcpy(u_message, "/me "); | |
398 for (j = 4, i = 8; buf[i] != '\001'; i++, j++) { | |
399 u_message[j] = buf[i]; | |
400 } | |
401 u_message[j] = '\0'; | |
402 } | |
403 } | |
404 | |
405 | |
406 /* Let's check to see if we have a channel on our hands */ | |
407 if (u_channel[0] == '#') { | |
408 /* Yup. We have a channel */ | |
409 int id; | |
410 | |
411 id = find_id_by_name(gc, u_channel); | |
412 if (id != -1) { | |
413 serv_got_chat_in(gc, id, u_nick, 0, u_message); | |
414 } | |
415 } | |
416 else { | |
417 /* Nope. Let's treat it as a private message */ | |
418 printf("JUST GOT AN IM!!\n"); | |
419 serv_got_im(gc, u_nick, u_message, 0); | |
420 } | |
421 | |
422 return; | |
423 } | |
424 | |
425 /* Let's parse PING requests so that we wont get booted for inactivity */ | |
426 | |
427 if (strncmp(buf, "PING :", 6) == 0) { | |
428 buf2 = g_strsplit(buf, ":", 1); | |
429 | |
430 /* Let's build a new response */ | |
431 g_snprintf(buf, IRC_BUF_LEN, "PONG :%s\n", buf2[1]); | |
432 write(idata->fd, buf, strlen(buf)); | |
433 | |
434 /* And clean up after ourselves */ | |
435 g_strfreev(buf2); | |
436 | |
437 return; | |
438 } | |
439 | |
440 } | |
441 | |
442 void irc_handler(gpointer data, gint source, GdkInputCondition condition) { | |
443 irc_callback(data); | |
444 } | |
445 | |
446 void irc_close(struct gaim_connection *gc) { | |
447 struct irc_data *idata = (struct irc_data *)gc->proto_data; | |
448 gchar *buf = (gchar *)g_malloc(IRC_BUF_LEN); | |
449 | |
450 g_snprintf(buf, IRC_BUF_LEN, "QUIT :GAIM [www.marko.net/gaim]\n"); | |
451 write(idata->fd, buf, strlen(buf)); | |
452 | |
453 g_free(buf); | |
454 close(idata->fd); | |
455 g_free(gc->proto_data); | |
456 } | |
457 | |
458 void irc_chat_leave(struct gaim_connection *gc, int id) { | |
459 struct irc_data *idata = (struct irc_data *)gc->proto_data; | |
460 struct irc_channel *channel; | |
461 gchar *buf = (gchar *)g_malloc(IRC_BUF_LEN+1); | |
462 | |
463 channel = find_channel_by_id(gc, id); | |
464 | |
465 if (!channel) { | |
466 return; | |
467 } | |
468 | |
469 g_snprintf(buf, IRC_BUF_LEN, "PART #%s\n", channel->name); | |
470 write(idata->fd, buf, strlen(buf)); | |
471 | |
472 g_free(buf); | |
473 } | |
474 | |
61 void irc_login(struct aim_user *user) { | 475 void irc_login(struct aim_user *user) { |
62 | 476 int fd; |
63 } | 477 struct hostent *host; |
64 | 478 struct sockaddr_in site; |
479 char buf[4096]; | |
480 | |
481 struct gaim_connection *gc = new_gaim_conn(PROTO_IRC, user->username, user->password); | |
482 struct irc_data *idata = gc->proto_data = g_new0(struct irc_data, 1); | |
483 char c; | |
484 int i; | |
485 int status; | |
486 | |
487 set_login_progress(gc, 1, buf); | |
488 | |
489 while (gtk_events_pending()) | |
490 gtk_main_iteration(); | |
491 | |
492 host = gethostbyname(IRC_SERVER); | |
493 if (!host) { | |
494 hide_login_progress(gc, "Unable to resolve hostname"); | |
495 destroy_gaim_conn(gc); | |
496 return; | |
497 } | |
498 | |
499 site.sin_family = AF_INET; | |
500 site.sin_addr.s_addr = *(long *)(host->h_addr); | |
501 site.sin_port = htons(IRC_PORT); | |
502 | |
503 fd = socket(AF_INET, SOCK_STREAM, 0); | |
504 if (fd < 0) { | |
505 hide_login_progress(gc, "Unable to create socket"); | |
506 destroy_gaim_conn(gc); | |
507 return; | |
508 } | |
509 | |
510 if (connect(fd, (struct sockaddr *)&site, sizeof(site)) < 0) { | |
511 hide_login_progress(gc, "Unable to connect."); | |
512 destroy_gaim_conn(gc); | |
513 return; | |
514 } | |
515 | |
516 idata->fd = fd; | |
517 | |
518 g_snprintf(buf, sizeof(buf), "Signon: %s", gc->username); | |
519 set_login_progress(gc, 2, buf); | |
520 | |
521 /* This is where we will attempt to sign on */ | |
522 | |
523 /* FIXME: This should be their servername, not their username. im just lazy right now */ | |
524 | |
525 g_snprintf(buf, 4096, "NICK %s\nUSER %s localhost %s :GAIM (www.marko.net/gaim)\n", gc->username, gc->username, gc->username); | |
526 write(idata->fd, buf, strlen(buf)); | |
527 | |
528 | |
529 /* Now lets sign ourselves on */ | |
530 account_online(gc); | |
531 | |
532 if (mainwindow) | |
533 gtk_widget_hide(mainwindow); | |
534 | |
535 show_buddy_list(); | |
536 refresh_buddy_window(); | |
537 | |
538 serv_finish_login(gc); | |
539 gaim_setup(gc); | |
540 | |
541 gc->inpa = gdk_input_add(idata->fd, GDK_INPUT_READ, irc_handler, gc); | |
542 } | |
65 | 543 |
66 struct prpl *irc_init() { | 544 struct prpl *irc_init() { |
67 struct prpl *ret = g_new0(struct prpl, 1); | 545 struct prpl *ret = g_new0(struct prpl, 1); |
68 | 546 |
69 ret->protocol = PROTO_IRC; | 547 ret->protocol = PROTO_IRC; |
70 ret->name = irc_name; | 548 ret->name = irc_name; |
71 ret->login = irc_login; | 549 ret->login = irc_login; |
72 ret->close = NULL; | 550 ret->close = irc_close; |
73 ret->send_im = NULL; | 551 ret->send_im = irc_send_im; |
74 ret->set_info = NULL; | 552 ret->set_info = NULL; |
75 ret->get_info = NULL; | 553 ret->get_info = NULL; |
76 ret->set_away = NULL; | 554 ret->set_away = NULL; |
77 ret->get_away_msg = NULL; | 555 ret->get_away_msg = NULL; |
78 ret->set_dir = NULL; | 556 ret->set_dir = NULL; |
85 ret->remove_buddy = NULL; | 563 ret->remove_buddy = NULL; |
86 ret->add_permit = NULL; | 564 ret->add_permit = NULL; |
87 ret->add_deny = NULL; | 565 ret->add_deny = NULL; |
88 ret->warn = NULL; | 566 ret->warn = NULL; |
89 ret->accept_chat = NULL; | 567 ret->accept_chat = NULL; |
90 ret->join_chat = NULL; | 568 ret->join_chat = irc_join_chat; |
91 ret->chat_invite = NULL; | 569 ret->chat_invite = NULL; |
92 ret->chat_leave = NULL; | 570 ret->chat_leave = irc_chat_leave; |
93 ret->chat_whisper = NULL; | 571 ret->chat_whisper = NULL; |
94 ret->chat_send = NULL; | 572 ret->chat_send = irc_chat_send; |
95 ret->keepalive = NULL; | 573 ret->keepalive = NULL; |
96 | 574 |
97 return ret; | 575 return ret; |
98 } | 576 } |
99 | 577 |