📄 simple.c
字号:
} else { hdr = g_strdup("Content-Type: text/plain\r\n"); } send_sip_request(sip->gc, "MESSAGE", fullto, fullto, hdr, msg, NULL, NULL); g_free(hdr); g_free(fullto);}static int simple_im_send(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags) { struct simple_account_data *sip = gc->proto_data; char *to = g_strdup(who); char *text = purple_unescape_html(what); simple_send_message(sip, to, text, NULL); g_free(to); g_free(text); return 1;}static void process_incoming_message(struct simple_account_data *sip, struct sipmsg *msg) { gchar *from; gchar *contenttype; gboolean found = FALSE; from = parse_from(sipmsg_find_header(msg, "From")); if(!from) return; purple_debug(PURPLE_DEBUG_MISC, "simple", "got message from %s: %s\n", from, msg->body); contenttype = sipmsg_find_header(msg, "Content-Type"); if(!contenttype || !strncmp(contenttype, "text/plain", 10) || !strncmp(contenttype, "text/html", 9)) { serv_got_im(sip->gc, from, msg->body, 0, time(NULL)); send_sip_response(sip->gc, msg, 200, "OK", NULL); found = TRUE; } if(!strncmp(contenttype, "application/im-iscomposing+xml", 30)) { xmlnode *isc = xmlnode_from_str(msg->body, msg->bodylen); xmlnode *state; gchar *statedata; if(!isc) { purple_debug_info("simple", "process_incoming_message: can not parse iscomposing\n"); return; } state = xmlnode_get_child(isc, "state"); if(!state) { purple_debug_info("simple", "process_incoming_message: no state found\n"); xmlnode_free(isc); return; } statedata = xmlnode_get_data(state); if(statedata) { if(strstr(statedata, "active")) serv_got_typing(sip->gc, from, 0, PURPLE_TYPING); else serv_got_typing_stopped(sip->gc, from); g_free(statedata); } xmlnode_free(isc); send_sip_response(sip->gc, msg, 200, "OK", NULL); found = TRUE; } if(!found) { purple_debug_info("simple", "got unknown mime-type"); send_sip_response(sip->gc, msg, 415, "Unsupported media type", NULL); } g_free(from);}gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { gchar *tmp; purple_debug(PURPLE_DEBUG_MISC, "simple", "in process register response response: %d\n", msg->response); switch (msg->response) { case 200: if(sip->registerstatus < 3) { /* registered */ if(purple_account_get_bool(sip->account, "dopublish", TRUE)) { send_publish(sip); } } sip->registerstatus = 3; purple_connection_set_state(sip->gc, PURPLE_CONNECTED); /* get buddies from blist */ simple_get_buddies(sip->gc); subscribe_timeout(sip); tmp = sipmsg_find_header(msg, "Allow-Events"); if(tmp && strstr(tmp, "vnd-microsoft-provisioning")){ simple_subscribe_buddylist(sip); } break; case 401: if(sip->registerstatus != 2) { purple_debug_info("simple", "REGISTER retries %d\n", sip->registrar.retries); if(sip->registrar.retries > 3) { sip->gc->wants_to_die = TRUE; purple_connection_error(sip->gc, _("Incorrect password.")); return TRUE; } tmp = sipmsg_find_header(msg, "WWW-Authenticate"); fill_auth(sip, tmp, &sip->registrar); sip->registerstatus = 2; do_register(sip); } break; } return TRUE;}static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) { gchar *from; gchar *fromhdr; gchar *tmp2; xmlnode *pidf; xmlnode *basicstatus = NULL, *tuple, *status; gboolean isonline = FALSE; fromhdr = sipmsg_find_header(msg, "From"); from = parse_from(fromhdr); if(!from) return; pidf = xmlnode_from_str(msg->body, msg->bodylen); if(!pidf) { purple_debug_info("simple", "process_incoming_notify: no parseable pidf\n"); return; } if ((tuple = xmlnode_get_child(pidf, "tuple"))) if ((status = xmlnode_get_child(tuple, "status"))) basicstatus = xmlnode_get_child(status, "basic"); if(!basicstatus) { purple_debug_info("simple", "process_incoming_notify: no basic found\n"); xmlnode_free(pidf); return; } tmp2 = xmlnode_get_data(basicstatus); if(!tmp2) { purple_debug_info("simple", "process_incoming_notify: no basic data found\n"); xmlnode_free(pidf); return; } if(strstr(tmp2, "open")) { isonline = TRUE; } g_free(tmp2); if(isonline) purple_prpl_got_user_status(sip->account, from, "available", NULL); else purple_prpl_got_user_status(sip->account, from, "offline", NULL); xmlnode_free(pidf); g_free(from); send_sip_response(sip->gc, msg, 200, "OK", NULL);}static unsigned int simple_typing(PurpleConnection *gc, const char *name, PurpleTypingState state) { struct simple_account_data *sip = gc->proto_data; gchar *xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<isComposing xmlns=\"urn:ietf:params:xml:ns:im-iscomposing\"\n" "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" "xsi:schemaLocation=\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\">\n" "<state>%s</state>\n" "<contenttype>text/plain</contenttype>\n" "<refresh>60</refresh>\n" "</isComposing>"; gchar *recv = g_strdup(name); if(state == PURPLE_TYPING) { gchar *msg = g_strdup_printf(xml, "active"); simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); g_free(msg); } else /* TODO: Only if (state == PURPLE_TYPED) ? */ { gchar *msg = g_strdup_printf(xml, "idle"); simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); g_free(msg); } g_free(recv); /* * TODO: Is this right? It will cause the core to call * serv_send_typing(gc, who, PURPLE_TYPING) once every second * until the user stops typing. If that's not desired, * then return 0 instead. */ return 1;}static gchar *find_tag(const gchar *hdr) { const gchar *tmp = strstr(hdr, ";tag="), *tmp2; if(!tmp) return NULL; tmp += 5; if((tmp2 = strchr(tmp, ';'))) { return g_strndup(tmp, tmp2 - tmp); } return g_strdup(tmp);}static gchar* gen_xpidf(struct simple_account_data *sip) { gchar *doc = g_strdup_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<presence>\n" "<presentity uri=\"sip:%s@%s;method=SUBSCRIBE\"/>\n" "<display name=\"sip:%s@%s\"/>\n" "<atom id=\"1234\">\n" "<address uri=\"sip:%s@%s\">\n" "<status status=\"%s\"/>\n" "</address>\n" "</atom>\n" "</presence>\n", sip->username, sip->servername, sip->username, sip->servername, sip->username, sip->servername, sip->status); return doc;}static gchar* gen_pidf(struct simple_account_data *sip) { gchar *doc = g_strdup_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n" "xmlns:im=\"urn:ietf:params:xml:ns:pidf:im\"\n" "entity=\"sip:%s@%s\">\n" "<tuple id=\"bs35r9f\">\n" "<status>\n" "<basic>open</basic>\n" "</status>\n" "<note>%s</note>\n" "</tuple>\n" "</presence>", sip->username, sip->servername, sip->status); return doc;}static void send_notify(struct simple_account_data *sip, struct simple_watcher *watcher) { gchar *doc = watcher->needsxpidf ? gen_xpidf(sip) : gen_pidf(sip); gchar *hdr = watcher->needsxpidf ? "Event: presence\r\nContent-Type: application/xpidf+xml\r\n" : "Event: presence\r\nContent-Type: application/pidf+xml\r\n"; send_sip_request(sip->gc, "NOTIFY", watcher->name, watcher->name, hdr, doc, &watcher->dialog, NULL); g_free(doc);}static gboolean process_publish_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { if(msg->response != 200 && msg->response != 408) { /* never send again */ sip->republish = -1; } return TRUE;}static void send_publish(struct simple_account_data *sip) { gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); gchar *doc = gen_pidf(sip); 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; g_free(uri); g_free(doc);}static void process_incoming_subscribe(struct simple_account_data *sip, struct sipmsg *msg) { const char *from_hdr = sipmsg_find_header(msg, "From"); gchar *from = parse_from(from_hdr); 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"); gchar *tmp; struct simple_watcher *watcher = watcher_find(sip, from); if(!ourtag) { tagadded = TRUE; ourtag = gentag(); } if(!watcher) { /* new subscription */ 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; gboolean foundpidf = FALSE; gboolean foundxpidf = FALSE; while(tmp && tmp < acceptheader + strlen(acceptheader)) { gchar *tmp2 = strchr(tmp, ','); if(tmp2) *tmp2 = '\0'; if(!g_ascii_strcasecmp("application/pidf+xml", tmp)) foundpidf = TRUE; if(!g_ascii_strcasecmp("application/xpidf+xml", tmp)) foundxpidf = TRUE; if(tmp2) { *tmp2 = ','; tmp = tmp2 + 1; while(*tmp == ' ') tmp++; } else tmp = 0; } if(!foundpidf && foundxpidf) needsxpidf = TRUE; g_free(acceptheader); } watcher = watcher_create(sip, from, callid, ourtag, theirtag, needsxpidf); } if(tagadded) { gchar *to = g_strdup_printf("%s;tag=%s", sipmsg_find_header(msg, "To"), ourtag); sipmsg_remove_header(msg, "To"); sipmsg_add_header(msg, "To", to); g_free(to); } if(expire) watcher->expire = time(NULL) + strtol(expire, NULL, 10); else watcher->expire = time(NULL) + 600; sipmsg_remove_header(msg, "Contact"); tmp = get_contact(sip); sipmsg_add_header(msg, "Contact", tmp); g_free(tmp); purple_debug_info("simple", "got subscribe: name %s ourtag %s theirtag %s callid %s\n", watcher->name, watcher->dialog.ourtag, watcher->dialog.theirtag, watcher->dialog.callid); send_sip_response(sip->gc, msg, 200, "Ok", NULL); send_notify(sip, watcher);privend: 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) { gboolean found = FALSE; if(msg->response == 0) { /* request */ if(!strcmp(msg->method, "MESSAGE")) { process_incoming_message(sip, msg); found = TRUE; } else if(!strcmp(msg->method, "NOTIFY")) { process_incoming_notify(sip, msg); found = TRUE; } else if(!strcmp(msg->method, "SUBSCRIBE")) { process_incoming_subscribe(sip, msg); found = TRUE; } else { send_sip_response(sip->gc, msg, 501, "Not implemented", NULL); } } else { /* response */ struct transaction *trans = transactions_find(sip, msg); if(trans) { if(msg->response == 407) { gchar *resend, *auth, *ptmp; if(sip->proxy.retries > 3) return; sip->proxy.retries++; /* do proxy authentication */ ptmp = sipmsg_find_header(msg, "Proxy-Authenticate"); fill_auth(sip, ptmp, &sip->proxy); auth = auth_header(sip, &sip->proxy, trans->msg->method, trans->msg->target); sipmsg_remove_header(trans->msg, "Proxy-Authorization"); sipmsg_add_header(trans->msg, "Proxy-Authorization", auth); g_free(auth); resend = sipmsg_to_string(trans->msg); /* resend request */ sendout_pkt(sip->gc, resend); g_free(resend); } else { if(msg->response == 100) { /* ignore provisional response */ purple_debug_info("simple", "got trying response\n"); } else { sip->proxy.retries = 0; if(!strcmp(trans->msg->method, "REGISTER")) { if(msg->response == 401) sip->registrar.retries++; else sip->registrar.retries = 0; } else { if(msg->response == 401) { gchar *resend, *auth, *ptmp; if(sip->registrar.retries > 4) return; sip->registrar.retries++; ptmp = sipmsg_find_header(msg, "WWW-Authenticate"); fill_auth(sip, ptmp, &sip->registrar); auth = auth_header(sip, &sip->registrar, trans->msg->method, trans->msg->target); sipmsg_remove_header(trans->msg, "Authorization"); sipmsg_add_header(trans->msg, "Authorization", auth); g_free(auth); resend = sipmsg_to_string(trans->msg); /* resend request */ sendout_pkt(sip->gc, resend); g_free(resend); } } if(trans->callback) { /* call the callback to process response*/ (trans->callback)(sip, msg, trans); } transactions_remove(sip, trans); } } found = TRUE; } else { purple_debug(PURPLE_DEBUG_MISC, "simple", "received response to unknown transaction"); } } if(!found) { purple_debug(PURPLE_DEBUG_MISC, "simple", "received a unknown sip message with method %s and response %d\n", msg->method, msg->response); }}static void process_input(struct simple_account_data *sip, struct sip_connection *conn){ char *cur; char *dummy; struct sipmsg *msg; int restlen; cur = conn->inbuf; /* according to the RFC remove CRLF at the beginning */ while(*cur == '\r' || *cur == '\n') { cur++; } if(cur != conn->inbuf) { memmove(conn->inbuf, cur, conn->inbufused - (cur - conn->inbuf)); conn->inbufused = strlen(conn->inbuf); } /* Received a full Header? */ if((cur = strstr(conn->inbuf, "\r\n\r\n")) != NULL) { time_t currtime = time(NULL); cur += 2; cur[0] = '\0'; purple_debug_info("simple", "\n\nreceived - %s\n######\n%s\n#######\n\n", ctime(&currtime), conn->inbuf); msg = sipmsg_parse_header(conn->inbuf); cur[0] = '\r'; cur += 2; restlen = conn->inbufused - (cur - conn->inbuf); if(restlen >= msg->bodylen) { dummy = g_malloc(msg->bodylen + 1); memcpy(dummy, cur, msg->bodylen); dummy[msg->bodylen] = '\0'; msg->body = dummy; cur += msg->bodylen; memmove(conn->inbuf, cur, conn->inbuflen - (cur - conn->inbuf)); conn->inbufused = strlen(conn->inbuf); } else { sipmsg_free(msg); return; } purple_debug(PURPLE_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); process_input_message(sip, msg); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -