Mercurial > pidgin
comparison src/server.c @ 4359:5fb47ec9bfe4
[gaim-migrate @ 4625]
Wow, okay, where to begin with this one ;)
I rewrote the whole conversation backend. It is now core/UI split. Here's
how it works..
Every conversation is represented by a gaim_conversation structure. This
branches out into gaim_im and gaim_chat structures. Every conversation
lives in (well, normally, but it doesn't have to) a gaim_window structure.
This is a _CORE_ representation of a window. There can be multiple
gaim_window structures around.
The gaim_window and gaim_conversation structures have UI-specific operation
structures associated with them. At the moment, the only UI is GTK+, and
this will be for some time. Don't start thinking you can write a QT UI now.
It's just not going to happen.
Everything that is done on a conversation is done through the core API.
This API does core processing and then calls the UI operations for the
rendering and anything else.
Now, what does this give the user?
- Multiple windows.
- Multiple tabs per window.
- Draggable tabs.
- Send As menu is moved to the menubar.
- Menubar for chats.
- Some very cool stuff in the future, like replacing, say, IRC chat windows
with an X-Chat interface, or whatever.
- Later on, customizable window/conversation positioning.
For developers:
- Fully documented API
- Core/UI split
- Variable checking and mostly sane handling of incorrect variables.
- Logical structure to conversations, both core and UI.
- Some very cool stuff in the future, like replacing, say, IRC chat windows
with an X-Chat interface, or whatever.
- Later on, customizable window/conversation positioning.
- Oh yeah, and the beginning of a stock icon system.
Now, there are things that aren't there yet. You will see tabs even if you
have them turned off. This will be fixed in time. Also, the preferences
will change to work with the new structure. I'm starting school in 2 days,
so it may not be done immediately, but hopefully in the next week.
Enjoy!
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Mon, 20 Jan 2003 09:10:23 +0000 |
| parents | 0c68d402f59f |
| children | a8249a5250b6 |
comparison
equal
deleted
inserted
replaced
| 4358:2b8abf7f9cc1 | 4359:5fb47ec9bfe4 |
|---|---|
| 88 | 88 |
| 89 void serv_close(struct gaim_connection *gc) | 89 void serv_close(struct gaim_connection *gc) |
| 90 { | 90 { |
| 91 struct prpl *prpl; | 91 struct prpl *prpl; |
| 92 while (gc->buddy_chats) { | 92 while (gc->buddy_chats) { |
| 93 struct conversation *b = gc->buddy_chats->data; | 93 struct gaim_conversation *b = gc->buddy_chats->data; |
| 94 | |
| 94 gc->buddy_chats = g_slist_remove(gc->buddy_chats, b); | 95 gc->buddy_chats = g_slist_remove(gc->buddy_chats, b); |
| 95 b->gc = NULL; | 96 |
| 96 update_buttons_by_protocol(b); | 97 /* TODO: Nuke the UI-specific code here. */ |
| 98 if (gaim_conversation_get_ops(b) == gaim_get_gtk_conversation_ops()) | |
| 99 gaim_gtkconv_update_buttons_by_protocol(b); | |
| 97 } | 100 } |
| 98 | 101 |
| 99 if (gc->idle_timer > 0) | 102 if (gc->idle_timer > 0) |
| 100 g_source_remove(gc->idle_timer); | 103 g_source_remove(gc->idle_timer); |
| 101 gc->idle_timer = 0; | 104 gc->idle_timer = 0; |
| 160 time_t sent_away; | 163 time_t sent_away; |
| 161 }; | 164 }; |
| 162 | 165 |
| 163 struct queued_away_response *find_queued_away_response_by_name(char *name); | 166 struct queued_away_response *find_queued_away_response_by_name(char *name); |
| 164 | 167 |
| 165 int serv_send_im(struct gaim_connection *gc, char *name, char *message, int len, int flags) | 168 int serv_send_im(struct gaim_connection *gc, char *name, char *message, |
| 166 { | 169 int len, int flags) |
| 170 { | |
| 171 struct gaim_conversation *c; | |
| 167 int val = -EINVAL; | 172 int val = -EINVAL; |
| 168 struct conversation *cnv = find_conversation(name); | 173 |
| 174 c = gaim_find_conversation(name); | |
| 175 | |
| 169 if (gc->prpl && gc->prpl->send_im) | 176 if (gc->prpl && gc->prpl->send_im) |
| 170 val = gc->prpl->send_im(gc, name, message, len, flags); | 177 val = gc->prpl->send_im(gc, name, message, len, flags); |
| 171 | 178 |
| 172 if (!(flags & IM_FLAG_AWAY)) | 179 if (!(flags & IM_FLAG_AWAY)) |
| 173 serv_touch_idle(gc); | 180 serv_touch_idle(gc); |
| 185 away_time_queue = g_slist_append(away_time_queue, qar); | 192 away_time_queue = g_slist_append(away_time_queue, qar); |
| 186 } | 193 } |
| 187 qar->sent_away = t; | 194 qar->sent_away = t; |
| 188 } | 195 } |
| 189 | 196 |
| 190 if (cnv && cnv->type_again_timeout) | 197 if (c && gaim_im_get_type_again_timeout(GAIM_IM(c))) |
| 191 g_source_remove(cnv->type_again_timeout); | 198 gaim_im_stop_type_again_timeout(GAIM_IM(c)); |
| 192 | 199 |
| 193 return val; | 200 return val; |
| 194 } | 201 } |
| 195 | 202 |
| 196 void serv_get_info(struct gaim_connection *g, char *name) | 203 void serv_get_info(struct gaim_connection *g, char *name) |
| 209 { | 216 { |
| 210 if (g && g_slist_find(connections, g) && g->prpl && g->prpl->get_dir) | 217 if (g && g_slist_find(connections, g) && g->prpl && g->prpl->get_dir) |
| 211 g->prpl->get_dir(g, name); | 218 g->prpl->get_dir(g, name); |
| 212 } | 219 } |
| 213 | 220 |
| 214 void serv_set_dir(struct gaim_connection *g, const char *first, const char *middle, const char *last, const char *maiden, | 221 void serv_set_dir(struct gaim_connection *g, const char *first, |
| 215 const char *city, const char *state, const char *country, int web) | 222 const char *middle, const char *last, const char *maiden, |
| 223 const char *city, const char *state, const char *country, | |
| 224 int web) | |
| 216 { | 225 { |
| 217 if (g && g_slist_find(connections, g) && g->prpl && g->prpl->set_dir) | 226 if (g && g_slist_find(connections, g) && g->prpl && g->prpl->set_dir) |
| 218 g->prpl->set_dir(g, first, middle, last, maiden, city, state, country, web); | 227 g->prpl->set_dir(g, first, middle, last, maiden, city, state, |
| 219 } | 228 country, web); |
| 220 | 229 } |
| 221 void serv_dir_search(struct gaim_connection *g, const char *first, const char *middle, const char *last, const char *maiden, | 230 |
| 222 const char *city, const char *state, const char *country, const char *email) | 231 void serv_dir_search(struct gaim_connection *g, const char *first, |
| 232 const char *middle, const char *last, const char *maiden, | |
| 233 const char *city, const char *state, const char *country, | |
| 234 const char *email) | |
| 223 { | 235 { |
| 224 if (g && g_slist_find(connections, g) && g->prpl && g->prpl->dir_search) | 236 if (g && g_slist_find(connections, g) && g->prpl && g->prpl->dir_search) |
| 225 g->prpl->dir_search(g, first, middle, last, maiden, city, state, country, email); | 237 g->prpl->dir_search(g, first, middle, last, maiden, city, state, |
| 238 country, email); | |
| 226 } | 239 } |
| 227 | 240 |
| 228 | 241 |
| 229 void serv_set_away(struct gaim_connection *gc, char *state, char *message) | 242 void serv_set_away(struct gaim_connection *gc, char *state, char *message) |
| 230 { | 243 { |
| 530 } | 543 } |
| 531 | 544 |
| 532 return NULL; | 545 return NULL; |
| 533 } | 546 } |
| 534 | 547 |
| 535 /* woo. i'm actually going to comment this function. isn't that fun. make sure to follow along, kids */ | 548 /* |
| 536 void serv_got_im(struct gaim_connection *gc, char *name, char *message, guint32 flags, time_t mtime, gint len) | 549 * woo. i'm actually going to comment this function. isn't that fun. make |
| 550 * sure to follow along, kids | |
| 551 */ | |
| 552 void serv_got_im(struct gaim_connection *gc, char *name, char *message, | |
| 553 guint32 flags, time_t mtime, gint len) | |
| 537 { | 554 { |
| 538 char *buffy; | 555 char *buffy; |
| 539 char *angel; | 556 char *angel; |
| 540 int plugin_return; | 557 int plugin_return; |
| 541 int away = 0; | 558 int away = 0; |
| 542 | 559 |
| 543 struct conversation *cnv; | 560 struct gaim_conversation *cnv; |
| 544 int new_conv = 0; | 561 |
| 545 | 562 /* |
| 546 /* pay no attention to the man behind the curtain. | 563 * Pay no attention to the man behind the curtain. |
| 547 * | 564 * |
| 548 * the reason i feel okay with this is because it's useful to some plugins. | 565 * The reason i feel okay with this is because it's useful to some |
| 549 * Gaim doesn't ever use it itself. Besides, it's not entirely accurate; it's | 566 * plugins. Gaim doesn't ever use it itself. Besides, it's not entirely |
| 550 * possible to have false negatives with most protocols. Also with some it's | 567 * accurate; it's possible to have false negatives with most protocols. |
| 551 * easy to have false positives as well. So if you're a plugin author, don't | 568 * Also with some it's easy to have false positives as well. So if you're |
| 552 * rely on this, still do your own checks. but uh. it's a start. */ | 569 * a plugin author, don't rely on this, still do your own checks. But uh. |
| 570 * It's a start. | |
| 571 */ | |
| 572 | |
| 553 if (flags & IM_FLAG_GAIMUSER) | 573 if (flags & IM_FLAG_GAIMUSER) |
| 554 debug_printf("%s is a gaim user.\n", name); | 574 debug_printf("%s is a gaim user.\n", name); |
| 555 | 575 |
| 556 /* we should update the conversation window buttons and menu, if it exists. */ | 576 /* |
| 557 cnv = find_conversation(name); | 577 * We should update the conversation window buttons and menu, |
| 558 if (cnv) | 578 * if it exists. |
| 559 set_convo_gc(cnv, gc); | 579 */ |
| 560 /* we do the new_conv check here in case any plugins decide to create it */ | 580 cnv = gaim_find_conversation_with_user(name, gc->user); |
| 561 else | 581 |
| 562 new_conv = 1; | 582 /* |
| 563 | 583 * Plugin stuff. we pass a char ** but we don't want to pass what's |
| 564 /* plugin stuff. we pass a char ** but we don't want to pass what's been given us | 584 * been given us by the prpls. So we create temp holders and pass |
| 565 * by the prpls. so we create temp holders and pass those instead. it's basically | 585 * those instead. It's basically just to avoid segfaults. Of course, |
| 566 * just to avoid segfaults. of course, if the data is binary, plugins don't see it. | 586 * if the data is binary, plugins don't see it. Bitch all you want; |
| 567 * bitch all you want; i really don't want you to be dealing with it. */ | 587 * I really don't want you to be dealing with it. |
| 588 */ | |
| 568 if (len < 0) { | 589 if (len < 0) { |
| 569 buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); | 590 buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); |
| 570 strcpy(buffy, message); | 591 strcpy(buffy, message); |
| 571 angel = g_strdup(name); | 592 angel = g_strdup(name); |
| 572 plugin_return = plugin_event(event_im_recv, gc, &angel, &buffy, &flags); | 593 plugin_return = plugin_event(event_im_recv, gc, &angel, &buffy, &flags); |
| 584 name = g_strdup(name); | 605 name = g_strdup(name); |
| 585 message = g_memdup(message, len); | 606 message = g_memdup(message, len); |
| 586 } | 607 } |
| 587 | 608 |
| 588 #if 0 | 609 #if 0 |
| 589 /* TiK, using TOC, sends an automated message in order to get your away message. Now, | 610 /* |
| 590 * this is one of the biggest hacks I think I've seen. But, in order to be nice to | 611 * TiK, using TOC, sends an automated message in order to get your |
| 591 * TiK, we're going to give users the option to ignore it. */ | 612 * away message. Now, this is one of the biggest hacks I think I've |
| 592 if ((away_options & OPT_AWAY_TIK_HACK) && gc->away && strlen(gc->away) && (len < 0) && | 613 * seen. But, in order to be nice to TiK, we're going to give users |
| 614 * the option to ignore it. | |
| 615 */ | |
| 616 if ((away_options & OPT_AWAY_TIK_HACK) && gc->away && | |
| 617 strlen(gc->away) && (len < 0) && | |
| 618 | |
| 593 !strcmp(message, ">>>Automated Message: Getting Away Message<<<")) { | 619 !strcmp(message, ">>>Automated Message: Getting Away Message<<<")) { |
| 594 char *tmpmsg = stylize(awaymessage->message, MSG_LEN); | 620 char *tmpmsg = stylize(awaymessage->message, MSG_LEN); |
| 595 serv_send_im(gc, name, tmpmsg, -1, IM_FLAG_AWAY); | 621 serv_send_im(gc, name, tmpmsg, -1, IM_FLAG_AWAY); |
| 596 g_free(tmpmsg); | 622 g_free(tmpmsg); |
| 597 g_free(name); | 623 g_free(name); |
| 598 g_free(message); | 624 g_free(message); |
| 599 return; | 625 return; |
| 600 } | 626 } |
| 601 #endif | 627 #endif |
| 602 | 628 |
| 603 /* if you can't figure this out, stop reading right now. | 629 /* |
| 604 * "we're not worthy! we're not worthy!" */ | 630 * If you can't figure this out, stop reading right now. |
| 631 * "We're not worthy! We're not worthy!" | |
| 632 */ | |
| 605 if ((len < 0) && (convo_options & OPT_CONVO_SEND_LINKS)) | 633 if ((len < 0) && (convo_options & OPT_CONVO_SEND_LINKS)) |
| 606 linkify_text(message); | 634 linkify_text(message); |
| 607 | 635 |
| 608 /* um. when we call write_to_conv with the message we received, it's nice to pass whether | 636 /* |
| 609 * or not it was an auto-response. so if it was an auto-response, we set the appropriate | 637 * Um. When we call gaim_conversation_write with the message we received, |
| 610 * flag. this is just so prpls don't have to know about WFLAG_* (though some do anyway) */ | 638 * it's nice to pass whether or not it was an auto-response. So if it |
| 639 * was an auto-response, we set the appropriate flag. This is just so | |
| 640 * prpls don't have to know about WFLAG_* (though some do anyway) | |
| 641 */ | |
| 611 if (flags & IM_FLAG_AWAY) | 642 if (flags & IM_FLAG_AWAY) |
| 612 away = WFLAG_AUTO; | 643 away = WFLAG_AUTO; |
| 613 | 644 |
| 614 /* alright. two cases for how to handle this. either we're away or we're not. if we're not, | 645 /* |
| 615 * then it's easy. if we are, then there are three or four different ways of handling it | 646 * Alright. Two cases for how to handle this. Either we're away or |
| 616 * and different things we have to do for each. */ | 647 * we're not. If we're not, then it's easy. If we are, then there |
| 648 * are three or four different ways of handling it and different | |
| 649 * things we have to do for each. | |
| 650 */ | |
| 617 if (gc->away) { | 651 if (gc->away) { |
| 618 time_t t; | 652 time_t t; |
| 619 char *tmpmsg; | 653 char *tmpmsg; |
| 620 struct buddy *b = find_buddy(gc->user, name); | 654 struct buddy *b = find_buddy(gc->user, name); |
| 621 char *alias = b ? get_buddy_alias(b) : name; | 655 char *alias = b ? get_buddy_alias(b) : name; |
| 622 int row; | 656 int row; |
| 623 struct queued_away_response *qar; | 657 struct queued_away_response *qar; |
| 624 | 658 |
| 625 time(&t); | 659 time(&t); |
| 626 | 660 |
| 627 /* either we're going to queue it or not. Because of the way awayness currently | 661 /* |
| 628 * works, this is fucked up. it's possible for an account to be away without the | 662 * Either we're going to queue it or not. Because of the way |
| 629 * imaway dialog being shown. in fact, it's possible for *all* the accounts to be | 663 * awayness currently works, this is fucked up. It's possible |
| 630 * away without the imaway dialog being shown. so in order for this to be queued | 664 * for an account to be away without the imaway dialog being |
| 631 * properly, we have to make sure that the imaway dialog actually exists, first. */ | 665 * shown. In fact, it's possible for *all* the accounts to be |
| 666 * away without the imaway dialog being shown. So in order for | |
| 667 * this to be queued properly, we have to make sure that the | |
| 668 * imaway dialog actually exists, first. | |
| 669 */ | |
| 632 if (!cnv && clistqueue && (away_options & OPT_AWAY_QUEUE)) { | 670 if (!cnv && clistqueue && (away_options & OPT_AWAY_QUEUE)) { |
| 633 /* alright, so we're going to queue it. neat, eh? :) so first we create | 671 /* |
| 634 * something to store the message, and add it to our queue. Then we update | 672 * Alright, so we're going to queue it. Neat, eh? :) |
| 635 * the away dialog to indicate that we've queued something. */ | 673 * So first we create something to store the message, and add |
| 674 * it to our queue. Then we update the away dialog to indicate | |
| 675 * that we've queued something. | |
| 676 */ | |
| 636 struct queued_message *qm; | 677 struct queued_message *qm; |
| 637 | 678 |
| 638 qm = g_new0(struct queued_message, 1); | 679 qm = g_new0(struct queued_message, 1); |
| 639 g_snprintf(qm->name, sizeof(qm->name), "%s", name); | 680 g_snprintf(qm->name, sizeof(qm->name), "%s", name); |
| 640 qm->message = g_memdup(message, len == -1 ? strlen(message) + 1 : len); | 681 qm->message = g_memdup(message, len == -1 ? strlen(message) + 1 : len); |
| 659 heh[0] = qm->name; | 700 heh[0] = qm->name; |
| 660 heh[1] = _("(1 message)"); | 701 heh[1] = _("(1 message)"); |
| 661 gtk_clist_append(GTK_CLIST(clistqueue), heh); | 702 gtk_clist_append(GTK_CLIST(clistqueue), heh); |
| 662 } | 703 } |
| 663 } else { | 704 } else { |
| 664 /* ok, so we're not queuing it. well then, we'll try to handle it normally. | 705 /* |
| 665 * Some people think that ignoring it is a perfectly acceptible way to handle | 706 * Ok, so we're not queuing it. Well then, we'll try to handle |
| 666 * it. i think they're on crack, but hey, that's why it's optional. */ | 707 * it normally. Some people think that ignoring it is a perfectly |
| 708 * acceptible way to handle it. I think they're on crack, but | |
| 709 * hey, that's why it's optional. | |
| 710 */ | |
| 667 if (away_options & OPT_AWAY_DISCARD) { | 711 if (away_options & OPT_AWAY_DISCARD) { |
| 668 g_free(name); | 712 g_free(name); |
| 669 g_free(message); | 713 g_free(message); |
| 670 return; | 714 return; |
| 671 } | 715 } |
| 672 | 716 |
| 673 /* ok, so we're not ignoring it. make sure the conversation exists and is | 717 /* |
| 674 * updated (partly handled above already), play the receive sound (sound.c | 718 * Ok, so we're not ignoring it. Make sure the conversation |
| 675 * will take care of not playing while away), and then write it to the | 719 * exists and is updated (partly handled above already), play |
| 676 * convo window. */ | 720 * the receive sound (sound.c will take care of not playing |
| 721 * while away), and then write it to the convo window. | |
| 722 */ | |
| 677 if (cnv == NULL) { | 723 if (cnv == NULL) { |
| 678 cnv = new_conversation(name); | 724 cnv = gaim_conversation_new(GAIM_CONV_IM, name); |
| 679 set_convo_gc(cnv, gc); | 725 gaim_conversation_set_user(cnv, gc->user); |
| 680 } | 726 } |
| 681 if (new_conv && (sound_options & OPT_SOUND_FIRST_RCV)) | 727 |
| 682 play_sound(SND_FIRST_RECEIVE); | 728 gaim_im_write(GAIM_IM(cnv), NULL, message, len, |
| 683 else if (cnv->makesound) | 729 away | WFLAG_RECV, mtime); |
| 684 play_sound(SND_RECEIVE); | 730 } |
| 685 | 731 |
| 686 write_to_conv(cnv, message, away | WFLAG_RECV, NULL, mtime, len); | 732 /* |
| 687 } | 733 * Regardless of whether we queue it or not, we should send an |
| 688 | 734 * auto-response. That is, of course, unless the horse.... no wait. |
| 689 /* regardless of whether we queue it or not, we should send an auto-response. | 735 * Don't autorespond if: |
| 690 * that is, of course, unless the horse.... no wait. don't autorespond if: | 736 * |
| 691 * - it's not supported on this connection | 737 * - it's not supported on this connection |
| 692 * - or it's disabled | 738 * - or it's disabled |
| 693 * - or the away message is empty | 739 * - or the away message is empty |
| 694 * - or we're not idle and the 'only auto respond if idle' pref is set | 740 * - or we're not idle and the 'only auto respond if idle' pref |
| 741 * is set | |
| 695 */ | 742 */ |
| 696 if (!(gc->flags & OPT_CONN_AUTO_RESP) || (away_options & OPT_AWAY_NO_AUTO_RESP) || | 743 if (!(gc->flags & OPT_CONN_AUTO_RESP) || |
| 697 !strlen(gc->away) || ((away_options & OPT_AWAY_IDLE_RESP) && !gc->is_idle)) { | 744 (away_options & OPT_AWAY_NO_AUTO_RESP) || !strlen(gc->away) || |
| 745 ((away_options & OPT_AWAY_IDLE_RESP) && !gc->is_idle)) { | |
| 746 | |
| 698 g_free(name); | 747 g_free(name); |
| 699 g_free(message); | 748 g_free(message); |
| 700 return; | 749 return; |
| 701 } | 750 } |
| 702 | 751 |
| 703 /* this used to be based on the conversation window. but um, if you went away, and | 752 /* |
| 704 * someone sent you a message and got your auto-response, and then you closed the | 753 * This used to be based on the conversation window. But um, if |
| 705 * window, and then the sent you another one, they'd get the auto-response back | 754 * you went away, and someone sent you a message and got your |
| 706 * too soon. besides that, we need to keep track of this even if we've got a queue. | 755 * auto-response, and then you closed the window, and then the |
| 707 * so the rest of this block is just the auto-response, if necessary */ | 756 * sent you another one, they'd get the auto-response back too |
| 757 * soon. Besides that, we need to keep track of this even if we've | |
| 758 * got a queue. So the rest of this block is just the auto-response, | |
| 759 * if necessary | |
| 760 */ | |
| 708 qar = find_queued_away_response_by_name(name); | 761 qar = find_queued_away_response_by_name(name); |
| 709 if (!qar) { | 762 if (!qar) { |
| 710 qar = (struct queued_away_response *)g_new0(struct queued_away_response, 1); | 763 qar = (struct queued_away_response *)g_new0(struct queued_away_response, 1); |
| 711 g_snprintf(qar->name, sizeof(qar->name), "%s", name); | 764 g_snprintf(qar->name, sizeof(qar->name), "%s", name); |
| 712 qar->sent_away = 0; | 765 qar->sent_away = 0; |
| 731 qm->tm = mtime; | 784 qm->tm = mtime; |
| 732 qm->flags = WFLAG_SEND | WFLAG_AUTO; | 785 qm->flags = WFLAG_SEND | WFLAG_AUTO; |
| 733 qm->len = -1; | 786 qm->len = -1; |
| 734 message_queue = g_slist_append(message_queue, qm); | 787 message_queue = g_slist_append(message_queue, qm); |
| 735 } else if (cnv != NULL) | 788 } else if (cnv != NULL) |
| 736 write_to_conv(cnv, away_subs(tmpmsg, alias), WFLAG_SEND | WFLAG_AUTO, NULL, | 789 gaim_im_write(GAIM_IM(cnv), NULL, away_subs(tmpmsg, alias), |
| 737 mtime, len); | 790 len, WFLAG_SEND | WFLAG_AUTO, mtime); |
| 791 | |
| 738 g_free(tmpmsg); | 792 g_free(tmpmsg); |
| 739 } else { | 793 } else { |
| 740 /* we're not away. this is easy. if the convo window doesn't exist, create and update | 794 /* |
| 741 * it (if it does exist it was updated earlier), then play a sound indicating we've | 795 * We're not away. This is easy. If the convo window doesn't |
| 742 * received it and then display it. easy. */ | 796 * exist, create and update it (if it does exist it was updated |
| 743 | 797 * earlier), then play a sound indicating we've received it and |
| 744 if (new_conv && (sound_options & OPT_SOUND_FIRST_RCV)) | 798 * then display it. Easy. |
| 745 play_sound(SND_FIRST_RECEIVE); | 799 */ |
| 746 else if (new_conv || cnv->makesound) | 800 if (away_options & OPT_AWAY_QUEUE_UNREAD && |
| 747 play_sound(SND_RECEIVE); | 801 !gaim_find_conversation(name) && docklet_count) { |
| 748 | 802 |
| 749 if (away_options & OPT_AWAY_QUEUE_UNREAD && !find_conversation(name) && docklet_count) { | 803 /* |
| 750 /* We're gonna queue it up and wait for the user to ask for it... probably | 804 * We're gonna queue it up and wait for the user to ask for |
| 751 * by clicking the docklet or windows tray icon. */ | 805 * it... probably by clicking the docklet or windows tray icon. |
| 806 */ | |
| 752 struct queued_message *qm; | 807 struct queued_message *qm; |
| 753 qm = g_new0(struct queued_message, 1); | 808 qm = g_new0(struct queued_message, 1); |
| 754 g_snprintf(qm->name, sizeof(qm->name), "%s", name); | 809 g_snprintf(qm->name, sizeof(qm->name), "%s", name); |
| 755 qm->message = g_strdup(message); | 810 qm->message = g_strdup(message); |
| 756 qm->gc = gc; | 811 qm->gc = gc; |
| 758 qm->flags = away | WFLAG_RECV; | 813 qm->flags = away | WFLAG_RECV; |
| 759 qm->len = len; | 814 qm->len = len; |
| 760 unread_message_queue = g_slist_append(unread_message_queue, qm); | 815 unread_message_queue = g_slist_append(unread_message_queue, qm); |
| 761 } else { | 816 } else { |
| 762 if (cnv == NULL) { | 817 if (cnv == NULL) { |
| 763 cnv = new_conversation(name); | 818 cnv = gaim_conversation_new(GAIM_CONV_IM, name); |
| 764 set_convo_gc(cnv, gc); | 819 gaim_conversation_set_user(cnv, gc->user); |
| 765 } | 820 } |
| 766 | 821 |
| 767 set_convo_name(cnv, name); | 822 /* CONV XXX gaim_conversation_set_name(cnv, name); */ |
| 768 | 823 |
| 769 write_to_conv(cnv, message, away | WFLAG_RECV, NULL, mtime, len); | 824 gaim_im_write(GAIM_IM(cnv), NULL, message, len, |
| 770 #ifdef _WIN32 | 825 away | WFLAG_RECV, mtime); |
| 771 wgaim_im_blink(cnv->window); | 826 gaim_window_flash(gaim_conversation_get_window(cnv)); |
| 772 #endif | 827 } |
| 773 } | 828 } |
| 774 } | 829 |
| 775 plugin_event(event_im_displayed_rcvd, gc, name, message, flags, mtime); | 830 plugin_event(event_im_displayed_rcvd, gc, name, message, flags, mtime); |
| 776 g_free(name); | 831 g_free(name); |
| 777 g_free(message); | 832 g_free(message); |
| 778 } | 833 } |
| 779 | 834 |
| 780 | 835 |
| 781 | 836 |
| 782 void serv_got_update(struct gaim_connection *gc, char *name, int loggedin, int evil, time_t signon, | 837 void serv_got_update(struct gaim_connection *gc, char *name, int loggedin, |
| 783 time_t idle, int type, guint caps) | 838 int evil, time_t signon, time_t idle, int type, guint caps) |
| 784 { | 839 { |
| 785 struct buddy *b = find_buddy(gc->user, name); | 840 struct buddy *b = find_buddy(gc->user, name); |
| 786 | 841 |
| 787 if (signon && (gc->prpl->options & OPT_PROTO_CORRECT_TIME)) { | 842 if (signon && (gc->prpl->options & OPT_PROTO_CORRECT_TIME)) { |
| 788 char *tmp = g_strdup(normalize(name)); | 843 char *tmp = g_strdup(normalize(name)); |
| 868 return; | 923 return; |
| 869 } | 924 } |
| 870 | 925 |
| 871 gc->evil = lev; | 926 gc->evil = lev; |
| 872 | 927 |
| 873 g_snprintf(buf2, sizeof(buf2), _("%s has just been warned by %s.\nYour new warning level is %d%%"), | 928 g_snprintf(buf2, sizeof(buf2), |
| 874 gc->username, ((name == NULL)? _("an anonymous person") : name), lev); | 929 _("%s has just been warned by %s.\n" |
| 930 "Your new warning level is %d%%"), | |
| 931 gc->username, | |
| 932 ((name == NULL)? _("an anonymous person") : name), lev); | |
| 875 | 933 |
| 876 do_error_dialog(buf2, NULL, GAIM_INFO); | 934 do_error_dialog(buf2, NULL, GAIM_INFO); |
| 877 } | 935 } |
| 878 | 936 |
| 879 void serv_got_typing(struct gaim_connection *gc, char *name, int timeout, int state) { | 937 void serv_got_typing(struct gaim_connection *gc, char *name, int timeout, |
| 880 struct conversation *cnv = find_conversation(name); | 938 int state) { |
| 881 if (cnv) { | 939 |
| 882 set_convo_gc(cnv, gc); | 940 struct gaim_conversation *cnv = gaim_find_conversation(name); |
| 883 cnv->typing_state = state; | 941 struct gaim_im *im; |
| 884 update_convo_status(cnv); | 942 |
| 885 } else return; | 943 if (!cnv) |
| 886 plugin_event(event_got_typing, gc, name); | 944 return; |
| 887 do_pounce(gc, name, OPT_POUNCE_TYPING); | 945 |
| 888 if (timeout > 0) { | 946 im = GAIM_IM(cnv); |
| 889 if (cnv->typing_timeout) | 947 |
| 890 g_source_remove (cnv->typing_timeout); | 948 gaim_conversation_set_user(cnv, gc->user); |
| 891 cnv->typing_timeout = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, | 949 gaim_im_set_typing_state(im, state); |
| 892 timeout * 1000, reset_typing, g_strdup(name), g_free); | 950 gaim_im_update_typing(im); |
| 893 } | 951 |
| 952 plugin_event(event_got_typing, gc, name); | |
| 953 do_pounce(gc, name, OPT_POUNCE_TYPING); | |
| 954 | |
| 955 if (timeout > 0) | |
| 956 gaim_im_start_typing_timeout(im, timeout); | |
| 894 } | 957 } |
| 895 | 958 |
| 896 void serv_got_typing_stopped(struct gaim_connection *gc, char *name) { | 959 void serv_got_typing_stopped(struct gaim_connection *gc, char *name) { |
| 897 struct conversation *c = find_conversation(name); | 960 |
| 898 if(!c) | 961 struct gaim_conversation *c = gaim_find_conversation(name); |
| 962 struct gaim_im *im; | |
| 963 | |
| 964 if (!c) | |
| 899 return; | 965 return; |
| 900 if (c->typing_timeout) { | 966 |
| 901 g_source_remove(c->typing_timeout); | 967 im = GAIM_IM(c); |
| 902 c->typing_timeout=0; | 968 |
| 903 } | 969 gaim_im_stop_typing_timeout(im); |
| 904 c->typing_state = NOT_TYPING; | 970 gaim_im_set_typing_state(im, NOT_TYPING); |
| 905 update_convo_status(c); | 971 gaim_im_update_typing(im); |
| 906 } | 972 } |
| 907 | 973 |
| 908 static void close_invite(GtkWidget *w, GtkWidget *w2) | 974 static void close_invite(GtkWidget *w, GtkWidget *w2) |
| 909 { | 975 { |
| 910 GList *str = gtk_object_get_user_data(GTK_OBJECT(w2)); | 976 GList *str = gtk_object_get_user_data(GTK_OBJECT(w2)); |
| 943 gtk_widget_destroy(w2); | 1009 gtk_widget_destroy(w2); |
| 944 } | 1010 } |
| 945 | 1011 |
| 946 | 1012 |
| 947 | 1013 |
| 948 void serv_got_chat_invite(struct gaim_connection *g, char *name, char *who, char *message, GList *data) | 1014 void serv_got_chat_invite(struct gaim_connection *g, char *name, |
| 1015 char *who, char *message, GList *data) | |
| 949 { | 1016 { |
| 950 GtkWidget *d; | 1017 GtkWidget *d; |
| 951 GtkWidget *label; | 1018 GtkWidget *label; |
| 952 GtkWidget *yesbtn; | 1019 GtkWidget *yesbtn; |
| 953 GtkWidget *nobtn; | 1020 GtkWidget *nobtn; |
| 956 | 1023 |
| 957 | 1024 |
| 958 plugin_event(event_chat_invited, g, who, name, message); | 1025 plugin_event(event_chat_invited, g, who, name, message); |
| 959 | 1026 |
| 960 if (message) | 1027 if (message) |
| 961 g_snprintf(buf2, sizeof(buf2), _("User '%s' invites %s to buddy chat room: '%s'\n%s"), who, | 1028 g_snprintf(buf2, sizeof(buf2), |
| 962 g->username, name, message); | 1029 _("User '%s' invites %s to buddy chat room: '%s'\n%s"), |
| 1030 who, g->username, name, message); | |
| 963 else | 1031 else |
| 964 g_snprintf(buf2, sizeof(buf2), _("User '%s' invites %s to buddy chat room: '%s'\n"), who, | 1032 g_snprintf(buf2, sizeof(buf2), |
| 965 g->username, name); | 1033 _("User '%s' invites %s to buddy chat room: '%s'\n"), |
| 1034 who, g->username, name); | |
| 966 | 1035 |
| 967 d = gtk_dialog_new(); | 1036 d = gtk_dialog_new(); |
| 968 gtk_widget_realize(d); | 1037 gtk_widget_realize(d); |
| 969 | 1038 |
| 970 | 1039 |
| 980 gtk_object_set_user_data(GTK_OBJECT(GTK_DIALOG(d)->vbox), g); | 1049 gtk_object_set_user_data(GTK_OBJECT(GTK_DIALOG(d)->vbox), g); |
| 981 gtk_object_set_user_data(GTK_OBJECT(d), data); | 1050 gtk_object_set_user_data(GTK_OBJECT(d), data); |
| 982 | 1051 |
| 983 | 1052 |
| 984 gtk_window_set_title(GTK_WINDOW(d), _("Buddy chat invite")); | 1053 gtk_window_set_title(GTK_WINDOW(d), _("Buddy chat invite")); |
| 985 g_signal_connect(GTK_OBJECT(nobtn), "clicked", G_CALLBACK(close_invite), d); | 1054 g_signal_connect(G_OBJECT(nobtn), "clicked", |
| 986 g_signal_connect(GTK_OBJECT(yesbtn), "clicked", G_CALLBACK(chat_invite_callback), d); | 1055 G_CALLBACK(close_invite), d); |
| 987 | 1056 g_signal_connect(G_OBJECT(yesbtn), "clicked", |
| 1057 G_CALLBACK(chat_invite_callback), d); | |
| 988 | 1058 |
| 989 gtk_widget_show(d); | 1059 gtk_widget_show(d); |
| 990 } | 1060 } |
| 991 | 1061 |
| 992 struct conversation *serv_got_joined_chat(struct gaim_connection *gc, int id, char *name) | 1062 struct gaim_conversation *serv_got_joined_chat(struct gaim_connection *gc, |
| 993 { | 1063 int id, char *name) |
| 994 struct conversation *b; | 1064 { |
| 995 | 1065 struct gaim_conversation *b; |
| 996 b = (struct conversation *)g_new0(struct conversation, 1); | 1066 struct gaim_chat *chat; |
| 1067 | |
| 1068 b = gaim_conversation_new(GAIM_CONV_CHAT, name); | |
| 1069 chat = GAIM_CHAT(b); | |
| 1070 | |
| 997 gc->buddy_chats = g_slist_append(gc->buddy_chats, b); | 1071 gc->buddy_chats = g_slist_append(gc->buddy_chats, b); |
| 998 chats = g_list_append(chats, b); | 1072 |
| 999 | 1073 gaim_chat_set_id(chat, id); |
| 1000 b->is_chat = TRUE; | 1074 gaim_conversation_set_user(b, gc->user); |
| 1001 b->ignored = NULL; | |
| 1002 b->in_room = NULL; | |
| 1003 b->id = id; | |
| 1004 b->gc = gc; | |
| 1005 b->send_history = g_list_append(NULL, NULL); | |
| 1006 b->history = g_string_new(""); | |
| 1007 g_snprintf(b->name, 80, "%s", name); | |
| 1008 | 1075 |
| 1009 if ((logging_options & OPT_LOG_CHATS) || find_log_info(b->name)) { | 1076 if ((logging_options & OPT_LOG_CHATS) || |
| 1077 find_log_info(gaim_conversation_get_name(b))) { | |
| 1078 | |
| 1010 FILE *fd; | 1079 FILE *fd; |
| 1011 char *filename; | 1080 char *filename; |
| 1012 | 1081 |
| 1013 filename = (char *)malloc(100); | 1082 filename = (char *)malloc(100); |
| 1014 g_snprintf(filename, 100, "%s.chat", b->name); | 1083 g_snprintf(filename, 100, "%s.chat", gaim_conversation_get_name(b)); |
| 1015 | 1084 |
| 1016 fd = open_log_file(filename, b->is_chat); | 1085 fd = open_log_file(filename, TRUE); |
| 1086 | |
| 1017 if (fd) { | 1087 if (fd) { |
| 1018 if (!(logging_options & OPT_LOG_STRIP_HTML)) | 1088 if (!(logging_options & OPT_LOG_STRIP_HTML)) |
| 1019 fprintf(fd, | 1089 fprintf(fd, |
| 1020 "<HR><BR><H3 Align=Center> ---- New Conversation @ %s ----</H3><BR>\n", | 1090 "<HR><BR><H3 Align=Center> ---- New Conversation @ %s ----</H3><BR>\n", |
| 1021 full_date()); | 1091 full_date()); |
| 1025 fclose(fd); | 1095 fclose(fd); |
| 1026 } | 1096 } |
| 1027 free(filename); | 1097 free(filename); |
| 1028 } | 1098 } |
| 1029 | 1099 |
| 1030 show_new_buddy_chat(b); | 1100 gaim_window_show(gaim_conversation_get_window(b)); |
| 1101 gaim_window_switch_conversation(gaim_conversation_get_window(b), | |
| 1102 gaim_conversation_get_index(b)); | |
| 1031 | 1103 |
| 1032 plugin_event(event_chat_join, gc, id, name); | 1104 plugin_event(event_chat_join, gc, id, name); |
| 1033 | 1105 |
| 1034 return b; | 1106 return b; |
| 1035 } | 1107 } |
| 1036 | 1108 |
| 1037 void serv_got_chat_left(struct gaim_connection *g, int id) | 1109 void serv_got_chat_left(struct gaim_connection *g, int id) |
| 1038 { | 1110 { |
| 1039 GSList *bcs = g->buddy_chats; | 1111 GSList *bcs; |
| 1040 struct conversation *b = NULL; | 1112 struct gaim_conversation *conv = NULL; |
| 1041 | 1113 struct gaim_chat *chat = NULL; |
| 1042 | 1114 |
| 1043 while (bcs) { | 1115 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { |
| 1044 b = (struct conversation *)bcs->data; | 1116 conv = (struct gaim_conversation *)bcs->data; |
| 1045 if (id == b->id) { | 1117 |
| 1118 chat = GAIM_CHAT(conv); | |
| 1119 | |
| 1120 if (gaim_chat_get_id(chat) == id) | |
| 1046 break; | 1121 break; |
| 1047 } | 1122 |
| 1048 b = NULL; | 1123 conv = NULL; |
| 1049 bcs = bcs->next; | 1124 } |
| 1050 } | 1125 |
| 1051 | 1126 if (!conv) |
| 1052 if (!b) | |
| 1053 return; | 1127 return; |
| 1054 | 1128 |
| 1055 plugin_event(event_chat_leave, g, b->id); | 1129 plugin_event(event_chat_leave, g, gaim_chat_get_id(chat)); |
| 1056 | 1130 |
| 1057 debug_printf("Leaving room %s.\n", b->name); | 1131 debug_printf("Leaving room %s.\n", gaim_conversation_get_name(conv)); |
| 1058 | 1132 |
| 1059 g->buddy_chats = g_slist_remove(g->buddy_chats, b); | 1133 g->buddy_chats = g_slist_remove(g->buddy_chats, conv); |
| 1060 | 1134 |
| 1061 delete_chat(b); | 1135 gaim_conversation_destroy(conv); |
| 1062 } | 1136 } |
| 1063 | 1137 |
| 1064 void serv_got_chat_in(struct gaim_connection *g, int id, char *who, int whisper, char *message, | 1138 void serv_got_chat_in(struct gaim_connection *g, int id, char *who, |
| 1065 time_t mtime) | 1139 int whisper, char *message, time_t mtime) |
| 1066 { | 1140 { |
| 1067 int w; | 1141 int w; |
| 1068 GSList *bcs = g->buddy_chats; | 1142 GSList *bcs; |
| 1069 struct conversation *b = NULL; | 1143 struct gaim_conversation *conv = NULL; |
| 1144 struct gaim_chat *chat = NULL; | |
| 1070 char *buf; | 1145 char *buf; |
| 1071 char *buffy, *angel; | 1146 char *buffy, *angel; |
| 1072 int plugin_return; | 1147 int plugin_return; |
| 1073 | 1148 |
| 1074 while (bcs) { | 1149 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { |
| 1075 b = (struct conversation *)bcs->data; | 1150 conv = (struct gaim_conversation *)bcs->data; |
| 1076 if (id == b->id) | 1151 |
| 1152 chat = GAIM_CHAT(conv); | |
| 1153 | |
| 1154 if (gaim_chat_get_id(chat) == id) | |
| 1077 break; | 1155 break; |
| 1078 bcs = bcs->next; | 1156 |
| 1079 b = NULL; | 1157 conv = NULL; |
| 1080 | 1158 } |
| 1081 } | 1159 |
| 1082 if (!b) | 1160 if (!conv) |
| 1083 return; | 1161 return; |
| 1084 | 1162 |
| 1085 | 1163 /* |
| 1086 /* plugin stuff. we pass a char ** but we don't want to pass what's been given us | 1164 * Plugin stuff. We pass a char ** but we don't want to pass what's |
| 1087 * by the prpls. so we create temp holders and pass those instead. it's basically | 1165 * been given us by the prpls. so we create temp holders and pass those |
| 1088 * just to avoid segfaults. of course, if the data is binary, plugins don't see it. | 1166 * instead. It's basically just to avoid segfaults. Of course, if the |
| 1089 * bitch all you want; i really don't want you to be dealing with it. */ | 1167 * data is binary, plugins don't see it. Bitch all you want; i really |
| 1090 | 1168 * don't want you to be dealing with it. |
| 1169 */ | |
| 1170 | |
| 1091 buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); | 1171 buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); |
| 1092 strcpy(buffy, message); | 1172 strcpy(buffy, message); |
| 1093 angel = g_strdup(who); | 1173 angel = g_strdup(who); |
| 1094 plugin_return = plugin_event(event_chat_recv, g, b->id, &angel, &buffy); | 1174 plugin_return = plugin_event(event_chat_recv, g, gaim_chat_get_id(chat), |
| 1175 &angel, &buffy); | |
| 1095 | 1176 |
| 1096 if (!buffy || !angel || plugin_return) { | 1177 if (!buffy || !angel || plugin_return) { |
| 1097 if (buffy) | 1178 if (buffy) |
| 1098 g_free(buffy); | 1179 g_free(buffy); |
| 1099 if (angel) | 1180 if (angel) |
| 1112 if (whisper) | 1193 if (whisper) |
| 1113 w = WFLAG_WHISPER; | 1194 w = WFLAG_WHISPER; |
| 1114 else | 1195 else |
| 1115 w = 0; | 1196 w = 0; |
| 1116 | 1197 |
| 1117 chat_write(b, who, w, buf, mtime); | 1198 gaim_chat_write(chat, who, buf, w, mtime); |
| 1199 | |
| 1118 g_free(who); | 1200 g_free(who); |
| 1119 g_free(message); | 1201 g_free(message); |
| 1120 g_free(buf); | 1202 g_free(buf); |
| 1121 } | 1203 } |
| 1122 | 1204 |
