comparison src/protocols/zephyr/zephyr.c @ 9478:0efa260e384f

[gaim-migrate @ 10303] " This patch adds the following features for zephyr, in order of usefulness :-) Protocol action (Retrieve subscriptions from server) to list user's subscriptions (chats) in a popup window. Typing notification - (both sending and receiving -- using zephyrs with opcode ping). Correct interpretation of %host% and %canon% entries in .zephyr.subs . These are often used to subscribe to system messages concerning a specific machine (by hostname and canonical hostname, respectively). An updated .todo list." --Arun A Tharuvai committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Wed, 07 Jul 2004 21:56:57 +0000
parents 7a65fdba750f
children 8b2451878e26
comparison
equal deleted inserted replaced
9477:2c7dcb5851f4 9478:0efa260e384f
33 #include "server.h" 33 #include "server.h"
34 #include "util.h" 34 #include "util.h"
35 #include "cmds.h" 35 #include "cmds.h"
36 36
37 #include "zephyr/zephyr.h" 37 #include "zephyr/zephyr.h"
38 #include "internal.h"
38 39
39 #include <strings.h> 40 #include <strings.h>
40 41
41 #define ZEPHYR_FALLBACK_CHARSET "ISO-8859-1" 42 #define ZEPHYR_FALLBACK_CHARSET "ISO-8859-1"
43
44 /* these are deliberately high, since most people don't send multiple "PING"s */
45 #define ZEPHYR_TYPING_SEND_TIMEOUT 15
46 #define ZEPHYR_TYPING_RECV_TIMEOUT 10
42 47
43 extern Code_t ZGetLocations(ZLocations_t *, int *); 48 extern Code_t ZGetLocations(ZLocations_t *, int *);
44 extern Code_t ZSetLocation(char *); 49 extern Code_t ZSetLocation(char *);
45 extern Code_t ZUnsetLocation(); 50 extern Code_t ZUnsetLocation();
51 extern Code_t ZGetSubscriptions(ZSubscription_t *, int*);
46 52
47 typedef struct _zframe zframe; 53 typedef struct _zframe zframe;
48 typedef struct _zephyr_triple zephyr_triple; 54 typedef struct _zephyr_triple zephyr_triple;
55
56 char ourhost[MAXHOSTNAMELEN];
57 char ourhostcanon[MAXHOSTNAMELEN];
49 58
50 /* struct I need for zephyr_to_html */ 59 /* struct I need for zephyr_to_html */
51 struct _zframe { 60 struct _zframe {
52 /* true for everything but @color, since inside the parens of that one is 61 /* true for everything but @color, since inside the parens of that one is
53 * the color. */ 62 * the color. */
112 static guint32 loctimer = 0; 121 static guint32 loctimer = 0;
113 GaimConnection *zgc = NULL; 122 GaimConnection *zgc = NULL;
114 static GList *pending_zloc_names = NULL; 123 static GList *pending_zloc_names = NULL;
115 static GSList *subscrips = NULL; 124 static GSList *subscrips = NULL;
116 static int last_id = 0; 125 static int last_id = 0;
117 126 unsigned short zephyr_port;
118 /* just for debugging */ 127 /* just for debugging */
119 static void handle_unknown(ZNotice_t notice) 128 static void handle_unknown(ZNotice_t notice)
120 { 129 {
121 gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_packet: %s\n", notice.z_packet); 130 gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_packet: %s\n", notice.z_packet);
122 gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_version: %s\n", notice.z_version); 131 gaim_debug(GAIM_DEBUG_MISC, "zephyr","z_version: %s\n", notice.z_version);
152 g_free(zt->recipient); 161 g_free(zt->recipient);
153 g_free(zt->name); 162 g_free(zt->name);
154 g_free(zt); 163 g_free(zt);
155 } 164 }
156 165
157 static const char *gaim_zephyr_get_sender() 166 static gchar *gaim_zephyr_get_sender()
158 { 167 {
159 /* will be useful once this plugin can use a backend other 168 /* will be useful once this plugin can use a backend other
160 than libzephyr */ 169 than libzephyr */
161 return ZGetSender(); 170 /* XXX add zephyr error reporting */
171 gchar *sender;
172 sender = ZGetSender();
173 if (!sender || !g_ascii_strcasecmp(sender,"")) {
174 sender = "";
175 }
176 return sender;
162 } 177 }
163 178
164 static const char *gaim_zephyr_get_realm() 179 static const char *gaim_zephyr_get_realm()
165 { 180 {
166 /* will be useful once this plugin can use a backend other 181 /* will be useful once this plugin can use a backend other
167 than libzephyr */ 182 than libzephyr */
168 return ZGetRealm(); 183 gchar *realm=NULL;
184 /* XXX add zephyr error reporting */
185 realm= ZGetRealm();
186 return realm;
169 } 187 }
170 188
171 /* returns true if zt1 is a subset of zt2. This function is used to 189 /* returns true if zt1 is a subset of zt2. This function is used to
172 determine whether a zephyr sent to zt1 should be placed in the chat 190 determine whether a zephyr sent to zt1 should be placed in the chat
173 with triple zt2 191 with triple zt2
263 { 281 {
264 int len, cnt, retcount; 282 int len, cnt, retcount;
265 char *ret; 283 char *ret;
266 284
267 len = strlen(message); 285 len = strlen(message);
286 if (!len)
287 return g_strdup("");
288
268 ret = g_new0(char, len * 3); 289 ret = g_new0(char, len * 3);
269 290
270 bzero(ret, len * 3); 291 bzero(ret, len * 3);
271 retcount = 0; 292 retcount = 0;
272 cnt = 0; 293 cnt = 0;
581 if (!g_ascii_strcasecmp(notice.z_opcode, LOCATE_LOCATE)) { 602 if (!g_ascii_strcasecmp(notice.z_opcode, LOCATE_LOCATE)) {
582 int nlocs; 603 int nlocs;
583 char *user; 604 char *user;
584 GaimBuddy *b; 605 GaimBuddy *b;
585 606
607 /* XXX add real error reporting */
586 if (ZParseLocations(&notice, NULL, &nlocs, &user) != ZERR_NONE) 608 if (ZParseLocations(&notice, NULL, &nlocs, &user) != ZERR_NONE)
587 return; 609 return;
588 610
589 if ((b = gaim_find_buddy(zgc->account, user)) == NULL) { 611 if ((b = gaim_find_buddy(zgc->account, user)) == NULL) {
590 char *e = strchr(user, '@'); 612 char *e = strchr(user, '@');
604 g_string_append_printf(str, _("<b>Alias:</b> %s<br>"), b->alias); 626 g_string_append_printf(str, _("<b>Alias:</b> %s<br>"), b->alias);
605 if (!nlocs) { 627 if (!nlocs) {
606 g_string_append_printf(str, _("<br>Hidden or not logged-in")); 628 g_string_append_printf(str, _("<br>Hidden or not logged-in"));
607 } 629 }
608 for (; nlocs > 0; nlocs--) { 630 for (; nlocs > 0; nlocs--) {
631 /* XXX add real error reporting */
609 ZGetLocations(&locs, &one); 632 ZGetLocations(&locs, &one);
610 g_string_append_printf(str, _("<br>At %s since %s"), locs.host, locs.time); 633 g_string_append_printf(str, _("<br>At %s since %s"), locs.host, locs.time);
611 } 634 }
612 gaim_notify_formatted(zgc, NULL, _("Buddy Information"), NULL, str->str, NULL, NULL); 635 gaim_notify_formatted(zgc, NULL, _("Buddy Information"), NULL, str->str, NULL, NULL);
613 g_string_free(str, TRUE); 636 g_string_free(str, TRUE);
620 char *buf, *buf2, *buf3; 643 char *buf, *buf2, *buf3;
621 char *send_inst; 644 char *send_inst;
622 GaimConversation *gconv1; 645 GaimConversation *gconv1;
623 GaimConvChat *gcc; 646 GaimConvChat *gcc;
624 char *ptr = notice.z_message + strlen(notice.z_message) + 1; 647 char *ptr = notice.z_message + strlen(notice.z_message) + 1;
625 int len = notice.z_message_len - (strlen(notice.z_message) +1); 648 int len;
626 char *sendertmp = g_strdup_printf("%s", gaim_zephyr_get_sender()); 649 char *sendertmp = g_strdup_printf("%s", gaim_zephyr_get_sender());
650 int signature_length = strlen(notice.z_message);
651 int message_has_no_body = 0;
627 GaimConvImFlags flags = 0; 652 GaimConvImFlags flags = 0;
628
629 if (len > 0) {
630 gchar *tmpescape; 653 gchar *tmpescape;
631 654
655 /* Need to deal with 0 length messages to handle typing notification (OPCODE) ping messages */
656 /* One field zephyrs would have caused gaim to crash */
657 if ( (notice.z_message_len == 0) || (signature_length >= notice.z_message_len - 1)) {
658 message_has_no_body = 1;
659 len = 0;
660 gaim_debug_info("zephyr","message_size %d %d %d\n",len,notice.z_message_len,signature_length);
661 buf3 = g_strdup("");
662
663 } else {
664 len = notice.z_message_len - ( signature_length +1);
665 gaim_debug_info("zephyr","message_size %d %d %d\n",len,notice.z_message_len,signature_length);
632 buf = g_malloc(len + 1); 666 buf = g_malloc(len + 1);
633 g_snprintf(buf, len + 1, "%s", ptr); 667 g_snprintf(buf, len + 1, "%s", ptr);
634 g_strchomp(buf); 668 g_strchomp(buf);
635 tmpescape = gaim_escape_html(buf); 669 tmpescape = gaim_escape_html(buf);
670 g_free(buf);
636 buf2 = zephyr_to_html(tmpescape); 671 buf2 = zephyr_to_html(tmpescape);
637 buf3 = zephyr_recv_convert(buf2, strlen(buf2)); 672 buf3 = zephyr_recv_convert(buf2, strlen(buf2));
638 g_free(buf2); 673 g_free(buf2);
639 g_free(buf);
640 g_free(tmpescape); 674 g_free(tmpescape);
675 }
641 676
642 if (!g_ascii_strcasecmp(notice.z_class, "MESSAGE") && !g_ascii_strcasecmp(notice.z_class_inst, "PERSONAL") 677 if (!g_ascii_strcasecmp(notice.z_class, "MESSAGE") && !g_ascii_strcasecmp(notice.z_class_inst, "PERSONAL")
643 && !g_ascii_strcasecmp(notice.z_recipient,gaim_zephyr_get_sender())) { 678 && !g_ascii_strcasecmp(notice.z_recipient,gaim_zephyr_get_sender())) {
644 gchar* stripped_sender; 679 gchar* stripped_sender;
645 if (!g_ascii_strcasecmp(notice.z_message, "Automated reply:")) 680 if (!g_ascii_strcasecmp(notice.z_message, "Automated reply:"))
646 flags |= GAIM_CONV_IM_AUTO_RESP; 681 flags |= GAIM_CONV_IM_AUTO_RESP;
647 stripped_sender = zephyr_strip_foreign_realm(notice.z_sender); 682 stripped_sender = zephyr_strip_foreign_realm(notice.z_sender);
683
684 if (!g_ascii_strcasecmp(notice.z_opcode,"PING"))
685 serv_got_typing(zgc,stripped_sender,ZEPHYR_TYPING_RECV_TIMEOUT, GAIM_TYPING);
686 else
648 serv_got_im(zgc, stripped_sender, buf3, flags, time(NULL)); 687 serv_got_im(zgc, stripped_sender, buf3, flags, time(NULL));
688
649 g_free(stripped_sender); 689 g_free(stripped_sender);
650 } else { 690 } else {
651 zephyr_triple *zt1, *zt2; 691 zephyr_triple *zt1, *zt2;
652 GList *gltmp; 692 GList *gltmp;
653 int found = 0; 693 int found = 0;
671 Realm from the sender field */ 711 Realm from the sender field */
672 sendertmp = zephyr_strip_foreign_realm(notice.z_sender); 712 sendertmp = zephyr_strip_foreign_realm(notice.z_sender);
673 send_inst = g_strdup_printf("%s %s",sendertmp,notice.z_class_inst); 713 send_inst = g_strdup_printf("%s %s",sendertmp,notice.z_class_inst);
674 send_inst_utf8 = zephyr_recv_convert(send_inst, strlen(send_inst)); 714 send_inst_utf8 = zephyr_recv_convert(send_inst, strlen(send_inst));
675 if (!send_inst_utf8) { 715 if (!send_inst_utf8) {
676 fprintf(stderr, "zephyr: send_inst %s became null\n",send_inst);
677 gaim_debug(GAIM_DEBUG_ERROR, "zephyr","send_inst %s became null\n", send_inst); 716 gaim_debug(GAIM_DEBUG_ERROR, "zephyr","send_inst %s became null\n", send_inst);
678 send_inst_utf8 = "malformed instance"; 717 send_inst_utf8 = "malformed instance";
679 } 718 }
680 719
681 serv_got_chat_in(zgc, zt2->id, send_inst_utf8, FALSE, buf3, time(NULL)); 720 serv_got_chat_in(zgc, zt2->id, send_inst_utf8, FALSE, buf3, time(NULL));
702 g_free(send_inst_utf8); 741 g_free(send_inst_utf8);
703 742
704 free_triple(zt1); 743 free_triple(zt1);
705 } 744 }
706 g_free(buf3); 745 g_free(buf3);
707 } 746
708 } 747 }
709 } 748 }
710 749
711 static gint check_notify(gpointer data) 750 static gint check_notify(gpointer data)
712 { 751 {
752 /* XXX add real error reporting */
753
713 while (ZPending()) { 754 while (ZPending()) {
714 ZNotice_t notice; 755 ZNotice_t notice;
715 struct sockaddr_in from; 756 struct sockaddr_in from;
757 /* XXX add real error reporting */
716 758
717 z_call_r(ZReceiveNotice(&notice, &from)); 759 z_call_r(ZReceiveNotice(&notice, &from));
718 760
719 switch (notice.z_kind) { 761 switch (notice.z_kind) {
720 case UNSAFE: 762 case UNSAFE:
726 if (!(g_ascii_strcasecmp(notice.z_message, ZSRVACK_NOTSENT))) { 768 if (!(g_ascii_strcasecmp(notice.z_message, ZSRVACK_NOTSENT))) {
727 message_failed(notice, from); 769 message_failed(notice, from);
728 } 770 }
729 break; 771 break;
730 case CLIENTACK: 772 case CLIENTACK:
731 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "Client ack received\n"); 773 gaim_debug_error("zephyr", "Client ack received\n");
732 default: 774 default:
733 /* we'll just ignore things for now */ 775 /* we'll just ignore things for now */
734 handle_unknown(notice); 776 handle_unknown(notice);
735 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "Unhandled notice.\n"); 777 gaim_debug_error("zephyr", "Unhandled notice.\n");
736 break; 778 break;
737 } 779 }
738 780 /* XXX add real error reporting */
739 ZFreeNotice(&notice); 781 ZFreeNotice(&notice);
740 } 782 }
741 783
742 return TRUE; 784 return TRUE;
743 } 785 }
764 continue; 806 continue;
765 if (b->account->gc == zgc) { 807 if (b->account->gc == zgc) {
766 const char *chk; 808 const char *chk;
767 809
768 chk = local_zephyr_normalize(b->name); 810 chk = local_zephyr_normalize(b->name);
811 /* XXX add real error reporting */
769 /* doesn't matter if this fails or not; we'll just move on to the next one */ 812 /* doesn't matter if this fails or not; we'll just move on to the next one */
770 ZRequestLocations(chk, &ald, UNACKED, ZAUTH); 813 ZRequestLocations(chk, &ald, UNACKED, ZAUTH);
771 g_free(ald.user); 814 g_free(ald.user);
772 g_free(ald.version); 815 g_free(ald.version);
773 } 816 }
778 return TRUE; 821 return TRUE;
779 } 822 }
780 823
781 static char *get_exposure_level() 824 static char *get_exposure_level()
782 { 825 {
826 /* XXX add real error reporting */
783 char *exposure = ZGetVariable("exposure"); 827 char *exposure = ZGetVariable("exposure");
784 828
785 if (!exposure) 829 if (!exposure)
786 return EXPOSE_REALMVIS; 830 return EXPOSE_REALMVIS;
787 if (!g_ascii_strcasecmp(exposure, EXPOSE_NONE)) 831 if (!g_ascii_strcasecmp(exposure, EXPOSE_NONE))
805 *tmp = '\0'; 849 *tmp = '\0';
806 g_strchug(str); 850 g_strchug(str);
807 g_strchomp(str); 851 g_strchomp(str);
808 } 852 }
809 853
854 static void zephyr_inithosts()
855 {
856 /* XXX This code may not be Win32 clean */
857 struct hostent *hent;
858
859 if (gethostname(ourhost, sizeof(ourhost)-1) == -1) {
860 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "unable to retrieve hostname, %%host%% and %%canon%% will be wrong in subscriptions and have been set to unknown\n");
861 g_stpcpy(ourhost,"unknown");
862 g_stpcpy(ourhostcanon,"unknown");
863 return;
864 }
865
866 if (!(hent = gethostbyname(ourhost))) {
867 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "unable to resolve hostname, %%canon%% will be wrong in subscriptions.and has been set to the value of %%host%%, %s\n",ourhost);
868 g_stpcpy(ourhostcanon,ourhost);
869 return;
870 }
871 g_stpcpy(ourhostcanon,hent->h_name);
872 return;
873 }
874
810 static void process_zsubs() 875 static void process_zsubs()
811 { 876 {
812 /* Loads zephyr chats "(subscriptions) from ~/.zephyr.subs, and 877 /* Loads zephyr chats "(subscriptions) from ~/.zephyr.subs, and
813 registers (subscribes to) them on the server */ 878 registers (subscribes to) them on the server */
814 879
815 /* XXX write subscriptions into the buddy list somehow "a Zephyr Chats group?"*/
816 /* XXX deal with unsubscriptions */ 880 /* XXX deal with unsubscriptions */
817 /* XXX deal with punts */ 881 /* XXX deal with punts */
818 882
819 FILE *f; 883 FILE *f;
820 gchar *fname; 884 gchar *fname;
821 gchar buff[BUFSIZ]; 885 gchar buff[BUFSIZ];
822 886
887 zephyr_inithosts();
823 fname = g_strdup_printf("%s/.zephyr.subs", gaim_home_dir()); 888 fname = g_strdup_printf("%s/.zephyr.subs", gaim_home_dir());
824 f = fopen(fname, "r"); 889 f = fopen(fname, "r");
825 if (f) { 890 if (f) {
826 char **triple; 891 char **triple;
827 ZSubscription_t sub; 892 ZSubscription_t sub;
828 char *recip; 893 char *recip;
894 char *z_class;
895 char *z_instance;
829 896
830 while (fgets(buff, BUFSIZ, f)) { 897 while (fgets(buff, BUFSIZ, f)) {
831 strip_comments(buff); 898 strip_comments(buff);
832 if (buff[0]) { 899 if (buff[0]) {
833 triple = g_strsplit(buff, ",", 3); 900 triple = g_strsplit(buff, ",", 3);
865 } else { 932 } else {
866 recip = g_strdup(triple[2]); 933 recip = g_strdup(triple[2]);
867 } 934 }
868 g_free(tmp); 935 g_free(tmp);
869 sub.zsub_recipient = recip; 936 sub.zsub_recipient = recip;
937
938 if (!g_ascii_strcasecmp(triple[0],"%host%")) {
939 z_class = g_strdup(ourhost);
940 } else if (!g_ascii_strcasecmp(triple[0],"%canon%")) {
941 z_class = g_strdup(ourhostcanon);
942 } else {
943 z_class = g_strdup(triple[0]);
944 }
945 sub.zsub_class = z_class;
946
947 if (!g_ascii_strcasecmp(triple[1],"%host%")) {
948 z_instance = g_strdup(ourhost);
949 } else if (!g_ascii_strcasecmp(triple[1],"%canon%")) {
950 z_instance = g_strdup(ourhostcanon);
951 } else {
952 z_instance = g_strdup(triple[1]);
953 }
954 sub.zsub_classinst = z_instance;
955
956 /* There should be some sort of error report listing classes that couldn't be subbed to.
957 Not important right now though */
958
870 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) { 959 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) {
960
871 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "Couldn't subscribe to %s, %s, %s\n", sub.zsub_class, sub.zsub_classinst, sub.zsub_recipient); 961 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "Couldn't subscribe to %s, %s, %s\n", sub.zsub_class, sub.zsub_classinst, sub.zsub_recipient);
872 } 962 }
873 subscrips = g_slist_append(subscrips, new_triple(triple[0], triple[1], recip)); 963
964 subscrips = g_slist_append(subscrips, new_triple(sub.zsub_class,sub.zsub_classinst,sub.zsub_recipient));
965 /* g_hash_table_destroy(sub_hash_table); */
966 g_free(z_instance);
967 g_free(z_class);
874 g_free(recip); 968 g_free(recip);
875 } 969 }
876 g_strfreev(triple); 970 g_strfreev(triple);
877 } 971 }
878 } 972 }
909 1003
910 static void zephyr_login(GaimAccount * account) 1004 static void zephyr_login(GaimAccount * account)
911 { 1005 {
912 ZSubscription_t sub; 1006 ZSubscription_t sub;
913 1007
1008 /* This needs to fixed to deal with multiple accounts somehow */
914 if (zgc) { 1009 if (zgc) {
915 gaim_notify_error(account->gc, NULL, 1010 gaim_notify_error(account->gc, NULL,
916 _("Already logged in with Zephyr"), _("Because Zephyr uses your system username, you " "are unable to have multiple accounts on it " "when logged in as the same user.")); 1011 _("Already logged in with Zephyr"), _("Because Zephyr uses your system username, you " "are unable to have multiple accounts on it " "when logged in as the same user."));
917 return; 1012 return;
918 } 1013 }
919 1014
920 zgc = gaim_account_get_connection(account); 1015 zgc = gaim_account_get_connection(account);
921 zgc->flags |= GAIM_CONNECTION_HTML; 1016 zgc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_URLDESC;
922 gaim_connection_update_progress(zgc, _("Connecting"), 0, 2); 1017 gaim_connection_update_progress(zgc, _("Connecting"), 0, 8);
1018
1019 /* XXX z_call_s should actually try to report the com_err determined error */
923 1020
924 z_call_s(ZInitialize(), "Couldn't initialize zephyr"); 1021 z_call_s(ZInitialize(), "Couldn't initialize zephyr");
925 z_call_s(ZOpenPort(NULL), "Couldn't open port"); 1022 z_call_s(ZOpenPort(&zephyr_port), "Couldn't open port");
926 z_call_s(ZSetLocation((char *) 1023 z_call_s(ZSetLocation((char *)
927 gaim_account_get_string(zgc->account, "exposure_level", EXPOSE_REALMVIS)), "Couldn't set location"); 1024 gaim_account_get_string(zgc->account, "exposure_level", EXPOSE_REALMVIS)), "Couldn't set location");
928 1025
929 sub.zsub_class = "MESSAGE"; 1026 sub.zsub_class = "MESSAGE";
930 sub.zsub_classinst = "PERSONAL"; 1027 sub.zsub_classinst = "PERSONAL";
931 sub.zsub_recipient = (char *)gaim_zephyr_get_sender(); 1028 sub.zsub_recipient = (char *)gaim_zephyr_get_sender();
932 1029
933 /* we don't care if this fails. i'm lying right now. */
934 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) { 1030 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) {
935 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "Couldn't subscribe to messages!\n"); 1031 /* XXX don't translate this yet. It could be written better */
1032 /* XXX error messages could be handled with more detail */
1033 gaim_notify_error(account->gc, NULL,
1034 "Unable to subscribe to messages", "Unable to subscribe to initial messages");
1035 return;
936 } 1036 }
937 1037
938 gaim_connection_set_state(zgc, GAIM_CONNECTED); 1038 gaim_connection_set_state(zgc, GAIM_CONNECTED);
939 serv_finish_login(zgc); 1039 serv_finish_login(zgc);
940 1040
966 g_free(fname); 1066 g_free(fname);
967 return; 1067 return;
968 } 1068 }
969 1069
970 while (s) { 1070 while (s) {
1071 char *zclass, *zinst, *zrecip;
971 zt = s->data; 1072 zt = s->data;
972 triple = g_strsplit(zt->name, ",", 3); 1073 triple = g_strsplit(zt->name, ",", 3);
973 if (triple[2] != NULL) { 1074
974 if (!g_ascii_strcasecmp(triple[2], "")) { 1075 /* deal with classes */
975 fprintf(fd, "%s,%s,*\n", triple[0], triple[1]); 1076 if (!g_ascii_strcasecmp(triple[0],ourhost)) {
976 } else if (!g_ascii_strcasecmp(triple[2], gaim_zephyr_get_sender())) { 1077 zclass = g_strdup("%host%");;
977 fprintf(fd, "%s,%s,%%me%%\n", triple[0], triple[1]); 1078 } else if (!g_ascii_strcasecmp(triple[0],ourhostcanon)) {
1079 zclass = g_strdup("%canon%");;
1080 } else {
1081 zclass = g_strdup(triple[0]);
1082 }
1083
1084 /* deal with instances */
1085
1086 if (!g_ascii_strcasecmp(triple[1],ourhost)) {
1087 zinst = g_strdup("%host%");;
1088 } else if (!g_ascii_strcasecmp(triple[1],ourhostcanon)) {
1089 zinst = g_strdup("%canon%");;
978 } else { 1090 } else {
979 fprintf(fd, "%s\n", zt->name); 1091 zinst = g_strdup(triple[1]);
980 } 1092 }
1093
1094 /* deal with recipients */
1095 if (triple[2] == NULL) {
1096 zrecip = g_strdup("*");
1097 } else if (!g_ascii_strcasecmp(triple[2],"")){
1098 zrecip = g_strdup("*");
1099 } else if (!g_ascii_strcasecmp(triple[2], gaim_zephyr_get_sender())) {
1100 zrecip = g_strdup("%me%");
981 } else { 1101 } else {
982 fprintf(fd, "%s,%s,*\n", triple[0], triple[1]); 1102 zrecip = g_strdup(triple[2]);
983 } 1103 }
1104
1105 fprintf(fd, "%s,%s,%s\n",zclass,zinst,zrecip);
1106
1107 g_free(zclass);
1108 g_free(zinst);
1109 g_free(zrecip);
984 g_free(triple); 1110 g_free(triple);
985 s = s->next; 1111 s = s->next;
986 } 1112 }
987 g_free(fname); 1113 g_free(fname);
988 fclose(fd); 1114 fclose(fd);
1070 z_call(ZUnsetLocation()); 1196 z_call(ZUnsetLocation());
1071 z_call(ZClosePort()); 1197 z_call(ZClosePort());
1072 } 1198 }
1073 1199
1074 static int zephyr_send_message(char* zclass, char* instance, char* recipient, const char *im, 1200 static int zephyr_send_message(char* zclass, char* instance, char* recipient, const char *im,
1075 const char *sig) ; 1201 const char *sig, char *opcode) ;
1076 1202
1077 const char * zephyr_get_signature() 1203 const char * zephyr_get_signature()
1078 { 1204 {
1079 const char * sig; 1205 /* XXX add zephyr error reporting */
1080 sig = ZGetVariable("zwrite-signature"); 1206 const char * sig =ZGetVariable("zwrite-signature");
1081 if (!sig) { 1207 if (!sig) {
1082 sig = g_get_real_name(); 1208 sig = g_get_real_name();
1083 } 1209 }
1084 return sig; 1210 return sig;
1085 } 1211 }
1109 if (!g_ascii_strcasecmp(zt->recipient, "*")) 1235 if (!g_ascii_strcasecmp(zt->recipient, "*"))
1110 recipient = local_zephyr_normalize(""); 1236 recipient = local_zephyr_normalize("");
1111 else 1237 else
1112 recipient = local_zephyr_normalize(zt->recipient); 1238 recipient = local_zephyr_normalize(zt->recipient);
1113 1239
1114 zephyr_send_message(zt->class,inst,recipient,im,sig); 1240 zephyr_send_message(zt->class,inst,recipient,im,sig,"");
1115 /* g_free(inst); */ 1241 /* g_free(inst); */
1116 /* g_free(recipient); */ 1242 /* g_free(recipient); */
1117 return 0; 1243 return 0;
1118 } 1244 }
1119 1245
1125 if (flags & GAIM_CONV_IM_AUTO_RESP) 1251 if (flags & GAIM_CONV_IM_AUTO_RESP)
1126 sig = "Automated reply:"; 1252 sig = "Automated reply:";
1127 else { 1253 else {
1128 sig = zephyr_get_signature(); 1254 sig = zephyr_get_signature();
1129 } 1255 }
1130 zephyr_send_message("MESSAGE","PERSONAL",local_zephyr_normalize(who),im,sig); 1256 zephyr_send_message("MESSAGE","PERSONAL",local_zephyr_normalize(who),im,sig,"");
1131 1257
1132 return 1; 1258 return 1;
1133 } 1259 }
1134 1260
1135 static int zephyr_send_message(char* zclass, char* instance, char* recipient, const char *im, 1261 static int zephyr_send_message(char* zclass, char* instance, char* recipient, const char *im,
1136 const char *sig) 1262 const char *sig, char *opcode)
1137 { 1263 {
1138 char *html_buf; 1264 char *html_buf;
1139 char *html_buf2; 1265 char *html_buf2;
1140 char *buf; 1266 char *buf;
1141 ZNotice_t notice; 1267 ZNotice_t notice;
1154 notice.z_recipient = recipient; 1280 notice.z_recipient = recipient;
1155 notice.z_sender = 0; 1281 notice.z_sender = 0;
1156 notice.z_default_format = "Class $class, Instance $instance:\n" "To: @bold($recipient) at $time $date\n" "From: @bold($1) <$sender>\n\n$2"; 1282 notice.z_default_format = "Class $class, Instance $instance:\n" "To: @bold($recipient) at $time $date\n" "From: @bold($1) <$sender>\n\n$2";
1157 notice.z_message_len = strlen(html_buf2) + strlen(sig) + 2; 1283 notice.z_message_len = strlen(html_buf2) + strlen(sig) + 2;
1158 notice.z_message = buf; 1284 notice.z_message = buf;
1285 notice.z_opcode = g_strdup(opcode);
1286 gaim_debug_info("zephyr","About to send notice");
1287 if (! ZSendNotice(&notice, ZAUTH) == ZERR_NONE) {
1288 /* XXX handle errors here */
1289 return 0;
1290 }
1291 gaim_debug_info("zephyr","notice sent");
1292 g_free(buf);
1293
1159 g_free(html_buf2); 1294 g_free(html_buf2);
1160 g_free(html_buf); 1295 g_free(html_buf);
1161 1296
1162 ZSendNotice(&notice, ZAUTH);
1163 g_free(buf);
1164 return 1; 1297 return 1;
1165 } 1298 }
1166 1299
1167 static const char *zephyr_normalize(const GaimAccount * account, const char *orig) 1300 static const char *zephyr_normalize(const GaimAccount * account, const char *orig)
1168 { 1301 {
1205 gchar* normalized_who = local_zephyr_normalize(who); 1338 gchar* normalized_who = local_zephyr_normalize(who);
1206 1339
1207 if (ZRequestLocations(normalized_who, &ald, UNACKED, ZAUTH) == ZERR_NONE) { 1340 if (ZRequestLocations(normalized_who, &ald, UNACKED, ZAUTH) == ZERR_NONE) {
1208 pending_zloc_names = g_list_append(pending_zloc_names, 1341 pending_zloc_names = g_list_append(pending_zloc_names,
1209 g_strdup(normalized_who)); 1342 g_strdup(normalized_who));
1343 } else {
1344 /* XXX deal with errors somehow */
1210 } 1345 }
1211 } 1346 }
1212 1347
1213 static void zephyr_set_away(GaimConnection * gc, const char *state, const char *msg) 1348 static void zephyr_set_away(GaimConnection * gc, const char *state, const char *msg)
1214 { 1349 {
1216 g_free(gc->away); 1351 g_free(gc->away);
1217 gc->away = NULL; 1352 gc->away = NULL;
1218 } 1353 }
1219 1354
1220 if (!g_ascii_strcasecmp(state, _("Hidden"))) { 1355 if (!g_ascii_strcasecmp(state, _("Hidden"))) {
1356 /* XXX handle errors */
1221 ZSetLocation(EXPOSE_OPSTAFF); 1357 ZSetLocation(EXPOSE_OPSTAFF);
1222 gc->away = g_strdup(""); 1358 gc->away = g_strdup("");
1223 } else if (!g_ascii_strcasecmp(state, _("Online"))) 1359 }
1360 else if (!g_ascii_strcasecmp(state, _("Online"))) {
1361 /* XXX handle errors */
1224 ZSetLocation(get_exposure_level()); 1362 ZSetLocation(get_exposure_level());
1363 }
1225 else /* state is GAIM_AWAY_CUSTOM */ if (msg) 1364 else /* state is GAIM_AWAY_CUSTOM */ if (msg)
1226 gc->away = g_strdup(msg); 1365 gc->away = g_strdup(msg);
1227 } 1366 }
1228 1367
1229 static GList *zephyr_away_states(GaimConnection * gc) 1368 static GList *zephyr_away_states(GaimConnection * gc)
1259 pce->label = _("_Recipient:"); 1398 pce->label = _("_Recipient:");
1260 pce->identifier = "recipient"; 1399 pce->identifier = "recipient";
1261 m = g_list_append(m, pce); 1400 m = g_list_append(m, pce);
1262 1401
1263 return m; 1402 return m;
1403 }
1404
1405 /* Called when the server notifies us a message couldn't get sent */
1406
1407 static void zephyr_subscribe_failed(ZSubscription_t *sub)
1408 {
1409 gchar* subscribe_failed = g_strdup_printf(_("Attempt to subscribe to %s,%s,%s failed"), sub->zsub_class, sub->zsub_classinst,sub->zsub_recipient);
1410 gaim_notify_error(zgc,"", subscribe_failed, NULL);
1411 g_free(subscribe_failed);
1264 } 1412 }
1265 1413
1266 static void zephyr_join_chat(GaimConnection * gc, GHashTable * data) 1414 static void zephyr_join_chat(GaimConnection * gc, GHashTable * data)
1267 { 1415 {
1268 ZSubscription_t sub; 1416 ZSubscription_t sub;
1273 1421
1274 classname = g_hash_table_lookup(data, "class"); 1422 classname = g_hash_table_lookup(data, "class");
1275 instname = g_hash_table_lookup(data, "instance"); 1423 instname = g_hash_table_lookup(data, "instance");
1276 recip = g_hash_table_lookup(data, "recipient"); 1424 recip = g_hash_table_lookup(data, "recipient");
1277 1425
1426
1278 if (!classname) 1427 if (!classname)
1279 return; 1428 return;
1429
1430 if (!g_ascii_strcasecmp(classname,"%host%"))
1431 classname = g_strdup(ourhost);
1432 if (!g_ascii_strcasecmp(classname,"%canon%"))
1433 classname = g_strdup(ourhostcanon);
1434
1280 if (!instname || !strlen(instname)) 1435 if (!instname || !strlen(instname))
1281 instname = "*"; 1436 instname = "*";
1437
1438 if (!g_ascii_strcasecmp(instname,"%host%"))
1439 instname = g_strdup(ourhost);
1440 if (!g_ascii_strcasecmp(instname,"%canon%"))
1441 instname = g_strdup(ourhostcanon);
1442
1282 if (!recip || (*recip == '*')) 1443 if (!recip || (*recip == '*'))
1283 recip = ""; 1444 recip = "";
1284 if (!g_ascii_strcasecmp(recip, "%me%")) 1445 if (!g_ascii_strcasecmp(recip, "%me%"))
1285 recip = gaim_zephyr_get_sender(); 1446 recip = gaim_zephyr_get_sender();
1286 1447
1301 sub.zsub_class = zt1->class; 1462 sub.zsub_class = zt1->class;
1302 sub.zsub_classinst = zt1->instance; 1463 sub.zsub_classinst = zt1->instance;
1303 sub.zsub_recipient = zt1->recipient; 1464 sub.zsub_recipient = zt1->recipient;
1304 1465
1305 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) { 1466 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) {
1467 /* XXX output better subscription information */
1468 zephyr_subscribe_failed(&sub);
1306 free_triple(zt1); 1469 free_triple(zt1);
1307 return; 1470 return;
1308 } 1471 }
1309 1472
1310 subscrips = g_slist_append(subscrips, zt1); 1473 subscrips = g_slist_append(subscrips, zt1);
1324 zt->open = FALSE; 1487 zt->open = FALSE;
1325 zt->id = ++last_id; 1488 zt->id = ++last_id;
1326 } 1489 }
1327 } 1490 }
1328 1491
1492 static GaimChat *zephyr_find_blist_chat(GaimAccount *account, const char *name)
1493 {
1494 GaimBlistNode *gnode, *cnode;
1495
1496 /* XXX needs to be %host%,%canon%, and %me% clean */
1497 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) {
1498 for(cnode = gnode->child; cnode; cnode = cnode->next) {
1499 GaimChat *chat = (GaimChat*)cnode;
1500 char *zclass, *inst, *recip;
1501 char** triple;
1502 if(!GAIM_BLIST_NODE_IS_CHAT(cnode))
1503 continue;
1504 if(chat->account !=account)
1505 continue;
1506 if(!(zclass = g_hash_table_lookup(chat->components, "class")))
1507 continue;
1508 if(!(inst = g_hash_table_lookup(chat->components, "instance")))
1509 inst = g_strdup("");
1510 if(!(recip = g_hash_table_lookup(chat->components, "recipient")))
1511 recip = g_strdup("");
1512 triple = g_strsplit(name,",",3);
1513 if (!g_ascii_strcasecmp(triple[0],zclass) && !g_ascii_strcasecmp(triple[1],inst) && !g_ascii_strcasecmp(triple[2],recip))
1514 return chat;
1515
1516 }
1517 }
1518 return NULL;
1519 }
1329 static const char *zephyr_list_icon(GaimAccount * a, GaimBuddy * b) 1520 static const char *zephyr_list_icon(GaimAccount * a, GaimBuddy * b)
1330 { 1521 {
1331 return "zephyr"; 1522 return "zephyr";
1332 } 1523 }
1333 1524
1525 static int zephyr_send_typing(GaimConnection *gc, const char *who, int typing) {
1526 gchar *recipient;
1527 if (!typing)
1528 return 0;
1529 /* XXX We probably should care if this fails. Or maybe we don't want to */
1530 if (!who) {
1531 gaim_debug_info("zephyr", "who is null\n");
1532 recipient = local_zephyr_normalize("");
1533 } else {
1534 recipient = local_zephyr_normalize(who);
1535 }
1536
1537 gaim_debug_info("zephyr","about to send typing notification to %s",recipient);
1538 zephyr_send_message("MESSAGE","PERSONAL",recipient,"","","PING");
1539 gaim_debug_info("zephyr","sent typing notification");
1540 return ZEPHYR_TYPING_SEND_TIMEOUT;
1541 }
1334 1542
1335 1543
1336 1544
1337 static void zephyr_chat_set_topic(GaimConnection * gc, int id, const char *topic) 1545 static void zephyr_chat_set_topic(GaimConnection * gc, int id, const char *topic)
1338 { 1546 {
1356 1564
1357 static GaimCmdRet zephyr_gaim_cmd_msg(GaimConversation *conv, 1565 static GaimCmdRet zephyr_gaim_cmd_msg(GaimConversation *conv,
1358 const char *cmd, char **args, char **error) 1566 const char *cmd, char **args, char **error)
1359 { 1567 {
1360 char *recipient; 1568 char *recipient;
1569
1361 if (!g_ascii_strcasecmp(args[0],"*")) 1570 if (!g_ascii_strcasecmp(args[0],"*"))
1362 recipient = local_zephyr_normalize(""); 1571 return GAIM_CMD_RET_FAILED; /* "*" is not a valid argument */
1363 else 1572 else
1364 recipient = local_zephyr_normalize(args[0]); 1573 recipient = local_zephyr_normalize(args[0]);
1365 1574
1366 if (zephyr_send_message("MESSAGE","PERSONAL",recipient,args[1],zephyr_get_signature())) 1575 if (strlen(recipient) < 1)
1576 return GAIM_CMD_RET_FAILED; /* a null recipient is a chat message, not an IM */
1577
1578 if (zephyr_send_message("MESSAGE","PERSONAL",recipient,args[1],zephyr_get_signature(),""))
1367 return GAIM_CMD_RET_OK; 1579 return GAIM_CMD_RET_OK;
1368 else 1580 else
1369 return GAIM_CMD_RET_FAILED; 1581 return GAIM_CMD_RET_FAILED;
1370 } 1582 }
1371 1583
1404 1616
1405 static GaimCmdRet zephyr_gaim_cmd_zi(GaimConversation *conv, 1617 static GaimCmdRet zephyr_gaim_cmd_zi(GaimConversation *conv,
1406 const char *cmd, char **args, char **error) 1618 const char *cmd, char **args, char **error)
1407 { 1619 {
1408 /* args = instance, message */ 1620 /* args = instance, message */
1409 if (zephyr_send_message("message",args[0],"",args[1],zephyr_get_signature())) 1621 if ( zephyr_send_message("message",args[0],"",args[1],zephyr_get_signature(),""))
1410 return GAIM_CMD_RET_OK; 1622 return GAIM_CMD_RET_OK;
1411 else 1623 else
1412 return GAIM_CMD_RET_FAILED; 1624 return GAIM_CMD_RET_FAILED;
1413 } 1625 }
1414 1626
1415 static GaimCmdRet zephyr_gaim_cmd_zci(GaimConversation *conv, 1627 static GaimCmdRet zephyr_gaim_cmd_zci(GaimConversation *conv,
1416 const char *cmd, char **args, char **error) 1628 const char *cmd, char **args, char **error)
1417 { 1629 {
1418 /* args = class, instance, message */ 1630 /* args = class, instance, message */
1419 if ( zephyr_send_message(args[0],args[1],"",args[2],zephyr_get_signature())) 1631 if ( zephyr_send_message(args[0],args[1],"",args[2],zephyr_get_signature(),""))
1420 return GAIM_CMD_RET_OK; 1632 return GAIM_CMD_RET_OK;
1421 else 1633 else
1422 return GAIM_CMD_RET_FAILED; 1634 return GAIM_CMD_RET_FAILED;
1423 } 1635 }
1424 1636
1425 static GaimCmdRet zephyr_gaim_cmd_zcir(GaimConversation *conv, 1637 static GaimCmdRet zephyr_gaim_cmd_zcir(GaimConversation *conv,
1426 const char *cmd, char **args, char **error) 1638 const char *cmd, char **args, char **error)
1427 { 1639 {
1428 /* args = class, instance, recipient, message */ 1640 /* args = class, instance, recipient, message */
1429 if ( zephyr_send_message(args[0],args[1],args[2],args[3],zephyr_get_signature())) 1641 if ( zephyr_send_message(args[0],args[1],args[2],args[3],zephyr_get_signature(),""))
1430 return GAIM_CMD_RET_OK; 1642 return GAIM_CMD_RET_OK;
1431 else 1643 else
1432 return GAIM_CMD_RET_FAILED; 1644 return GAIM_CMD_RET_FAILED;
1433 } 1645 }
1434 1646
1435 static GaimCmdRet zephyr_gaim_cmd_zir(GaimConversation *conv, 1647 static GaimCmdRet zephyr_gaim_cmd_zir(GaimConversation *conv,
1436 const char *cmd, char **args, char **error) 1648 const char *cmd, char **args, char **error)
1437 { 1649 {
1438 /* args = instance, recipient, message */ 1650 /* args = instance, recipient, message */
1439 if ( zephyr_send_message("message",args[0],args[1],args[2],zephyr_get_signature())) 1651 if ( zephyr_send_message("message",args[0],args[1],args[2],zephyr_get_signature(),""))
1440 return GAIM_CMD_RET_OK; 1652 return GAIM_CMD_RET_OK;
1441 else 1653 else
1442 return GAIM_CMD_RET_FAILED; 1654 return GAIM_CMD_RET_FAILED;
1443 } 1655 }
1444 1656
1445 static GaimCmdRet zephyr_gaim_cmd_zc(GaimConversation *conv, 1657 static GaimCmdRet zephyr_gaim_cmd_zc(GaimConversation *conv,
1446 const char *cmd, char **args, char **error) 1658 const char *cmd, char **args, char **error)
1447 { 1659 {
1448 /* args = class, message */ 1660 /* args = class, message */
1449 if ( zephyr_send_message(args[0],"PERSONAL","",args[1],zephyr_get_signature())) 1661 if ( zephyr_send_message(args[0],"PERSONAL","",args[1],zephyr_get_signature(),""))
1450 return GAIM_CMD_RET_OK; 1662 return GAIM_CMD_RET_OK;
1451 else 1663 else
1452 return GAIM_CMD_RET_FAILED; 1664 return GAIM_CMD_RET_FAILED;
1453 } 1665 }
1454 1666
1528 while (s) { 1740 while (s) {
1529 zt = s->data; 1741 zt = s->data;
1530 zst.zsub_class = zt->class; 1742 zst.zsub_class = zt->class;
1531 zst.zsub_classinst = zt->instance; 1743 zst.zsub_classinst = zt->instance;
1532 zst.zsub_recipient = zt->recipient; 1744 zst.zsub_recipient = zt->recipient;
1533 ZSubscribeTo(&zst, 1, 0);
1534 /* XXX We really should care if this fails */ 1745 /* XXX We really should care if this fails */
1746 ZSubscribeTo(&zst, 1, 0);
1535 s = s->next; 1747 s = s->next;
1536 } 1748 }
1537 /* XXX handle unsubscriptions */ 1749 /* XXX handle unsubscriptions */
1538 return 1; 1750 return 1;
1539 } 1751 }
1545 GaimConnection *gc = (GaimConnection *) action->context; 1757 GaimConnection *gc = (GaimConnection *) action->context;
1546 zephyr_resubscribe(gc); 1758 zephyr_resubscribe(gc);
1547 } 1759 }
1548 1760
1549 1761
1762 static void zephyr_action_get_subs_from_server(GaimPluginAction *action)
1763 {
1764 GaimConnection *gc = (GaimConnection *) action->context;
1765 gchar *title;
1766 int retval, nsubs, one,i;
1767 ZSubscription_t subs;
1768 GString* subout = g_string_new("Subscription list<br>");
1769
1770 title = g_strdup_printf("Server subscriptions for %s", gaim_zephyr_get_sender());
1771
1772 if (zephyr_port == 0) {
1773 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving port");
1774 return;
1775 }
1776 if ((retval = ZRetrieveSubscriptions(zephyr_port,&nsubs)) != ZERR_NONE) {
1777 /* XXX better error handling */
1778 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving subscriptions from server");
1779 return;
1780 }
1781 g_string_append_printf(subout,"Subscription list <br>");
1782 for(i=0;i<nsubs;i++) {
1783 one = 1;
1784 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
1785 /* XXX better error handling */
1786 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving individual subscription");
1787 return;
1788 }
1789 g_string_append_printf(subout, "Class %s Instance %s Recipient %s<br>",
1790 subs.zsub_class, subs.zsub_classinst,
1791 subs.zsub_recipient);
1792 }
1793 gaim_notify_formatted(gc, title, title, NULL, subout->str, NULL, NULL);
1794 }
1795
1796
1550 static GList *zephyr_actions(GaimPlugin *plugin, gpointer context) 1797 static GList *zephyr_actions(GaimPlugin *plugin, gpointer context)
1551 { 1798 {
1552 GList *list = NULL; 1799 GList *list = NULL;
1553 GaimPluginAction *act = NULL; 1800 GaimPluginAction *act = NULL;
1554 1801
1555 act = gaim_plugin_action_new(_("Resubscribe"), zephyr_action_resubscribe); 1802 act = gaim_plugin_action_new(_("Resubscribe"), zephyr_action_resubscribe);
1556 list = g_list_append(list, act); 1803 list = g_list_append(list, act);
1804
1805 act = gaim_plugin_action_new(_("Retrieve subscriptions from server"), zephyr_action_get_subs_from_server);
1806 list = g_list_append(list,act);
1557 1807
1558 return list; 1808 return list;
1559 } 1809 }
1560 1810
1561 static GaimPlugin *my_protocol = NULL; 1811 static GaimPlugin *my_protocol = NULL;
1562 1812
1563 static GaimPluginProtocolInfo prpl_info = { 1813 static GaimPluginProtocolInfo prpl_info = {
1564 GAIM_PRPL_API_VERSION, 1814 GAIM_PRPL_API_VERSION,
1565 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_NO_PASSWORD, 1815 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_NO_PASSWORD,
1566 NULL, /* user_splits */ 1816 NULL, /* ??? user_splits */
1567 NULL, /* protocol_options */ 1817 NULL, /* ??? protocol_options */
1568 NO_BUDDY_ICONS, /* icon_spec */ 1818 NO_BUDDY_ICONS,
1569 zephyr_list_icon, /* list_icon */ 1819 zephyr_list_icon,
1570 NULL, /* list_emblems */ 1820 NULL, /* ??? list_emblems */
1571 NULL, /* status_text */ 1821 NULL, /* ??? status_text */
1572 NULL, /* tooltip_text */ 1822 NULL, /* ??? tooltip_text */
1573 zephyr_away_states, /* away_states */ 1823 zephyr_away_states, /* away_states */
1574 NULL, /* blist_node_menu */ 1824 NULL, /* ??? blist_node_menu - probably all useful actions are already handled*/
1575 zephyr_chat_info, /* chat_info */ 1825 zephyr_chat_info, /* chat_info */
1576 zephyr_login, /* login */ 1826 zephyr_login, /* login */
1577 zephyr_close, /* close */ 1827 zephyr_close, /* close */
1578 zephyr_send_im, /* send_im */ 1828 zephyr_send_im, /* send_im */
1579 NULL, /* set_info */ 1829 NULL, /* XXX set info (Location?) */
1580 NULL, /* send_typing */ 1830 zephyr_send_typing, /* send_typing */
1581 zephyr_zloc, /* get_info */ 1831 zephyr_zloc, /* get_info */
1582 zephyr_set_away, /* set_away */ 1832 zephyr_set_away, /* XXX set_away need to fix */
1583 NULL, /* set_idle */ 1833 NULL, /* ??? set idle */
1584 NULL, /* change_passwd */ 1834 NULL, /* change password */
1585 NULL, /* add_buddy */ 1835 NULL, /* add_buddy */
1586 NULL, /* add_buddies */ 1836 NULL, /* add_buddies */
1587 NULL, /* remove_buddy */ 1837 NULL, /* remove_buddy */
1588 NULL, /* remove_buddies */ 1838 NULL, /* remove_buddies */
1589 NULL, /* add_permit */ 1839 NULL, /* add_permit -- not useful, since anyone can zephyr you by default*/
1590 NULL, /* add_deny */ 1840 NULL, /* XXX add deny -- maybe put an auto "I'm ignoring your zephyrs*/
1591 NULL, /* rem_permit */ 1841 NULL, /* remove_permit -- not useful, see add permit */
1592 NULL, /* rem_deny */ 1842 NULL, /* XXX remove deny -- remove above deny, */
1593 NULL, /* set_permit_deny */ 1843 NULL, /* ??? set permit deny */
1594 NULL, /* warn */ 1844 NULL, /* --- warn */
1595 zephyr_join_chat, /* join_chat */ 1845 zephyr_join_chat, /* join_chat */
1596 NULL, /* reject_chat */ 1846 NULL, /* reject_chat */
1597 NULL, /* chat_invite */ 1847 NULL, /* chat_invite */
1598 zephyr_chat_leave, /* chat_leave */ 1848 zephyr_chat_leave, /* chat_leave */
1599 NULL, /* chat_whisper */ 1849 NULL, /* chat_whisper */
1600 zephyr_chat_send, /* chat_send */ 1850 zephyr_chat_send, /* chat_send */
1601 NULL, /* keepalive */ 1851 NULL, /* keepalive */
1602 NULL, /* register_user */ 1852 NULL, /* register_user */
1603 NULL, /* get_cb_info */ 1853 NULL, /* XXX get_cb_info get chat buddy info */
1604 NULL, /* get_cb_away */ 1854 NULL, /* get_cb_away */
1605 NULL, /* alias_buddy */ 1855 NULL, /* alias_buddy */
1606 NULL, /* group_buddy */ 1856 NULL, /* group_buddy */
1607 NULL, /* rename_group */ 1857 NULL, /* rename_group */
1608 NULL, /* buddy_free */ 1858 NULL, /* ??? buddy_free */
1609 NULL, /* convo_closed */ 1859 NULL, /* convo_closed */
1610 zephyr_normalize, /* normalize */ 1860 zephyr_normalize, /* normalize */
1611 NULL, /* set_buddy_icon */ 1861 NULL, /* XXX set_buddy_icon */
1612 NULL, /* remove_group */ 1862 NULL, /* remove_group */
1613 NULL, /* get_cb_real_name */ 1863 NULL, /* XXX get_cb_real_name */
1614 zephyr_chat_set_topic, /* set_chat_topic */ 1864 zephyr_chat_set_topic, /* set_chat_topic */
1615 NULL, /* find_blist_chat */ 1865 zephyr_find_blist_chat, /* find_blist_chat */
1616 NULL, /* roomlist_get_list */ 1866 NULL, /* roomlist_get_list */
1617 NULL, /* roomlist_cancel */ 1867 NULL, /* roomlist_cancel */
1618 NULL, /* roomlist_expand_category */ 1868 NULL, /* roomlist_expand_category */
1619 NULL, /* can_receive_file */ 1869 NULL, /* can_receive_file */
1620 NULL /* send_file */ 1870 NULL /* send_file */
1621 }; 1871 };
1622 1872
1623 static GaimPluginInfo info = { 1873 static GaimPluginInfo info = {