📄 oscar.c
字号:
if (dim->watcher) gaim_input_remove(dim->watcher); if (dim->conn) { aim_conn_close(dim->conn); aim_conn_kill(od->sess, &dim->conn); } g_free(dim);}/* the only difference between this and destroy is this writes a conv message */static void oscar_direct_im_disconnect(OscarData *od, struct oscar_direct_im *dim){ GaimConversation *conv; char buf[256]; gaim_debug_info("oscar", "%s disconnected Direct IM.\n", dim->name); if (dim->connected) g_snprintf(buf, sizeof buf, _("Direct IM with %s closed"), dim->name); else g_snprintf(buf, sizeof buf, _("Direct IM with %s failed"), dim->name); conv = gaim_find_conversation_with_account(dim->name, gaim_connection_get_account(dim->gc)); if (conv) { gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); gaim_conversation_update_progress(conv, 0); } else { gaim_notify_error(dim->gc, NULL, _("Direct Connect failed"), buf); } oscar_direct_im_destroy(od, dim); return;}/* oops i made two of these. this one just calls the other one. */static void gaim_odc_disconnect(aim_session_t *sess, aim_conn_t *conn){ GaimConnection *gc = sess->aux_data; OscarData *od = (OscarData *)gc->proto_data; struct oscar_direct_im *dim; char *sn; sn = g_strdup(aim_odc_getsn(conn)); dim = oscar_direct_im_find(od, sn); oscar_direct_im_disconnect(od, dim); g_free(sn);}static void destroy_direct_im_request(struct ask_direct *d) { gaim_debug_info("oscar", "Freeing DirectIM prompts.\n"); g_free(d->sn); g_free(d);}/* this is just a gaim_proxy_connect cb that sets up the rest of the cbs */static void oscar_odc_callback(gpointer data, gint source, GaimInputCondition condition) { struct oscar_direct_im *dim = data; GaimConnection *gc = dim->gc; OscarData *od = gc->proto_data; GaimConversation *conv; char buf[256]; struct sockaddr name; socklen_t name_len = 1; g_return_if_fail(gc != NULL); dim->gpc_pend = FALSE; if (dim->killme) { oscar_direct_im_destroy(od, dim); return; } if (!g_list_find(gaim_connections_get_all(), gc)) { oscar_direct_im_destroy(od, dim); return; } if (source < 0) { if (dim->donttryagain) { oscar_direct_im_disconnect(od, dim); return; } else { fu8_t cookie[8]; char *who = g_strdup(dim->name); const char *tmp = aim_odc_getcookie(dim->conn); memcpy(cookie, tmp, 8); oscar_direct_im_destroy(od, dim); oscar_direct_im_initiate(gc, who, cookie); gaim_debug_info("oscar", "asking direct im initiator to connect to us\n"); g_free(who); return; } } dim->conn->fd = source; aim_conn_completeconnect(od->sess, dim->conn); conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, dim->name); /* This is the best way to see if we're connected or not */ /* Is this really needed? */ if (getpeername(source, &name, &name_len) == 0) { g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), dim->name); dim->connected = TRUE; gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); } else { if (dim->donttryagain) { oscar_direct_im_disconnect(od, dim); return; } else { fu8_t cookie[8]; char *who = g_strdup(dim->name); const char *tmp = aim_odc_getcookie(dim->conn); memcpy(cookie, tmp, 8); oscar_direct_im_destroy(od, dim); oscar_direct_im_initiate(gc, who, cookie); gaim_debug_info("oscar", "asking direct im initiator to connect to us\n"); g_free(who); return; } }}static void accept_direct_im_request(struct ask_direct *d) { GaimConnection *gc = d->gc; OscarData *od; struct oscar_direct_im *dim; char *host; int port = 5190; int i, rc; char *tmp; GaimConversation *conv; if (!g_list_find(gaim_connections_get_all(), gc)) { destroy_direct_im_request(d); return; } od = (OscarData *)gc->proto_data; gaim_debug_info("oscar", "Accepted DirectIM.\n"); dim = oscar_direct_im_find(od, d->sn); if (dim && dim->connected) { destroy_direct_im_request(d); /* 40 */ /* what does that 40 mean? */ gaim_debug_info("oscar", "Wait, we're already connected, ignoring DirectIM.\n"); return; } dim = g_new0(struct oscar_direct_im, 1); dim->gc = d->gc; dim->donttryagain = d->donttryagain; g_snprintf(dim->name, sizeof dim->name, "%s", d->sn); dim->conn = aim_odc_connect(od->sess, d->sn, NULL, d->cookie); od->direct_ims = g_slist_append(od->direct_ims, dim); if (!dim->conn) { oscar_direct_im_disconnect(od, dim); destroy_direct_im_request(d); return; } aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_odc_incoming, 0); aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_odc_typing, 0); aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER, gaim_odc_update_ui, 0); gaim_debug_info("oscar", "ip is %s.\n", d->ip); for (i = 0; i < (int)strlen(d->ip); i++) { if (d->ip[i] == ':') { port = atoi(&(d->ip[i+1])); break; } } host = g_strndup(d->ip, i); dim->conn->status |= AIM_CONN_STATUS_INPROGRESS; dim->gpc_pend = TRUE; rc = gaim_proxy_connect(gc->account, host, port, oscar_odc_callback, dim); conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, d->sn); tmp = g_strdup_printf(_("Attempting to connect to %s at %s:%hu for Direct IM."), d->sn, host, port); gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL)); g_free(tmp); g_free(host); if (rc < 0) { dim->gpc_pend = FALSE; oscar_direct_im_disconnect(od, dim); destroy_direct_im_request(d); return; } destroy_direct_im_request(d); return;}/* * We have just established a socket with the other dude, so set up some handlers. */static int gaim_odc_initiate(aim_session_t *sess, aim_frame_t *fr, ...) { GaimConnection *gc = sess->aux_data; OscarData *od = (OscarData *)gc->proto_data; GaimConversation *conv; struct oscar_direct_im *dim; char buf[256]; char *sn; va_list ap; aim_conn_t *newconn, *listenerconn; va_start(ap, fr); newconn = va_arg(ap, aim_conn_t *); listenerconn = va_arg(ap, aim_conn_t *); va_end(ap); aim_conn_close(listenerconn); aim_conn_kill(sess, &listenerconn); sn = g_strdup(aim_odc_getsn(newconn)); gaim_debug_info("oscar", "DirectIM: initiate success to %s\n", sn); dim = oscar_direct_im_find(od, sn); conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, sn); gaim_input_remove(dim->watcher); dim->conn = newconn; dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); dim->connected = TRUE; g_snprintf(buf, sizeof buf, _("Direct IM with %s established"), sn); g_free(sn); gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_SYSTEM, time(NULL)); aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_odc_incoming, 0); aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_odc_typing, 0); aim_conn_addhandler(sess, newconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_IMAGETRANSFER, gaim_odc_update_ui, 0); return 1;}/* * This is called when each chunk of an image is received. It can be used to * update a progress bar, or to eat lots of dry cat food. Wet cat food is * nasty, you sicko. */static int gaim_odc_update_ui(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *sn; double percent; GaimConnection *gc = sess->aux_data; OscarData *od = (OscarData *)gc->proto_data; GaimConversation *c; struct oscar_direct_im *dim; va_start(ap, fr); sn = va_arg(ap, char *); percent = va_arg(ap, double); va_end(ap); if (!sn || !(dim = oscar_direct_im_find(od, sn))) return 1; if (dim->watcher) { gaim_input_remove(dim->watcher); /* Otherwise, the callback will callback */ /* The callback will callback? I don't get how that would happen here. */ dim->watcher = 0; } c = gaim_find_conversation_with_account(sn, gaim_connection_get_account(gc)); if (c != NULL) gaim_conversation_update_progress(c, percent); dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); return 1;}/* * This is called after a direct IM has been received in its entirety. This * function is passed a long chunk of data which contains the IM with any * data chunks (images) appended to it. * * This function rips out all the data chunks and creates an imgstore for * each one. In order to do this, it first goes through the IM and takes * out all the IMG tags. When doing so, it rewrites the original IMG tag * with one compatible with the imgstore Gaim core code. For each one, we * then read in chunks of data from the end of the message and actually * create the img store using the given data. * * For somewhat easy reference, here's a sample message * (without the whitespace and asterisks): * * <HTML><BODY BGCOLOR="#ffffff"> * <FONT LANG="0"> * This is a really stupid picture:<BR> * <IMG SRC="Sample.jpg" ID="1" WIDTH="283" HEIGHT="212" DATASIZE="9894"><BR> * Yeah it is<BR> * Here is another one:<BR> * <IMG SRC="Soap Bubbles.bmp" ID="2" WIDTH="256" HEIGHT="256" DATASIZE="65978"> * </FONT> * </BODY></HTML> * <BINARY> * <DATA ID="1" SIZE="9894">datadatadatadata</DATA> * <DATA ID="2" SIZE="65978">datadatadatadata</DATA> * </BINARY> */static int gaim_odc_incoming(aim_session_t *sess, aim_frame_t *fr, ...) { GaimConnection *gc = sess->aux_data; GaimConvImFlags imflags = 0; gchar *utf8; GString *newmsg = g_string_new(""); GSList *images = NULL; va_list ap; const char *sn, *msg, *msgend, *binary; size_t len; int encoding, isawaymsg; va_start(ap, fr); sn = va_arg(ap, const char *); msg = va_arg(ap, const char *); len = va_arg(ap, size_t); encoding = va_arg(ap, int); isawaymsg = va_arg(ap, int); va_end(ap); msgend = msg + len; gaim_debug_info("oscar", "Got DirectIM message from %s\n", sn); if (isawaymsg) imflags |= GAIM_CONV_IM_AUTO_RESP; /* message has a binary trailer */ if ((binary = gaim_strcasestr(msg, "<binary>"))) { GData *attribs; const char *tmp, *start, *end, *last = NULL; tmp = msg; /* for each valid image tag... */ while (gaim_markup_find_tag("img", tmp, &start, &end, &attribs)) { const char *id, *src, *datasize; const char *tag = NULL, *data = NULL; size_t size; int imgid = 0; /* update the location of the last img tag */ last = end; /* grab attributes */ id = g_datalist_get_data(&attribs, "id"); src = g_datalist_get_data(&attribs, "src"); datasize = g_datalist_get_data(&attribs, "datasize"); /* if we have id & datasize, build the data tag */ if (id && datasize) tag = g_strdup_printf("<data id=\"%s\" size=\"%s\">", id, datasize); /* if we have a tag, find the start of the data */ if (tag && (data = gaim_strcasestr(binary, tag))) data += strlen(tag); /* check the data is here and store it */ if (data + (size = atoi(datasize)) <= msgend) imgid = gaim_imgstore_add(data, size, src); /* * XXX - The code below contains some calls to oscar_encoding_to_utf8 * The hardcoded "us-ascii" value REALLY needs to be removed. */ /* if we have a stored image... */ if (imgid) { /* append the message up to the tag */ utf8 = oscar_encoding_to_utf8("us-ascii", tmp, start - tmp); if (utf8 != NULL) { newmsg = g_string_append(newmsg, utf8); g_free(utf8); } /* write the new image tag */ g_string_append_printf(newmsg, "<IMG ID=\"%d\">", imgid); /* and record the image number */ images = g_slist_append(images, GINT_TO_POINTER(imgid)); } else { /* otherwise, copy up to the end of the tag */ utf8 = oscar_encoding_to_utf8("us-ascii", tmp, (end + 1) - tmp); if (utf8 != NULL) { newmsg = g_string_append(newmsg, utf8); g_free(utf8); } } /* clear the attribute list */ g_datalist_clear(&attribs); /* continue from the end of the tag */ tmp = end + 1; } /* append any remaining message data (without the > :-) */ if (last++ && (last < binary)) newmsg = g_string_append_len(newmsg, last, binary - last); /* set the flag if we caught any images */ if (images) imflags |= GAIM_CONV_IM_IMAGES; } else { g_string_append_len(newmsg, msg, len); } /* XXX - I imagine Paco-Paco will want to do some voodoo with the encoding here */ serv_got_im(gc, sn, newmsg->str, imflags, time(NULL)); /* free up the message */ g_string_free(newmsg, TRUE); /* unref any images we allocated */ if (images) { GSList *tmp; int id; for (tmp = images; tmp != NULL; tmp = tmp->next) { id = GPOINTER_TO_INT(tmp->data); gaim_imgstore_unref(id); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -