📄 simple.c
字号:
if(purple_circ_buffer_get_max_read(sip->txbuf) > 0) purple_circ_buffer_append(sip->txbuf, "\r\n", 2); purple_circ_buffer_append(sip->txbuf, buf, strlen(buf));}static void sendout_pkt(PurpleConnection *gc, const char *buf) { struct simple_account_data *sip = gc->proto_data; time_t currtime = time(NULL); int writelen = strlen(buf); purple_debug(PURPLE_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf); if(sip->udp) { if(sendto(sip->fd, buf, writelen, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < writelen) { purple_debug_info("simple", "could not send packet\n"); } } else { int ret; if(sip->fd < 0) { sendlater(gc, buf); return; } if(sip->tx_handler) { ret = -1; errno = EAGAIN; } else ret = write(sip->fd, buf, writelen); if (ret < 0 && errno == EAGAIN) ret = 0; else if(ret <= 0) { /* XXX: When does this happen legitimately? */ sendlater(gc, buf); return; } if (ret < writelen) { if(!sip->tx_handler) sip->tx_handler = purple_input_add(sip->fd, PURPLE_INPUT_WRITE, simple_canwrite_cb, gc); /* XXX: is it OK to do this? You might get part of a request sent with part of another. */ if(sip->txbuf->bufused > 0) purple_circ_buffer_append(sip->txbuf, "\r\n", 2); purple_circ_buffer_append(sip->txbuf, buf + ret, writelen - ret); } }}static int simple_send_raw(PurpleConnection *gc, const char *buf, int len){ sendout_pkt(gc, buf); return len;}static void sendout_sipmsg(struct simple_account_data *sip, struct sipmsg *msg) { GSList *tmp = msg->headers; gchar *name; gchar *value; GString *outstr = g_string_new(""); g_string_append_printf(outstr, "%s %s SIP/2.0\r\n", msg->method, msg->target); while(tmp) { name = ((struct siphdrelement*) (tmp->data))->name; value = ((struct siphdrelement*) (tmp->data))->value; g_string_append_printf(outstr, "%s: %s\r\n", name, value); tmp = g_slist_next(tmp); } g_string_append_printf(outstr, "\r\n%s", msg->body ? msg->body : ""); sendout_pkt(sip->gc, outstr->str); g_string_free(outstr, TRUE);}static void send_sip_response(PurpleConnection *gc, struct sipmsg *msg, int code, const char *text, const char *body) { GSList *tmp = msg->headers; gchar *name; gchar *value; GString *outstr = g_string_new(""); /* When sending the acknowlegements and errors, the content length from the original message is still here, but there is no body; we need to make sure we're sending the correct content length */ sipmsg_remove_header(msg, "Content-Length"); if(body) { gchar len[12]; sprintf(len, "%" G_GSIZE_FORMAT , strlen(body)); sipmsg_add_header(msg, "Content-Length", len); } else sipmsg_add_header(msg, "Content-Length", "0"); g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text); while(tmp) { name = ((struct siphdrelement*) (tmp->data))->name; value = ((struct siphdrelement*) (tmp->data))->value; g_string_append_printf(outstr, "%s: %s\r\n", name, value); tmp = g_slist_next(tmp); } g_string_append_printf(outstr, "\r\n%s", body ? body : ""); sendout_pkt(gc, outstr->str); g_string_free(outstr, TRUE);}static void transactions_remove(struct simple_account_data *sip, struct transaction *trans) { if(trans->msg) sipmsg_free(trans->msg); sip->transactions = g_slist_remove(sip->transactions, trans); g_free(trans);}static void transactions_add_buf(struct simple_account_data *sip, const gchar *buf, void *callback) { struct transaction *trans = g_new0(struct transaction, 1); trans->time = time(NULL); trans->msg = sipmsg_parse_msg(buf); trans->cseq = sipmsg_find_header(trans->msg, "CSeq"); trans->callback = callback; sip->transactions = g_slist_append(sip->transactions, trans);}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"); if (cseq) { while(transactions) { trans = transactions->data; if(!strcmp(trans->cseq, cseq)) { return trans; } transactions = transactions->next; } } else { purple_debug(PURPLE_DEBUG_MISC, "simple", "Received message contains no CSeq header.\n"); } return NULL;}static void send_sip_request(PurpleConnection *gc, const gchar *method, const gchar *url, const gchar *to, const gchar *addheaders, const gchar *body, struct sip_dialog *dialog, TransCallback tc) { struct simple_account_data *sip = gc->proto_data; char *callid = dialog ? g_strdup(dialog->callid) : gencallid(); char *auth = NULL; const char *addh = ""; gchar *branch = genbranch(); gchar *tag = NULL; char *buf; if(!strcmp(method, "REGISTER")) { if(sip->regcallid) { g_free(callid); callid = g_strdup(sip->regcallid); } else sip->regcallid = g_strdup(callid); } if(addheaders) addh = addheaders; if(sip->registrar.type && !strcmp(method, "REGISTER")) { buf = auth_header(sip, &sip->registrar, method, url); auth = g_strdup_printf("Authorization: %s\r\n", buf); g_free(buf); purple_debug(PURPLE_DEBUG_MISC, "simple", "header %s", auth); } else if(sip->proxy.type && strcmp(method, "REGISTER")) { buf = auth_header(sip, &sip->proxy, method, url); auth = g_strdup_printf("Proxy-Authorization: %s\r\n", buf); g_free(buf); purple_debug(PURPLE_DEBUG_MISC, "simple", "header %s", auth); } if (!dialog) tag = gentag(); buf = g_strdup_printf("%s %s SIP/2.0\r\n" "Via: SIP/2.0/%s %s:%d;branch=%s\r\n" /* Don't know what epid is, but LCS wants it */ "From: <sip:%s@%s>;tag=%s;epid=1234567890\r\n" "To: <%s>%s%s\r\n" "Max-Forwards: 10\r\n" "CSeq: %d %s\r\n" "User-Agent: Purple/" VERSION "\r\n" "Call-ID: %s\r\n" "%s%s" "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s", method, url, sip->udp ? "UDP" : "TCP", purple_network_get_my_ip(-1), sip->listenport, branch, sip->username, sip->servername, dialog ? dialog->ourtag : tag, to, dialog ? ";tag=" : "", dialog ? dialog->theirtag : "", ++sip->cseq, method, callid, auth ? auth : "", addh, strlen(body), body); g_free(tag); g_free(auth); g_free(branch); g_free(callid); /* add to ongoing transactions */ transactions_add_buf(sip, buf, tc); sendout_pkt(gc, buf); g_free(buf);}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");}static void do_register_exp(struct simple_account_data *sip, int expire) { char *uri = g_strdup_printf("sip:%s", sip->servername); char *to = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); char *contact = get_contact(sip); char *hdr = g_strdup_printf("Contact: %s\r\nExpires: %d\r\n", contact, expire); g_free(contact); sip->registerstatus = 1; if(expire) { sip->reregister = time(NULL) + expire - 50; } else { sip->reregister = time(NULL) + 600; } send_sip_request(sip->gc, "REGISTER", uri, to, hdr, "", NULL, process_register_response); g_free(hdr); g_free(uri); g_free(to);}static void do_register(struct simple_account_data *sip) { do_register_exp(sip, sip->registerexpire);}static gchar *parse_from(const gchar *hdr) { gchar *from; const gchar *tmp, *tmp2 = hdr; if(!hdr) return NULL; purple_debug_info("simple", "parsing address out of %s\n", hdr); tmp = strchr(hdr, '<'); /* i hate the different SIP UA behaviours... */ if(tmp) { /* sip address in <...> */ tmp2 = tmp + 1; tmp = strchr(tmp2, '>'); if(tmp) { from = g_strndup(tmp2, tmp - tmp2); } else { purple_debug_info("simple", "found < without > in From\n"); return NULL; } } else { tmp = strchr(tmp2, ';'); if(tmp) { from = g_strndup(tmp2, tmp - tmp2); } else { from = g_strdup(tmp2); } } purple_debug_info("simple", "got %s\n", from); return from;}static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { gchar *to; if(msg->response == 200 || msg->response == 202) { return TRUE; } to = parse_from(sipmsg_find_header(tc->msg, "To")); /* cant be NULL since it is our own msg */ /* we can not subscribe -> user is offline (TODO unknown status?) */ purple_prpl_got_user_status(sip->account, to, "offline", NULL); g_free(to); 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; if(strstr(buddy->name, "sip:")) to = g_strdup(buddy->name); else to = g_strdup_printf("sip:%s", buddy->name); tmp = get_contact(sip); contact = g_strdup_printf("%sContact: %s\r\n", contact, tmp); g_free(tmp); /* 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); g_free(to); g_free(contact); /* resubscribe before subscription expires */ /* add some jitter */ buddy->resubscribe = time(NULL)+1140+(rand()%50);}static gboolean simple_add_lcs_contacts(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { gchar *tmp; xmlnode *item, *group, *isc; const char *name_group; PurpleBuddy *b; PurpleGroup *g = NULL; struct simple_buddy *bs; int len = msg->bodylen; tmp = sipmsg_find_header(msg, "Event"); if(tmp && !strncmp(tmp, "vnd-microsoft-roaming-contacts", 30)){ purple_debug_info("simple", "simple_add_lcs_contacts->%s-%d\n", msg->body, len); /*Convert the contact from XML to Purple Buddies*/ isc = xmlnode_from_str(msg->body, len); /* ToDo. Find for all groups */ if ((group = xmlnode_get_child(isc, "group"))) { name_group = xmlnode_get_attrib(group, "name"); purple_debug_info("simple", "name_group->%s\n", name_group); g = purple_find_group(name_group); if(!g) g = purple_group_new(name_group); } if (!g) { g = purple_find_group("Buddies"); if(!g) g = purple_group_new("Buddies"); } for(item = xmlnode_get_child(isc, "contact"); item; item = xmlnode_get_next_twin(item)) { const char *uri, *name, *groups; char *buddy_name; uri = xmlnode_get_attrib(item, "uri"); name = xmlnode_get_attrib(item, "name"); groups = xmlnode_get_attrib(item, "groups"); purple_debug_info("simple", "URI->%s\n", uri); buddy_name = g_strdup_printf("sip:%s", uri); b = purple_find_buddy(sip->account, buddy_name); if(!b){ b = purple_buddy_new(sip->account, buddy_name, uri); } g_free(buddy_name); purple_blist_add_buddy(b, NULL, g, NULL); purple_blist_alias_buddy(b, uri); bs = g_new0(struct simple_buddy, 1); bs->name = g_strdup(b->name); g_hash_table_insert(sip->buddies, bs->name, bs); } xmlnode_free(isc); } return 0;}static void simple_subscribe_buddylist(struct simple_account_data *sip) { gchar *contact = "Event: vnd-microsoft-roaming-contacts\r\nAccept: application/vnd-microsoft-roaming-contacts+xml\r\nSupported: com.microsoft.autoextend\r\nSupported: ms-benotify\r\nProxy-Require: ms-benotify\r\nSupported: ms-piggyback-first-notify\r\n"; gchar *to; gchar *tmp; to = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); tmp = get_contact(sip); contact = g_strdup_printf("%sContact: %s\r\n", contact, tmp); g_free(tmp); send_sip_request(sip->gc, "SUBSCRIBE", to, to, contact, "", NULL, simple_add_lcs_contacts); g_free(to); g_free(contact);}static void simple_buddy_resub(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) { time_t curtime = time(NULL); purple_debug_info("simple", "buddy resub\n"); if(buddy->resubscribe < curtime) { purple_debug(PURPLE_DEBUG_MISC, "simple", "simple_buddy_resub %s\n", name); simple_subscribe(sip, buddy); }}static gboolean resend_timeout(struct simple_account_data *sip) { GSList *tmp = sip->transactions; time_t currtime = time(NULL); while(tmp) { struct transaction *trans = tmp->data; tmp = tmp->next; purple_debug_info("simple", "have open transaction age: %d\n", currtime- trans->time); if((currtime - trans->time > 5) && trans->retries >= 1) { /* TODO 408 */ } else { if((currtime - trans->time > 2) && trans->retries == 0) { trans->retries++; sendout_sipmsg(sip, trans->msg); } } } return TRUE;}static gboolean subscribe_timeout(struct simple_account_data *sip) { GSList *tmp; time_t curtime = time(NULL); /* register again if first registration expires */ if(sip->reregister < curtime) { do_register(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; if(watcher->expire < curtime) { watcher_remove(sip, watcher->name); tmp = sip->watcher; } if(tmp) tmp = tmp->next; } return TRUE;}static void simple_send_message(struct simple_account_data *sip, const char *to, const char *msg, const char *type) { gchar *hdr; gchar *fullto; if(strncmp("sip:", to, 4)) { fullto = g_strdup_printf("sip:%s", to); } else { fullto = g_strdup(to); } if(type) { hdr = g_strdup_printf("Content-Type: %s\r\n", type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -