📄 oscar.c
字号:
aim_conn_addhandler(sess, conn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_connerr, 0); aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0); aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0); conn->status |= AIM_CONN_STATUS_INPROGRESS; if (gaim_proxy_connect(account, gaim_account_get_string(account, "server", FAIM_LOGIN_SERVER), gaim_account_get_int(account, "port", FAIM_LOGIN_PORT), oscar_login_connect, gc) < 0) { gaim_connection_error(gc, _("Couldn't connect to host")); return; } gaim_connection_update_progress(gc, _("Connecting"), 0, OSCAR_CONNECT_STEPS); ck[0] = 0x5a;}static void oscar_close(GaimConnection *gc) { OscarData *od = (OscarData *)gc->proto_data; while (od->oscar_chats) { struct chat_connection *n = od->oscar_chats->data; if (n->inpa > 0) gaim_input_remove(n->inpa); g_free(n->name); g_free(n->show); od->oscar_chats = g_slist_remove(od->oscar_chats, n); g_free(n); } while (od->direct_ims) { struct oscar_direct_im *n = od->direct_ims->data; oscar_direct_im_destroy(od, n); }/* BBB */ while (od->file_transfers) { GaimXfer *xfer; xfer = (GaimXfer *)od->file_transfers->data; gaim_xfer_cancel_local(xfer); } while (od->requesticon) { char *sn = od->requesticon->data; od->requesticon = g_slist_remove(od->requesticon, sn); free(sn); } g_hash_table_destroy(od->buddyinfo); 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); } if (od->email) g_free(od->email); if (od->newp) g_free(od->newp); if (od->oldp) g_free(od->oldp); if (gc->inpa > 0) gaim_input_remove(gc->inpa); if (od->cnpa > 0) gaim_input_remove(od->cnpa); if (od->paspa > 0) gaim_input_remove(od->paspa); if (od->emlpa > 0) gaim_input_remove(od->emlpa); if (od->icopa > 0) gaim_input_remove(od->icopa); if (od->icontimer > 0) gaim_timeout_remove(od->icontimer); if (od->getblisttimer > 0) gaim_timeout_remove(od->getblisttimer); if (od->getinfotimer > 0) gaim_timeout_remove(od->getinfotimer); aim_session_kill(od->sess); g_free(od->sess); od->sess = NULL; g_free(gc->proto_data); gc->proto_data = NULL; gaim_debug_info("oscar", "Signed off.\n");}static void oscar_bos_connect(gpointer data, gint source, GaimInputCondition cond) { GaimConnection *gc = data; OscarData *od; aim_session_t *sess; aim_conn_t *bosconn; if (!g_list_find(gaim_connections_get_all(), gc)) { close(source); return; } od = gc->proto_data; sess = od->sess; bosconn = od->conn; bosconn->fd = source; if (source < 0) { gaim_connection_error(gc, _("Could Not Connect")); return; } aim_conn_completeconnect(sess, bosconn); gc->inpa = gaim_input_add(bosconn->fd, GAIM_INPUT_READ, oscar_callback, bosconn); gaim_connection_update_progress(gc, _("Connection established, cookie sent"), 4, OSCAR_CONNECT_STEPS); ck[4] = 0x61;}/* BBB *//* * This little area in oscar.c is the nexus of file transfer code, * so I wrote a little explanation of what happens. I am such a * ninja. * * The series of events for a file send is: * -Create xfer and call gaim_xfer_request (this happens in oscar_ask_sendfile) * -User chooses a file and oscar_xfer_init is called. It establishes a * listening socket, then asks the remote user to connect to us (and * gives them the file name, port, IP, etc.) * -They connect to us and we send them an AIM_CB_OFT_PROMPT (this happens * in oscar_sendfile_estblsh) * -They send us an AIM_CB_OFT_ACK and then we start sending data * -When we finish, they send us an AIM_CB_OFT_DONE and they close the * connection. * -We get drunk because file transfer kicks ass. * * The series of events for a file receive is: * -Create xfer and call gaim_xfer request (this happens in incomingim_chan2) * -Gaim user selects file to name and location to save file to and * oscar_xfer_init is called * -It connects to the remote user using the IP they gave us earlier * -After connecting, they send us an AIM_CB_OFT_PROMPT. In reply, we send * them an AIM_CB_OFT_ACK. * -They begin to send us lots of raw data. * -When they finish sending data we send an AIM_CB_OFT_DONE and then close * the connection. */static void oscar_sendfile_connected(gpointer data, gint source, GaimInputCondition condition);/* * Miscellaneous xfer functions */static GaimXfer *oscar_find_xfer_by_cookie(GSList *fts, const fu8_t *ck){ GaimXfer *xfer; struct aim_oft_info *oft_info; while (fts) { xfer = fts->data; oft_info = xfer->data; if (oft_info && !memcmp(ck, oft_info->cookie, 8)) return xfer; fts = g_slist_next(fts); } return NULL;}static GaimXfer *oscar_find_xfer_by_conn(GSList *fts, aim_conn_t *conn){ GaimXfer *xfer; struct aim_oft_info *oft_info; while (fts) { xfer = fts->data; oft_info = xfer->data; if (oft_info && (conn == oft_info->conn)) return xfer; fts = g_slist_next(fts); } return NULL;}static void oscar_xfer_end(GaimXfer *xfer){ struct aim_oft_info *oft_info = xfer->data; GaimConnection *gc = oft_info->sess->aux_data; OscarData *od = gc->proto_data; gaim_debug_info("oscar", "AAA - in oscar_xfer_end\n"); if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) { oft_info->fh.nrecvd = gaim_xfer_get_bytes_sent(xfer); aim_oft_sendheader(oft_info->sess, AIM_CB_OFT_DONE, oft_info); } aim_conn_kill(oft_info->sess, &oft_info->conn); aim_oft_destroyinfo(oft_info); xfer->data = NULL; od->file_transfers = g_slist_remove(od->file_transfers, xfer);}/* * xfer functions used when receiving files */static void oscar_xfer_init_recv(GaimXfer *xfer){ struct aim_oft_info *oft_info = xfer->data; GaimConnection *gc = oft_info->sess->aux_data; OscarData *od = gc->proto_data; gaim_debug_info("oscar", "AAA - in oscar_xfer_recv_init\n"); oft_info->conn = aim_newconn(od->sess, AIM_CONN_TYPE_RENDEZVOUS, NULL); if (oft_info->conn) { oft_info->conn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_PROMPT, oscar_sendfile_prompt, 0); oft_info->conn->fd = xfer->fd = gaim_proxy_connect(gaim_connection_get_account(gc), xfer->remote_ip, xfer->remote_port, oscar_sendfile_connected, xfer); if (xfer->fd == -1) { gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to establish file descriptor.")); gaim_xfer_cancel_local(xfer); } } else { gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to create new connection.")); gaim_xfer_cancel_local(xfer); /* Try a different port? Ask them to connect to us? /join #gaim and whine? */ }}static void oscar_xfer_cancel_recv(GaimXfer *xfer){ struct aim_oft_info *oft_info = xfer->data; GaimConnection *gc = oft_info->sess->aux_data; OscarData *od = gc->proto_data; gaim_debug_info("oscar", "AAA - in oscar_xfer_cancel_recv\n"); if (gaim_xfer_get_status(xfer) != GAIM_XFER_STATUS_CANCEL_REMOTE) aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info); aim_conn_kill(oft_info->sess, &oft_info->conn); aim_oft_destroyinfo(oft_info); xfer->data = NULL; od->file_transfers = g_slist_remove(od->file_transfers, xfer);}static void oscar_xfer_ack_recv(GaimXfer *xfer, const char *buffer, size_t size){ struct aim_oft_info *oft_info = xfer->data; /* Update our rolling checksum. Like Walmart, yo. */ oft_info->fh.recvcsum = aim_oft_checksum_chunk(buffer, size, oft_info->fh.recvcsum);}/* * xfer functions used when sending files */static void oscar_xfer_init_send(GaimXfer *xfer){ struct aim_oft_info *oft_info = xfer->data; GaimConnection *gc = oft_info->sess->aux_data; OscarData *od = gc->proto_data; int listenfd; gaim_debug_info("oscar", "AAA - in oscar_xfer_send_init\n"); xfer->filename = g_path_get_basename(xfer->local_filename); strncpy(oft_info->fh.name, xfer->filename, 64); oft_info->fh.name[63] = '\0'; oft_info->fh.totsize = gaim_xfer_get_size(xfer); oft_info->fh.size = gaim_xfer_get_size(xfer); oft_info->fh.checksum = aim_oft_checksum_file(xfer->local_filename); /* Create a listening socket and an associated libfaim conn */ if ((listenfd = gaim_network_listen_range(5190, 5199)) < 0) { gaim_xfer_cancel_local(xfer); return; } xfer->local_port = gaim_network_get_port_from_fd(listenfd); oft_info->port = xfer->local_port; if (aim_sendfile_listen(od->sess, oft_info, listenfd) != 0) { gaim_xfer_cancel_local(xfer); return; } gaim_debug_misc("oscar", "port is %hu, ip is %s\n", xfer->local_port, oft_info->clientip); if (oft_info->conn) { xfer->watcher = gaim_input_add(oft_info->conn->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn); aim_im_sendch2_sendfile_ask(od->sess, oft_info); aim_conn_addhandler(od->sess, oft_info->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_ESTABLISHED, oscar_sendfile_estblsh, 0); } else { gaim_xfer_error(GAIM_XFER_SEND, xfer->who, _("Unable to establish listener socket.")); gaim_xfer_cancel_local(xfer); }}static void oscar_xfer_cancel_send(GaimXfer *xfer){ struct aim_oft_info *oft_info = xfer->data; GaimConnection *gc = oft_info->sess->aux_data; OscarData *od = gc->proto_data; gaim_debug_info("oscar", "AAA - in oscar_xfer_cancel_send\n"); if (gaim_xfer_get_status(xfer) != GAIM_XFER_STATUS_CANCEL_REMOTE) aim_im_sendch2_sendfile_cancel(oft_info->sess, oft_info); aim_conn_kill(oft_info->sess, &oft_info->conn); aim_oft_destroyinfo(oft_info); xfer->data = NULL; od->file_transfers = g_slist_remove(od->file_transfers, xfer);}static void oscar_xfer_ack_send(GaimXfer *xfer, const char *buffer, size_t size){ struct aim_oft_info *oft_info = xfer->data; /* I'm not sure I like how we do this. --marv * I do. AIM file transfers aren't really meant to be thought * of as a transferring just a single file. The rendezvous * establishes a connection between two computers, and then * those computers can use the same connection for transferring * multiple files. So we don't want the Gaim core up and closing * the socket all willy-nilly. We want to do that in the oscar * prpl, whenever one side or the other says they're finished * using the connection. There might be a better way to intercept * the socket from the core, however... --KingAnt */ /* * If we're done sending, intercept the socket from the core ft code * and wait for the other guy to send the "done" OFT packet. */ if (gaim_xfer_get_bytes_remaining(xfer) <= 0) { gaim_input_remove(xfer->watcher); xfer->watcher = gaim_input_add(xfer->fd, GAIM_INPUT_READ, oscar_callback, oft_info->conn); xfer->fd = 0; gaim_xfer_set_completed(xfer, TRUE); }}static gboolean oscar_can_receive_file(GaimConnection *gc, const char *who) { gboolean can_receive = FALSE; OscarData *od = gc->proto_data; if (!od->icq) { aim_userinfo_t *userinfo; userinfo = aim_locate_finduserinfo(od->sess, who); if (userinfo && userinfo->capabilities & AIM_CAPS_SENDFILE) can_receive = TRUE; } return can_receive;}static void oscar_send_file(GaimConnection *gc, const char *who, const char *file) { OscarData *od; GaimXfer *xfer; struct aim_oft_info *oft_info; const char *ip; od = (OscarData *)gc->proto_data; /* You want to send a file to someone else, you're so generous */ /* Build the file transfer handle */ xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); /* Create the oscar-specific data */ ip = gaim_network_get_my_ip(od->conn ? od->conn->fd : -1); oft_info = aim_oft_createinfo(od->sess, NULL, who, ip, 0, 0, 0, NULL); xfer->data = oft_info; /* Setup our I/O op functions */ gaim_xfer_set_init_fnc(xfer, oscar_xfer_init_send); gaim_xfer_set_end_fnc(xfer, oscar_xfer_end); gaim_xfer_set_cancel_send_fnc(xfer, oscar_xfer_cancel_send); gaim_xfer_set_request_denied_fnc(xfer, oscar_xfer_cancel_send); gaim_xfer_set_ack_fnc(xfer, oscar_xfer_ack_send); /* Keep track of this transfer for later */ od->file_transfers = g_slist_append(od->file_transfers, xfer); /* Now perform the request */ if (file) gaim_xfer_request_accepted(xfer, file); else gaim_xfer_request(xfer);}static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { GaimConnection *gc = sess->aux_data; OscarData *od = gc->proto_data; GaimAccount *account = gc->account; aim_conn_t *bosconn; char *host; int port; int i, rc; va_list ap; struct aim_authresp_info *info; port = gaim_account_get_int(account, "port", FAIM_LOGIN_PORT); va_start(ap, fr); info = va_arg(ap, struct aim_authresp_info *); va_end(ap); gaim_debug_info("oscar", "inside auth_resp (Screen name: %s)\n", info->sn); if (info->errorcode || !info->bosip || !info->cookielen || !info->cookie) { char buf[256]; switch (info->errorcode) { case 0x05: /* Incorrect nick/password */ gc->wants_to_die = TRUE; gaim_connection_error(gc, _("Incorrect nickname or password.")); break; case 0x11: /* Suspended account */ gc->wants_to_die = TRUE; gaim_connection_error(gc, _("Your account is currently suspended.")); break; case 0x14: /* service temporarily unavailable */ gaim_connection_error(gc, _("The AOL Instant Messenger service is temporaril
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -