Mercurial > pidgin.yaz
diff libpurple/protocols/simple/simple.c @ 21418:38cc722159ff
propagate from branch 'im.pidgin.pidgin' (head d8103be97302efb404e2f6922925f661c807ad23)
to branch 'im.pidgin.cpw.resiak.disconnectreason' (head 0ac25a1f38ae28654c967caa143f1c0d12ef2e1c)
author | Will Thompson <will.thompson@collabora.co.uk> |
---|---|
date | Sat, 10 Nov 2007 12:10:04 +0000 |
parents | e747ac0c42d6 b2d9f859663e |
children | c38d72677c8a 60f5abc6cf0c |
line wrap: on
line diff
--- a/libpurple/protocols/simple/simple.c Wed Nov 07 11:23:03 2007 +0000 +++ b/libpurple/protocols/simple/simple.c Sat Nov 10 12:10:04 2007 +0000 @@ -321,7 +321,7 @@ return retval; } -static void fill_auth(struct simple_account_data *sip, gchar *hdr, struct sip_auth *auth) { +static void fill_auth(struct simple_account_data *sip, const gchar *hdr, struct sip_auth *auth) { int i = 0; const char *authuser; char *tmp; @@ -596,7 +596,7 @@ static struct transaction *transactions_find(struct simple_account_data *sip, struct sipmsg *msg) { struct transaction *trans; GSList *transactions = sip->transactions; - gchar *cseq = sipmsg_find_header(msg, "CSeq"); + const gchar *cseq = sipmsg_find_header(msg, "CSeq"); if (cseq) { while(transactions) { @@ -694,19 +694,15 @@ } static char *get_contact(struct simple_account_data *sip) { - 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"); + 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"); } static void do_register_exp(struct simple_account_data *sip, int expire) { char *uri, *to, *contact, *hdr; - /* Set our default expiration to 900, - * as done in the initialization of the simple_account_data - * structure. - */ - if (!expire) - expire = 900; - sip->reregister = time(NULL) + expire - 50; uri = g_strdup_printf("sip:%s", sip->servername); @@ -758,11 +754,49 @@ purple_debug_info("simple", "got %s\n", from); return from; } +static gchar *find_tag(const gchar *); static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { - gchar *to; + gchar *to = NULL; + struct simple_buddy *b = NULL; + gchar *theirtag = NULL, *ourtag = NULL; + const gchar *callid = NULL; + + purple_debug_info("simple", "process subscribe response\n"); if(msg->response == 200 || msg->response == 202) { + if ( (to = parse_from(sipmsg_find_header(msg, "To"))) && + (b = g_hash_table_lookup(sip->buddies, to)) && + !(b->dialog)) + { + purple_debug_info("simple", "creating dialog" + " information for a subscription.\n"); + + theirtag = find_tag(sipmsg_find_header(msg, "To")); + ourtag = find_tag(sipmsg_find_header(msg, "From")); + callid = sipmsg_find_header(msg, "Call-ID"); + + if (theirtag && ourtag && callid) + { + b->dialog = g_new0(struct sip_dialog, 1); + b->dialog->ourtag = g_strdup(ourtag); + b->dialog->theirtag = g_strdup(theirtag); + b->dialog->callid = g_strdup(callid); + + purple_debug_info("simple", "ourtag: %s\n", + ourtag); + purple_debug_info("simple", "theirtag: %s\n", + theirtag); + purple_debug_info("simple", "callid: %s\n", + callid); + g_free(theirtag); + g_free(ourtag); + } + } + else + { + purple_debug_info("simple", "cannot create dialog!\n"); + } return TRUE; } @@ -775,10 +809,14 @@ return TRUE; } -static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) { - gchar *contact = "Expires: 1200\r\nAccept: application/pidf+xml, application/xpidf+xml\r\nEvent: presence\r\n"; - gchar *to; - gchar *tmp; +static void simple_subscribe_exp(struct simple_account_data *sip, struct simple_buddy *buddy, int expiration) { + gchar *contact, *to, *tmp, *tmp2; + + tmp2 = g_strdup_printf( + "Expires: %d\r\n" + "Accept: application/pidf+xml, application/xpidf+xml\r\n" + "Event: presence\r\n", + expiration); if(strstr(buddy->name, "sip:")) to = g_strdup(buddy->name); @@ -786,25 +824,38 @@ to = g_strdup_printf("sip:%s", buddy->name); tmp = get_contact(sip); - contact = g_strdup_printf("%sContact: %s\r\n", contact, tmp); + contact = g_strdup_printf("%sContact: %s\r\n", tmp2, tmp); g_free(tmp); + g_free(tmp2); - /* subscribe to buddy presence - * we dont need to know the status so we do not need a callback */ - - send_sip_request(sip->gc, "SUBSCRIBE", to, to, contact, "", NULL, - process_subscribe_response); + send_sip_request(sip->gc, "SUBSCRIBE", to, to, contact,"",buddy->dialog, + (expiration > 0) ? process_subscribe_response : NULL); g_free(to); g_free(contact); /* resubscribe before subscription expires */ /* add some jitter */ - buddy->resubscribe = time(NULL)+1140+(rand()%50); + if (expiration > 60) + buddy->resubscribe = time(NULL) + (expiration - 60) + (rand() % 50); + else if (expiration > 0) + buddy->resubscribe = time(NULL) + ((int) (expiration / 2)); +} + +static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) { + simple_subscribe_exp(sip, buddy, SUBSCRIBE_EXPIRATION); +} + +static void simple_unsubscribe(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) { + if (buddy->dialog) + { + purple_debug_info("simple", "Unsubscribing from %s\n", name); + simple_subscribe_exp(sip, buddy, 0); + } } static gboolean simple_add_lcs_contacts(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { - gchar *tmp; + const gchar *tmp; xmlnode *item, *group, *isc; const char *name_group; PurpleBuddy *b; @@ -916,11 +967,20 @@ if(sip->reregister < curtime) { do_register(sip); } + + /* publish status again if our last update is about to expire. */ + if (sip->republish != -1 && + sip->republish < curtime && + purple_account_get_bool(sip->account, "dopublish", TRUE)) + { + purple_debug_info("simple", "subscribe_timeout: republishing status.\n"); + send_open_publish(sip); + } + /* check for every subscription if we need to resubscribe */ g_hash_table_foreach(sip->buddies, (GHFunc)simple_buddy_resub, (gpointer)sip); /* remove a timed out suscriber */ - tmp = sip->watcher; while(tmp) { struct simple_watcher *watcher = tmp->data; @@ -964,7 +1024,7 @@ static void process_incoming_message(struct simple_account_data *sip, struct sipmsg *msg) { gchar *from; - gchar *contenttype; + const gchar *contenttype; gboolean found = FALSE; from = parse_from(sipmsg_find_header(msg, "From")); @@ -1019,7 +1079,7 @@ gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { - gchar *tmp; + const gchar *tmp; purple_debug(PURPLE_DEBUG_MISC, "simple", "in process register response response: %d\n", msg->response); switch (msg->response) { case 200: @@ -1075,23 +1135,96 @@ return TRUE; } +static gboolean dialog_match(struct sip_dialog *dialog, struct sipmsg *msg) +{ + const gchar *fromhdr; + const gchar *tohdr; + const gchar *callid; + gchar *ourtag, *theirtag; + gboolean match = FALSE; + + fromhdr = sipmsg_find_header(msg, "From"); + tohdr = sipmsg_find_header(msg, "To"); + callid = sipmsg_find_header(msg, "Call-ID"); + + if (!fromhdr || !tohdr || !callid) + return FALSE; + + ourtag = find_tag(tohdr); + theirtag = find_tag(fromhdr); + + if (ourtag && theirtag && + !strcmp(dialog->callid, callid) && + !strcmp(dialog->ourtag, ourtag) && + !strcmp(dialog->theirtag, theirtag)) + match = TRUE; + + g_free(ourtag); + g_free(theirtag); + + return match; +} + static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) { gchar *from; - gchar *fromhdr; + const gchar *fromhdr; gchar *basicstatus_data; xmlnode *pidf; xmlnode *basicstatus = NULL, *tuple, *status; gboolean isonline = FALSE; + struct simple_buddy *b = NULL; + const gchar *sshdr = NULL; fromhdr = sipmsg_find_header(msg, "From"); from = parse_from(fromhdr); if(!from) return; + b = g_hash_table_lookup(sip->buddies, from); + if (!b) + { + g_free(from); + purple_debug_info("simple", "Could not find the buddy.\n"); + return; + } + + if (b->dialog && !dialog_match(b->dialog, msg)) + { + /* We only accept notifies from people that + * we already have a dialog with. + */ + purple_debug_info("simple","No corresponding dialog for notify--discard\n"); + g_free(from); + return; + } + pidf = xmlnode_from_str(msg->body, msg->bodylen); if(!pidf) { purple_debug_info("simple", "process_incoming_notify: no parseable pidf\n"); - purple_prpl_got_user_status(sip->account, from, "offline", NULL); + sshdr = sipmsg_find_header(msg, "Subscription-State"); + if (sshdr) + { + int i = 0; + gchar **ssparts = g_strsplit(sshdr, ":", 0); + while (ssparts[i]) + { + g_strchug(ssparts[i]); + if (g_str_has_prefix(ssparts[i], "terminated")) + { + purple_debug_info("simple", "Subscription expired!"); + g_free(b->dialog->ourtag); + g_free(b->dialog->theirtag); + g_free(b->dialog->callid); + g_free(b->dialog); + b->dialog = NULL; + + purple_prpl_got_user_status(sip->account, from, "offline", NULL); + break; + } + i++; + } + g_strfreev(ssparts); + } send_sip_response(sip->gc, msg, 200, "OK", NULL); g_free(from); return; @@ -1231,15 +1364,22 @@ } static void send_open_publish(struct simple_account_data *sip) { + gchar *add_headers = NULL; gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); gchar *doc = gen_pidf(sip, TRUE); + + add_headers = g_strdup_printf("%s%d%s", + "Expires: ", + PUBLISH_EXPIRATION, + "\r\nEvent: presence\r\n" + "Content-Type: application/pidf+xml\r\n"); + send_sip_request(sip->gc, "PUBLISH", uri, uri, - "Expires: 600\r\nEvent: presence\r\n" - "Content-Type: application/pidf+xml\r\n", - doc, NULL, process_publish_response); - sip->republish = time(NULL) + 500; + add_headers, doc, NULL, process_publish_response); + sip->republish = time(NULL) + PUBLISH_EXPIRATION - 50; g_free(uri); g_free(doc); + g_free(add_headers); } static void send_closed_publish(struct simple_account_data *sip) { @@ -1260,8 +1400,8 @@ gchar *theirtag = find_tag(from_hdr); gchar *ourtag = find_tag(sipmsg_find_header(msg, "To")); gboolean tagadded = FALSE; - gchar *callid = sipmsg_find_header(msg, "Call-ID"); - gchar *expire = sipmsg_find_header(msg, "Expire"); + const gchar *callid = sipmsg_find_header(msg, "Call-ID"); + const gchar *expire = sipmsg_find_header(msg, "Expire"); gchar *tmp; struct simple_watcher *watcher = watcher_find(sip, from); if(!ourtag) { @@ -1269,14 +1409,14 @@ ourtag = gentag(); } if(!watcher) { /* new subscription */ - gchar *acceptheader = sipmsg_find_header(msg, "Accept"); + const gchar *acceptheader = sipmsg_find_header(msg, "Accept"); gboolean needsxpidf = FALSE; if(!purple_privacy_check(sip->account, from)) { send_sip_response(sip->gc, msg, 202, "Ok", NULL); goto privend; } if(acceptheader) { - gchar *tmp = acceptheader; + const gchar *tmp = acceptheader; gboolean foundpidf = FALSE; gboolean foundxpidf = FALSE; while(tmp && tmp < acceptheader + strlen(acceptheader)) { @@ -1294,7 +1434,6 @@ tmp = 0; } if(!foundpidf && foundxpidf) needsxpidf = TRUE; - g_free(acceptheader); } watcher = watcher_create(sip, from, callid, ourtag, theirtag, needsxpidf); } @@ -1319,8 +1458,6 @@ g_free(from); g_free(theirtag); g_free(ourtag); - g_free(callid); - g_free(expire); } static void process_input_message(struct simple_account_data *sip, struct sipmsg *msg) { @@ -1342,7 +1479,8 @@ struct transaction *trans = transactions_find(sip, msg); if(trans) { if(msg->response == 407) { - gchar *resend, *auth, *ptmp; + gchar *resend, *auth; + const gchar *ptmp; if(sip->proxy.retries > 3) return; sip->proxy.retries++; @@ -1386,7 +1524,8 @@ /* This is encountered when a generic (MESSAGE, NOTIFY, etc) * was denied until further authorization is provided. */ - gchar *resend, *auth, *ptmp; + gchar *resend, *auth; + const gchar *ptmp; if(sip->registrar.retries > SIMPLE_REGISTER_RETRY_MAX) return; sip->registrar.retries++; @@ -1775,11 +1914,14 @@ /* unregister */ if (sip->registerstatus == SIMPLE_REGISTER_COMPLETE) { - if(purple_account_get_bool(sip->account, - "dopublish", - TRUE)) + g_hash_table_foreach(sip->buddies, + (GHFunc)simple_unsubscribe, + (gpointer)sip); + + if(purple_account_get_bool(sip->account, + "dopublish", TRUE)) send_closed_publish(sip); - + do_register_exp(sip, 0); } connection_free_all(sip); @@ -1911,7 +2053,7 @@ "prpl-simple", /**< id */ "SIMPLE", /**< name */ - VERSION, /**< version */ + DISPLAY_VERSION, /**< version */ N_("SIP/SIMPLE Protocol Plugin"), /** summary */ N_("The SIP/SIMPLE Protocol Plugin"), /** description */ "Thomas Butter <butter@uni-mannheim.de>", /**< author */