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 |
