📄 oscar.c
字号:
g_slist_free(images); } return 1;}static int gaim_odc_typing(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *sn; int typing; GaimConnection *gc = sess->aux_data; va_start(ap, fr); sn = va_arg(ap, char *); typing = va_arg(ap, int); va_end(ap); if (typing == 0x0002) { /* I had to leave this. It's just too funny. It reminds me of my sister. */ gaim_debug_info("oscar", "ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn); serv_got_typing(gc, sn, 0, GAIM_TYPING); } else if (typing == 0x0001) serv_got_typing(gc, sn, 0, GAIM_TYPED); else serv_got_typing_stopped(gc, sn); return 1;}static int gaim_odc_send_im(aim_session_t *sess, aim_conn_t *conn, const char *message, GaimConvImFlags imflags) { char *buf; size_t len; int ret; GString *msg = g_string_new("<HTML><BODY>"); GString *data = g_string_new("</BODY></HTML><BINARY>"); GData *attribs; const char *start, *end, *last; int oscar_id = 0; last = message; /* for each valid IMG tag... */ while (last && *last && gaim_markup_find_tag("img", last, &start, &end, &attribs)) { GaimStoredImage *image = NULL; const char *id; if (start - last) { g_string_append_len(msg, last, start - last); } id = g_datalist_get_data(&attribs, "id"); /* ... if it refers to a valid gaim image ... */ if (id && (image = gaim_imgstore_get(atoi(id)))) { /* ... append the message from start to the tag ... */ unsigned long size = gaim_imgstore_get_size(image); const char *filename = gaim_imgstore_get_filename(image); gpointer imgdata = gaim_imgstore_get_data(image); oscar_id++; /* ... insert a new img tag with the oscar id ... */ if (filename) g_string_append_printf(msg, "<IMG SRC=\"%s\" ID=\"%d\" DATASIZE=\"%lu\">", filename, oscar_id, size); else g_string_append_printf(msg, "<IMG ID=\"%d\" DATASIZE=\"%lu\">", oscar_id, size); /* ... and append the data to the binary section ... */ g_string_append_printf(data, "<DATA ID=\"%d\" SIZE=\"%lu\">", oscar_id, size); data = g_string_append_len(data, imgdata, size); data = g_string_append(data, "</DATA>"); } /* If the tag is invalid, skip it, thus no else here */ g_datalist_clear(&attribs); /* continue from the end of the tag */ last = end + 1; } /* append any remaining message data (without the > :-) */ if (last && *last) msg = g_string_append(msg, last); /* if we inserted any images in the binary section, append it */ if (oscar_id) { msg = g_string_append_len(msg, data->str, data->len); msg = g_string_append(msg, "</BINARY>"); } len = msg->len; buf = msg->str; g_string_free(msg, FALSE); g_string_free(data, TRUE); /* XXX - The last parameter below is the encoding. Let Paco-Paco do something with it. */ if (imflags & GAIM_CONV_IM_AUTO_RESP) ret = aim_odc_send_im(sess, conn, buf, len, 0, 1); else ret = aim_odc_send_im(sess, conn, buf, len, 0, 0); g_free(buf); return ret;}struct ask_do_dir_im { char *who; GaimConnection *gc;};static void oscar_cancel_direct_im(struct ask_do_dir_im *data) { g_free(data->who); g_free(data);}/* this function is used to initiate a direct im session with someone. * we start listening on a port and send a request. they either connect * or send some kind of reply. If they can't connect, they ask us to * connect to them, and so we do that. * * this function will also get called if the other side initiate's a direct * im and we try to connect and fail. in that case cookie will not be null. * * note that cookie is an 8 byte string that isn't NULL terminated */static void oscar_direct_im_initiate(GaimConnection *gc, const char *who, const char *cookie) { OscarData *od; struct oscar_direct_im *dim; int listenfd; const char *ip; od = (OscarData *)gc->proto_data; dim = oscar_direct_im_find(od, who); if (dim) { if (!(dim->connected)) { /* We'll free the old, unconnected dim, and start over */ oscar_direct_im_disconnect(od, dim); gaim_debug_info("oscar", "Gave up on old direct IM, trying again\n"); } else { gaim_notify_error(gc, NULL, "DirectIM already open.", NULL); return; } } dim = g_new0(struct oscar_direct_im, 1); dim->gc = gc; g_snprintf(dim->name, sizeof dim->name, "%s", who); listenfd = gaim_network_listen_range(5190, 5199); ip = gaim_network_get_my_ip(od->conn ? od->conn->fd : -1); if (listenfd >= 0) dim->conn = aim_odc_initiate(od->sess, who, listenfd, gaim_network_ip_atoi(ip), gaim_network_get_port_from_fd(listenfd), cookie); if (dim->conn != NULL) { char *tmp; GaimConversation *conv; od->direct_ims = g_slist_append(od->direct_ims, dim); dim->watcher = gaim_input_add(dim->conn->fd, GAIM_INPUT_READ, oscar_callback, dim->conn); aim_conn_addhandler(od->sess, dim->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIM_ESTABLISHED, gaim_odc_initiate, 0); conv = gaim_conversation_new(GAIM_CONV_IM, dim->gc->account, who); tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for Direct IM."), who, ip, gaim_network_get_port_from_fd(listenfd)); gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL)); g_free(tmp); } else { gaim_notify_error(gc, NULL, _("Unable to open Direct IM"), NULL); oscar_direct_im_destroy(od, dim); }}static void oscar_direct_im(struct ask_do_dir_im *data) { GaimConnection *gc = data->gc; if (!g_list_find(gaim_connections_get_all(), gc)) { g_free(data->who); g_free(data); return; } oscar_direct_im_initiate(gc, data->who, NULL); g_free(data->who); g_free(data);}/* this is the right click menu cb thingy */static void oscar_ask_direct_im(GaimBlistNode *node, gpointer ignored) { GaimBuddy *buddy; GaimConnection *gc; gchar *buf; struct ask_do_dir_im *data; g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); buddy = (GaimBuddy *) node; gc = gaim_account_get_connection(buddy->account); data = g_new0(struct ask_do_dir_im, 1); data->who = g_strdup(buddy->name); data->gc = gc; buf = g_strdup_printf(_("You have selected to open a Direct IM connection with %s."), buddy->name); gaim_request_action(gc, NULL, buf, _("Because this reveals your IP address, it " "may be considered a privacy risk. Do you " "wish to continue?"), 0, data, 2, _("Connect"), G_CALLBACK(oscar_direct_im), _("Cancel"), G_CALLBACK(oscar_cancel_direct_im)); g_free(buf);}/***************************************************************************** * End scary direct im stuff *****************************************************************************/static void oscar_callback(gpointer data, gint source, GaimInputCondition condition) { aim_conn_t *conn = (aim_conn_t *)data; aim_session_t *sess = aim_conn_getsess(conn); GaimConnection *gc = sess ? sess->aux_data : NULL; OscarData *od; if (!gc) { gaim_debug_info("oscar", "oscar callback for closed connection (1).\n"); return; } od = (OscarData *)gc->proto_data; if (!g_list_find(gaim_connections_get_all(), gc)) { /* oh boy. this is probably bad. i guess the only thing we * can really do is return? */ gaim_debug_info("oscar", "oscar callback for closed connection (2).\n"); gaim_debug_misc("oscar", "gc = %p\n", gc); return; } if (condition & GAIM_INPUT_READ) { if (conn->type == AIM_CONN_TYPE_LISTENER) { gaim_debug_info("oscar", "got information on rendezvous listener\n"); if (aim_handlerendconnect(od->sess, conn) < 0) { gaim_debug_error("oscar", "connection error (rendezvous listener)\n"); aim_conn_kill(od->sess, &conn); /* AAA - Don't we need to gaim_xfer_cancel here? --marv */ } } else { if (aim_get_command(od->sess, conn) >= 0) { aim_rxdispatch(od->sess); if (od->killme) { gaim_debug_error("oscar", "Waiting to be destroyed\n"); return; } } else { if ((conn->type == AIM_CONN_TYPE_BOS) || !(aim_getconn_type(od->sess, AIM_CONN_TYPE_BOS))) { gaim_debug_error("oscar", "major connection error\n"); gaim_connection_error(gc, _("Disconnected.")); } else if (conn->type == AIM_CONN_TYPE_CHAT) { struct chat_connection *c = find_oscar_chat_by_conn(gc, conn); GaimConversation *conv = gaim_find_chat(gc, c->id); char *buf; gaim_debug_info("oscar", "disconnected from chat room %s\n", c->name); c->conn = NULL; if (c->inpa > 0) gaim_input_remove(c->inpa); c->inpa = 0; c->fd = -1; aim_conn_kill(od->sess, &conn); buf = g_strdup_printf(_("You have been disconnected from chat room %s."), c->name); if (conv) gaim_conversation_write(conv, NULL, buf, GAIM_MESSAGE_ERROR, time(NULL)); else gaim_notify_error(gc, NULL, buf, NULL); g_free(buf); } else if (conn->type == AIM_CONN_TYPE_CHATNAV) { if (od->cnpa > 0) gaim_input_remove(od->cnpa); od->cnpa = 0; gaim_debug_info("oscar", "removing chatnav input watcher\n"); while (od->create_rooms) { struct create_room *cr = od->create_rooms->data; g_free(cr->name); od->create_rooms = g_slist_remove(od->create_rooms, cr); g_free(cr); gaim_notify_error(gc, NULL, _("Chat is currently unavailable"), NULL); } aim_conn_kill(od->sess, &conn); } else if (conn->type == AIM_CONN_TYPE_AUTH) { if (od->paspa > 0) gaim_input_remove(od->paspa); od->paspa = 0; gaim_debug_info("oscar", "removing authconn input watcher\n"); aim_conn_kill(od->sess, &conn); } else if (conn->type == AIM_CONN_TYPE_EMAIL) { if (od->emlpa > 0) gaim_input_remove(od->emlpa); od->emlpa = 0; gaim_debug_info("oscar", "removing email input watcher\n"); aim_conn_kill(od->sess, &conn); } else if (conn->type == AIM_CONN_TYPE_ICON) { if (od->icopa > 0) gaim_input_remove(od->icopa); od->icopa = 0; gaim_debug_info("oscar", "removing icon input watcher\n"); aim_conn_kill(od->sess, &conn); } else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) { if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) gaim_odc_disconnect(od->sess, conn); aim_conn_kill(od->sess, &conn); } else { gaim_debug_error("oscar", "holy crap! generic connection error! %hu\n", conn->type); aim_conn_kill(od->sess, &conn); } } } }}static void oscar_debug(aim_session_t *sess, int level, const char *format, va_list va) { GaimConnection *gc = sess->aux_data; gchar *s = g_strdup_vprintf(format, va); gchar *buf; buf = g_strdup_printf("%s %d: %s", gaim_account_get_username(gaim_connection_get_account(gc)), level, s); gaim_debug_info("oscar", buf); if (buf[strlen(buf)-1] != '\n') gaim_debug_info(NULL, "\n"); g_free(buf); g_free(s);}static void oscar_login_connect(gpointer data, gint source, GaimInputCondition cond){ GaimConnection *gc = data; OscarData *od; aim_session_t *sess; aim_conn_t *conn; if (!g_list_find(gaim_connections_get_all(), gc)) { close(source); return; } od = gc->proto_data; sess = od->sess; conn = aim_getconn_type_all(sess, AIM_CONN_TYPE_AUTH); conn->fd = source; if (source < 0) { gaim_connection_error(gc, _("Couldn't connect to host")); return; } aim_conn_completeconnect(sess, conn); gc->inpa = gaim_input_add(conn->fd, GAIM_INPUT_READ, oscar_callback, conn); aim_request_login(sess, conn, gaim_account_get_username(gaim_connection_get_account(gc))); gaim_debug_info("oscar", "Screen name sent, waiting for response\n"); gaim_connection_update_progress(gc, _("Screen name sent"), 1, OSCAR_CONNECT_STEPS); ck[1] = 0x65;}static void oscar_login(GaimAccount *account) { aim_session_t *sess; aim_conn_t *conn; GaimConnection *gc = gaim_account_get_connection(account); OscarData *od = gc->proto_data = g_new0(OscarData, 1); gaim_debug_misc("oscar", "oscar_login: gc = %p\n", gc); if (!aim_snvalid(gaim_account_get_username(account))) { gchar *buf; buf = g_strdup_printf(_("Unable to login: Could not sign on as %s because the screen name is invalid. Screen names must either start with a letter and contain only letters, numbers and spaces, or contain only numbers."), gaim_account_get_username(account)); gaim_connection_error(gc, buf); g_free(buf); } if (isdigit(*(gaim_account_get_username(account)))) { od->icq = TRUE; } else { gc->flags |= GAIM_CONNECTION_HTML; gc->flags |= GAIM_CONNECTION_AUTO_RESP; } od->buddyinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, oscar_free_buddyinfo); sess = g_new0(aim_session_t, 1); aim_session_init(sess, TRUE, 0); aim_setdebuggingcb(sess, oscar_debug); /* * We need an immediate queue because we don't use a while-loop * to see if things need to be sent. */ aim_tx_setenqueue(sess, AIM_TX_IMMEDIATE, NULL); od->sess = sess; sess->aux_data = gc; conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, NULL); if (conn == NULL) { gaim_debug_error("oscar", "internal connection error\n"); gaim_connection_error(gc, _("Unable to login to AIM")); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -