Mercurial > pidgin.yaz
comparison libpurple/protocols/simple/simple.c @ 21149:b2d9f859663e
Patch from Will Hawkins to make the SIMPLE prpl more standards compliant by keeping all subscribe/notify messaging within a dialog. This didn't apply cleanly, so I had to manually apply it - hopefully I didn't break anything during the process. Fixes #3778.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Tue, 06 Nov 2007 02:52:41 +0000 |
parents | 3cc856ca2338 |
children | 38cc722159ff |
comparison
equal
deleted
inserted
replaced
21148:3635ddf4170f | 21149:b2d9f859663e |
---|---|
688 | 688 |
689 g_free(buf); | 689 g_free(buf); |
690 } | 690 } |
691 | 691 |
692 static char *get_contact(struct simple_account_data *sip) { | 692 static char *get_contact(struct simple_account_data *sip) { |
693 return g_strdup_printf("<sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"", sip->username, purple_network_get_my_ip(-1), sip->listenport, sip->udp ? "udp" : "tcp"); | 693 return g_strdup_printf("<sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"", |
694 sip->username, purple_network_get_my_ip(-1), | |
695 sip->listenport, | |
696 sip->udp ? "udp" : "tcp"); | |
694 } | 697 } |
695 | 698 |
696 static void do_register_exp(struct simple_account_data *sip, int expire) { | 699 static void do_register_exp(struct simple_account_data *sip, int expire) { |
697 char *uri, *to, *contact, *hdr; | 700 char *uri, *to, *contact, *hdr; |
698 | |
699 /* Set our default expiration to 900, | |
700 * as done in the initialization of the simple_account_data | |
701 * structure. | |
702 */ | |
703 if (!expire) | |
704 expire = 900; | |
705 | 701 |
706 sip->reregister = time(NULL) + expire - 50; | 702 sip->reregister = time(NULL) + expire - 50; |
707 | 703 |
708 uri = g_strdup_printf("sip:%s", sip->servername); | 704 uri = g_strdup_printf("sip:%s", sip->servername); |
709 to = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); | 705 to = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); |
752 } | 748 } |
753 } | 749 } |
754 purple_debug_info("simple", "got %s\n", from); | 750 purple_debug_info("simple", "got %s\n", from); |
755 return from; | 751 return from; |
756 } | 752 } |
753 static gchar *find_tag(const gchar *); | |
757 | 754 |
758 static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | 755 static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { |
759 gchar *to; | 756 gchar *to = NULL; |
757 struct simple_buddy *b = NULL; | |
758 gchar *theirtag = NULL, *ourtag = NULL; | |
759 const gchar *callid = NULL; | |
760 | |
761 purple_debug_info("simple", "process subscribe response\n"); | |
760 | 762 |
761 if(msg->response == 200 || msg->response == 202) { | 763 if(msg->response == 200 || msg->response == 202) { |
764 if ( (to = parse_from(sipmsg_find_header(msg, "To"))) && | |
765 (b = g_hash_table_lookup(sip->buddies, to)) && | |
766 !(b->dialog)) | |
767 { | |
768 purple_debug_info("simple", "creating dialog" | |
769 " information for a subscription.\n"); | |
770 | |
771 theirtag = find_tag(sipmsg_find_header(msg, "To")); | |
772 ourtag = find_tag(sipmsg_find_header(msg, "From")); | |
773 callid = sipmsg_find_header(msg, "Call-ID"); | |
774 | |
775 if (theirtag && ourtag && callid) | |
776 { | |
777 b->dialog = g_new0(struct sip_dialog, 1); | |
778 b->dialog->ourtag = g_strdup(ourtag); | |
779 b->dialog->theirtag = g_strdup(theirtag); | |
780 b->dialog->callid = g_strdup(callid); | |
781 | |
782 purple_debug_info("simple", "ourtag: %s\n", | |
783 ourtag); | |
784 purple_debug_info("simple", "theirtag: %s\n", | |
785 theirtag); | |
786 purple_debug_info("simple", "callid: %s\n", | |
787 callid); | |
788 g_free(theirtag); | |
789 g_free(ourtag); | |
790 } | |
791 } | |
792 else | |
793 { | |
794 purple_debug_info("simple", "cannot create dialog!\n"); | |
795 } | |
762 return TRUE; | 796 return TRUE; |
763 } | 797 } |
764 | 798 |
765 to = parse_from(sipmsg_find_header(tc->msg, "To")); /* cant be NULL since it is our own msg */ | 799 to = parse_from(sipmsg_find_header(tc->msg, "To")); /* cant be NULL since it is our own msg */ |
766 | 800 |
769 purple_prpl_got_user_status(sip->account, to, "offline", NULL); | 803 purple_prpl_got_user_status(sip->account, to, "offline", NULL); |
770 g_free(to); | 804 g_free(to); |
771 return TRUE; | 805 return TRUE; |
772 } | 806 } |
773 | 807 |
774 static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) { | 808 static void simple_subscribe_exp(struct simple_account_data *sip, struct simple_buddy *buddy, int expiration) { |
775 gchar *contact = "Expires: 1200\r\nAccept: application/pidf+xml, application/xpidf+xml\r\nEvent: presence\r\n"; | 809 gchar *contact, *to, *tmp, *tmp2; |
776 gchar *to; | 810 |
777 gchar *tmp; | 811 tmp2 = g_strdup_printf( |
812 "Expires: %d\r\n" | |
813 "Accept: application/pidf+xml, application/xpidf+xml\r\n" | |
814 "Event: presence\r\n", | |
815 expiration); | |
778 | 816 |
779 if(strstr(buddy->name, "sip:")) | 817 if(strstr(buddy->name, "sip:")) |
780 to = g_strdup(buddy->name); | 818 to = g_strdup(buddy->name); |
781 else | 819 else |
782 to = g_strdup_printf("sip:%s", buddy->name); | 820 to = g_strdup_printf("sip:%s", buddy->name); |
783 | 821 |
784 tmp = get_contact(sip); | 822 tmp = get_contact(sip); |
785 contact = g_strdup_printf("%sContact: %s\r\n", contact, tmp); | 823 contact = g_strdup_printf("%sContact: %s\r\n", tmp2, tmp); |
786 g_free(tmp); | 824 g_free(tmp); |
787 | 825 g_free(tmp2); |
788 /* subscribe to buddy presence | 826 |
789 * we dont need to know the status so we do not need a callback */ | 827 send_sip_request(sip->gc, "SUBSCRIBE", to, to, contact,"",buddy->dialog, |
790 | 828 (expiration > 0) ? process_subscribe_response : NULL); |
791 send_sip_request(sip->gc, "SUBSCRIBE", to, to, contact, "", NULL, | |
792 process_subscribe_response); | |
793 | 829 |
794 g_free(to); | 830 g_free(to); |
795 g_free(contact); | 831 g_free(contact); |
796 | 832 |
797 /* resubscribe before subscription expires */ | 833 /* resubscribe before subscription expires */ |
798 /* add some jitter */ | 834 /* add some jitter */ |
799 buddy->resubscribe = time(NULL)+1140+(rand()%50); | 835 if (expiration > 60) |
836 buddy->resubscribe = time(NULL) + (expiration - 60) + (rand() % 50); | |
837 else if (expiration > 0) | |
838 buddy->resubscribe = time(NULL) + ((int) (expiration / 2)); | |
839 } | |
840 | |
841 static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) { | |
842 simple_subscribe_exp(sip, buddy, SUBSCRIBE_EXPIRATION); | |
843 } | |
844 | |
845 static void simple_unsubscribe(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) { | |
846 if (buddy->dialog) | |
847 { | |
848 purple_debug_info("simple", "Unsubscribing from %s\n", name); | |
849 simple_subscribe_exp(sip, buddy, 0); | |
850 } | |
800 } | 851 } |
801 | 852 |
802 static gboolean simple_add_lcs_contacts(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | 853 static gboolean simple_add_lcs_contacts(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { |
803 const gchar *tmp; | 854 const gchar *tmp; |
804 xmlnode *item, *group, *isc; | 855 xmlnode *item, *group, *isc; |
910 time_t curtime = time(NULL); | 961 time_t curtime = time(NULL); |
911 /* register again if first registration expires */ | 962 /* register again if first registration expires */ |
912 if(sip->reregister < curtime) { | 963 if(sip->reregister < curtime) { |
913 do_register(sip); | 964 do_register(sip); |
914 } | 965 } |
966 | |
967 /* publish status again if our last update is about to expire. */ | |
968 if (sip->republish != -1 && | |
969 sip->republish < curtime && | |
970 purple_account_get_bool(sip->account, "dopublish", TRUE)) | |
971 { | |
972 purple_debug_info("simple", "subscribe_timeout: republishing status.\n"); | |
973 send_open_publish(sip); | |
974 } | |
975 | |
915 /* check for every subscription if we need to resubscribe */ | 976 /* check for every subscription if we need to resubscribe */ |
916 g_hash_table_foreach(sip->buddies, (GHFunc)simple_buddy_resub, (gpointer)sip); | 977 g_hash_table_foreach(sip->buddies, (GHFunc)simple_buddy_resub, (gpointer)sip); |
917 | 978 |
918 /* remove a timed out suscriber */ | 979 /* remove a timed out suscriber */ |
919 | |
920 tmp = sip->watcher; | 980 tmp = sip->watcher; |
921 while(tmp) { | 981 while(tmp) { |
922 struct simple_watcher *watcher = tmp->data; | 982 struct simple_watcher *watcher = tmp->data; |
923 if(watcher->expire < curtime) { | 983 if(watcher->expire < curtime) { |
924 watcher_remove(sip, watcher->name); | 984 watcher_remove(sip, watcher->name); |
1068 break; | 1128 break; |
1069 } | 1129 } |
1070 return TRUE; | 1130 return TRUE; |
1071 } | 1131 } |
1072 | 1132 |
1133 static gboolean dialog_match(struct sip_dialog *dialog, struct sipmsg *msg) | |
1134 { | |
1135 const gchar *fromhdr; | |
1136 const gchar *tohdr; | |
1137 const gchar *callid; | |
1138 gchar *ourtag, *theirtag; | |
1139 gboolean match = FALSE; | |
1140 | |
1141 fromhdr = sipmsg_find_header(msg, "From"); | |
1142 tohdr = sipmsg_find_header(msg, "To"); | |
1143 callid = sipmsg_find_header(msg, "Call-ID"); | |
1144 | |
1145 if (!fromhdr || !tohdr || !callid) | |
1146 return FALSE; | |
1147 | |
1148 ourtag = find_tag(tohdr); | |
1149 theirtag = find_tag(fromhdr); | |
1150 | |
1151 if (ourtag && theirtag && | |
1152 !strcmp(dialog->callid, callid) && | |
1153 !strcmp(dialog->ourtag, ourtag) && | |
1154 !strcmp(dialog->theirtag, theirtag)) | |
1155 match = TRUE; | |
1156 | |
1157 g_free(ourtag); | |
1158 g_free(theirtag); | |
1159 | |
1160 return match; | |
1161 } | |
1162 | |
1073 static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) { | 1163 static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) { |
1074 gchar *from; | 1164 gchar *from; |
1075 const gchar *fromhdr; | 1165 const gchar *fromhdr; |
1076 gchar *basicstatus_data; | 1166 gchar *basicstatus_data; |
1077 xmlnode *pidf; | 1167 xmlnode *pidf; |
1078 xmlnode *basicstatus = NULL, *tuple, *status; | 1168 xmlnode *basicstatus = NULL, *tuple, *status; |
1079 gboolean isonline = FALSE; | 1169 gboolean isonline = FALSE; |
1170 struct simple_buddy *b = NULL; | |
1171 const gchar *sshdr = NULL; | |
1080 | 1172 |
1081 fromhdr = sipmsg_find_header(msg, "From"); | 1173 fromhdr = sipmsg_find_header(msg, "From"); |
1082 from = parse_from(fromhdr); | 1174 from = parse_from(fromhdr); |
1083 if(!from) return; | 1175 if(!from) return; |
1084 | 1176 |
1177 b = g_hash_table_lookup(sip->buddies, from); | |
1178 if (!b) | |
1179 { | |
1180 g_free(from); | |
1181 purple_debug_info("simple", "Could not find the buddy.\n"); | |
1182 return; | |
1183 } | |
1184 | |
1185 if (b->dialog && !dialog_match(b->dialog, msg)) | |
1186 { | |
1187 /* We only accept notifies from people that | |
1188 * we already have a dialog with. | |
1189 */ | |
1190 purple_debug_info("simple","No corresponding dialog for notify--discard\n"); | |
1191 g_free(from); | |
1192 return; | |
1193 } | |
1194 | |
1085 pidf = xmlnode_from_str(msg->body, msg->bodylen); | 1195 pidf = xmlnode_from_str(msg->body, msg->bodylen); |
1086 | 1196 |
1087 if(!pidf) { | 1197 if(!pidf) { |
1088 purple_debug_info("simple", "process_incoming_notify: no parseable pidf\n"); | 1198 purple_debug_info("simple", "process_incoming_notify: no parseable pidf\n"); |
1089 purple_prpl_got_user_status(sip->account, from, "offline", NULL); | 1199 sshdr = sipmsg_find_header(msg, "Subscription-State"); |
1200 if (sshdr) | |
1201 { | |
1202 int i = 0; | |
1203 gchar **ssparts = g_strsplit(sshdr, ":", 0); | |
1204 while (ssparts[i]) | |
1205 { | |
1206 g_strchug(ssparts[i]); | |
1207 if (g_str_has_prefix(ssparts[i], "terminated")) | |
1208 { | |
1209 purple_debug_info("simple", "Subscription expired!"); | |
1210 g_free(b->dialog->ourtag); | |
1211 g_free(b->dialog->theirtag); | |
1212 g_free(b->dialog->callid); | |
1213 g_free(b->dialog); | |
1214 b->dialog = NULL; | |
1215 | |
1216 purple_prpl_got_user_status(sip->account, from, "offline", NULL); | |
1217 break; | |
1218 } | |
1219 i++; | |
1220 } | |
1221 g_strfreev(ssparts); | |
1222 } | |
1090 send_sip_response(sip->gc, msg, 200, "OK", NULL); | 1223 send_sip_response(sip->gc, msg, 200, "OK", NULL); |
1091 g_free(from); | 1224 g_free(from); |
1092 return; | 1225 return; |
1093 } | 1226 } |
1094 | 1227 |
1224 } | 1357 } |
1225 return TRUE; | 1358 return TRUE; |
1226 } | 1359 } |
1227 | 1360 |
1228 static void send_open_publish(struct simple_account_data *sip) { | 1361 static void send_open_publish(struct simple_account_data *sip) { |
1362 gchar *add_headers = NULL; | |
1229 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); | 1363 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); |
1230 gchar *doc = gen_pidf(sip, TRUE); | 1364 gchar *doc = gen_pidf(sip, TRUE); |
1365 | |
1366 add_headers = g_strdup_printf("%s%d%s", | |
1367 "Expires: ", | |
1368 PUBLISH_EXPIRATION, | |
1369 "\r\nEvent: presence\r\n" | |
1370 "Content-Type: application/pidf+xml\r\n"); | |
1371 | |
1231 send_sip_request(sip->gc, "PUBLISH", uri, uri, | 1372 send_sip_request(sip->gc, "PUBLISH", uri, uri, |
1232 "Expires: 600\r\nEvent: presence\r\n" | 1373 add_headers, doc, NULL, process_publish_response); |
1233 "Content-Type: application/pidf+xml\r\n", | 1374 sip->republish = time(NULL) + PUBLISH_EXPIRATION - 50; |
1234 doc, NULL, process_publish_response); | |
1235 sip->republish = time(NULL) + 500; | |
1236 g_free(uri); | 1375 g_free(uri); |
1237 g_free(doc); | 1376 g_free(doc); |
1377 g_free(add_headers); | |
1238 } | 1378 } |
1239 | 1379 |
1240 static void send_closed_publish(struct simple_account_data *sip) { | 1380 static void send_closed_publish(struct simple_account_data *sip) { |
1241 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); | 1381 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); |
1242 gchar *doc = gen_pidf(sip, FALSE); | 1382 gchar *doc = gen_pidf(sip, FALSE); |
1750 | 1890 |
1751 if(sip) { | 1891 if(sip) { |
1752 /* unregister */ | 1892 /* unregister */ |
1753 if (sip->registerstatus == SIMPLE_REGISTER_COMPLETE) | 1893 if (sip->registerstatus == SIMPLE_REGISTER_COMPLETE) |
1754 { | 1894 { |
1755 if(purple_account_get_bool(sip->account, | 1895 g_hash_table_foreach(sip->buddies, |
1756 "dopublish", | 1896 (GHFunc)simple_unsubscribe, |
1757 TRUE)) | 1897 (gpointer)sip); |
1898 | |
1899 if(purple_account_get_bool(sip->account, | |
1900 "dopublish", TRUE)) | |
1758 send_closed_publish(sip); | 1901 send_closed_publish(sip); |
1759 | 1902 |
1760 do_register_exp(sip, 0); | 1903 do_register_exp(sip, 0); |
1761 } | 1904 } |
1762 connection_free_all(sip); | 1905 connection_free_all(sip); |
1763 | 1906 |
1764 if (sip->query_data != NULL) | 1907 if (sip->query_data != NULL) |