📄 toc.c
字号:
/* * purple * * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include "internal.h"#include "account.h"#include "accountopt.h"#include "conversation.h"#include "debug.h"#include "notify.h"#include "privacy.h"#include "proxy.h"#include "prpl.h"#include "request.h"#include "util.h"#include "version.h"static PurplePlugin *my_protocol = NULL;#define REVISION "penguin"#define TYPE_SIGNON 1#define TYPE_DATA 2#define TYPE_ERROR 3#define TYPE_SIGNOFF 4#define TYPE_KEEPALIVE 5#define FLAPON "FLAPON\r\n\r\n"#define ROAST "Tic/Toc"#define TOC_HOST "toc.oscar.aol.com"#define TOC_PORT 9898#define AUTH_HOST "login.oscar.aol.com"#define AUTH_PORT 5190#define LANGUAGE "english"#define STATE_OFFLINE 0#define STATE_FLAPON 1#define STATE_SIGNON_REQUEST 2#define STATE_ONLINE 3#define STATE_PAUSE 4#define VOICE_UID "09461341-4C7F-11D1-8222-444553540000"#define FILE_SEND_UID "09461343-4C7F-11D1-8222-444553540000"#define IMAGE_UID "09461345-4C7F-11D1-8222-444553540000"#define B_ICON_UID "09461346-4C7F-11D1-8222-444553540000"#define STOCKS_UID "09461347-4C7F-11D1-8222-444553540000"#define FILE_GET_UID "09461348-4C7F-11D1-8222-444553540000"#define GAMES_UID "0946134a-4C7F-11D1-8222-444553540000"#define UC_UNAVAILABLE 0x01#define UC_AOL 0x02#define UC_ADMIN 0x04#define UC_UNCONFIRMED 0x08#define UC_NORMAL 0x10#define UC_WIRELESS 0x20struct ft_request { PurpleConnection *gc; char *user; char UID[2048]; char *cookie; char *ip; int port; char *message; char *filename; int files; int size;};struct buddy_icon { guint32 hash; guint32 len; time_t time; void *data;};struct toc_data { int toc_fd; char toc_ip[20]; int seqno; int state;};struct sflap_hdr { unsigned char ast; unsigned char type; unsigned short seqno; unsigned short len;};struct signon { unsigned int ver; unsigned short tag; unsigned short namelen; char username[80];};/* constants to identify proto_opts */#define USEROPT_AUTH 0#define USEROPT_AUTHPORT 1#define TOC_CONNECT_STEPS 3static void toc_login_callback(gpointer, gint, PurpleInputCondition);static void toc_callback(gpointer, gint, PurpleInputCondition);/* ok. this function used to take username/password, and return 0 on success. * now, it takes username/password, and returns NULL on error or a new purple_connection * on success. */static void toc_login(PurpleAccount *account){ PurpleConnection *gc; struct toc_data *tdt; char buf[80]; gc = purple_account_get_connection(account); gc->proto_data = tdt = g_new0(struct toc_data, 1); gc->flags |= PURPLE_CONNECTION_HTML; gc->flags |= PURPLE_CONNECTION_AUTO_RESP; g_snprintf(buf, sizeof buf, _("Looking up %s"), purple_account_get_string(account, "server", TOC_HOST)); purple_connection_update_progress(gc, buf, 0, TOC_CONNECT_STEPS); purple_debug(PURPLE_DEBUG_INFO, "toc", "Client connects to TOC\n"); if (purple_proxy_connect(gc, account, purple_account_get_string(account, "server", TOC_HOST), purple_account_get_int(account, "port", TOC_PORT), toc_login_callback, gc) != 0 || !account->gc) { g_snprintf(buf, sizeof(buf), _("Connect to %s failed"), purple_account_get_string(account, "server", TOC_HOST)); purple_connection_error(gc, buf); return; }}static void toc_login_callback(gpointer data, gint source, PurpleInputCondition cond){ PurpleConnection *gc = data; struct toc_data *tdt; char buf[80]; struct sockaddr_in name; socklen_t namelen; if (!PURPLE_CONNECTION_IS_VALID(gc)) { if (source >= 0) close(source); return; } tdt = gc->proto_data; if (source == -1) { /* we didn't successfully connect. tdt->toc_fd is valid here */ purple_connection_error(gc, _("Unable to connect.")); return; } tdt->toc_fd = source; /* * Copy the IP that we're connected to. We need this because "GOTO_URL"'s * should open on the exact server we're connected to. toc.oscar.aol.com * doesn't work because that hostname resolves to multiple IP addresses. */ if (getpeername(tdt->toc_fd, (struct sockaddr *)&name, &namelen) == 0) strncpy(tdt->toc_ip, inet_ntoa(name.sin_addr), sizeof(tdt->toc_ip)); else strncpy(tdt->toc_ip, purple_account_get_string(gc->account, "server", TOC_HOST), sizeof(tdt->toc_ip)); purple_debug(PURPLE_DEBUG_INFO, "toc", "Client sends \"FLAPON\\r\\n\\r\\n\"\n"); if (write(tdt->toc_fd, FLAPON, strlen(FLAPON)) < 0) { purple_connection_error(gc, _("Disconnected.")); return; } tdt->state = STATE_FLAPON; /* i know a lot of people like to look at purple to see how TOC works. so i'll comment * on what this does. it's really simple. when there's data ready to be read from the * toc_fd file descriptor, toc_callback is called, with gc passed as its data arg. */ gc->inpa = purple_input_add(tdt->toc_fd, PURPLE_INPUT_READ, toc_callback, gc); g_snprintf(buf, sizeof(buf), _("Signon: %s"), purple_account_get_username(gc->account)); purple_connection_update_progress(gc, buf, 1, TOC_CONNECT_STEPS);}static void toc_close(PurpleConnection *gc){ if (gc->inpa > 0) purple_input_remove(gc->inpa); gc->inpa = 0; close(((struct toc_data *)gc->proto_data)->toc_fd); g_free(gc->proto_data);}static void toc_build_config(PurpleAccount *account, char *s, int len, gboolean show){ PurpleBlistNode *gnode, *cnode, *bnode; PurpleGroup *g; PurpleBuddy *b; GSList *plist = account->permit; GSList *dlist = account->deny; int pos = 0; if (!account->perm_deny) account->perm_deny = 1; pos += g_snprintf(&s[pos], len - pos, "m %d\n", account->perm_deny); for(gnode = purple_get_blist()->root; gnode && len > pos; gnode = gnode->next) { g = (PurpleGroup *)gnode; if(!PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue; if(purple_group_on_account(g, account)) { pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name); for(cnode = gnode->child; cnode; cnode = cnode->next) { if(!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) continue; for(bnode = gnode->child; bnode && len > pos; bnode = bnode->next) { b = (PurpleBuddy *)bnode; if(!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) continue; if(b->account == account) { pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name, (show && b->alias) ? ":" : "", (show && b->alias) ? b->alias : ""); } } } } } while (len > pos && plist) { pos += g_snprintf(&s[pos], len - pos, "p %s\n", (char *)plist->data); plist = plist->next; } while (len > pos && dlist) { pos += g_snprintf(&s[pos], len - pos, "d %s\n", (char *)dlist->data); dlist = dlist->next; }}char *escape_message(const char *msg){ char *ret; int i, j; if (!msg) return NULL; /* Calculate the length after escaping */ for (i=0, j=0; msg[i]; i++) switch (msg[i]) { case '$': case '[': case ']': case '(': case ')': j++; default: j++; } /* Allocate a string */ ret = (char *)g_malloc((j+1) * sizeof(char)); /* Copy the string */ for (i=0, j=0; msg[i]; i++) switch (msg[i]) { case '$': case '[': case ']': case '(': case ')': ret[j++] = '\\'; default: ret[j++] = msg[i]; } ret[j] = '\0'; return ret;}/* * Duplicates the input string, replacing each \n with a <BR>, and * escaping a few other characters. */char *escape_text(const char *msg){ char *ret; int i, j; if (!msg) return NULL; /* Calculate the length after escaping */ for (i=0, j=0; msg[i]; i++) switch (msg[i]) { case '\n': j += 4; break; case '{': case '}': case '\\': case '"': j += 1; default: j += 1; } /* Allocate a string */ ret = (char *)malloc((j+1) * sizeof(char)); /* Copy the string */ for (i=0, j=0; msg[i]; i++) switch (msg[i]) { case '\n': ret[j++] = '<'; ret[j++] = 'B'; ret[j++] = 'R'; ret[j++] = '>'; break; case '{': case '}': case '\\': case '"': ret[j++] = '\\'; default: ret[j++] = msg[i]; } ret[j] = '\0'; return ret;}static int sflap_send(PurpleConnection *gc, const char *buf, int olen, int type){ struct toc_data *tdt = (struct toc_data *)gc->proto_data; int len; int slen = 0; int ret; struct sflap_hdr hdr; char *escaped, *obuf; if (tdt->state == STATE_PAUSE) /* TOC has given us the PAUSE message; sending could cause a disconnect * so we just return here like everything went through fine */ return 0; if (olen < 0) { escaped = escape_message(buf); len = strlen(escaped); } else { escaped = g_memdup(buf, olen); len = olen; } /* * One _last_ 2048 check here! This shouldn't ever * get hit though, hopefully. If it gets hit on an IM * It'll lose the last " and the message won't go through, * but this'll stop a segfault. */ if (len > MSG_LEN) { purple_debug(PURPLE_DEBUG_WARNING, "toc", "message too long, truncating\n"); escaped[MSG_LEN - 1] = '\0'; len = MSG_LEN; } if (olen < 0) purple_debug(PURPLE_DEBUG_INFO, "toc", "C: %s\n", escaped); hdr.ast = '*'; hdr.type = type; hdr.seqno = htons(tdt->seqno++ & 0xffff); hdr.len = htons(len + (type == TYPE_SIGNON ? 0 : 1)); obuf = (char *)malloc((sizeof(hdr)+len+1) * sizeof(char)); memcpy(obuf, &hdr, sizeof(hdr)); slen += sizeof(hdr); memcpy(&obuf[slen], escaped, len); slen += len; if (type != TYPE_SIGNON) { obuf[slen] = '\0'; slen += 1; } ret = write(tdt->toc_fd, obuf, slen); free(obuf); g_free(escaped); return ret;}static int toc_send_raw(PurpleConnection *gc, const char *buf, int len){ return sflap_send(gc, buf, len, 2);}static int wait_reply(PurpleConnection *gc, char *buffer, size_t buflen){ struct toc_data *tdt = (struct toc_data *)gc->proto_data; struct sflap_hdr *hdr; int ret; if (read(tdt->toc_fd, buffer, sizeof(struct sflap_hdr)) < 0) { purple_debug(PURPLE_DEBUG_ERROR, "toc", "Couldn't read flap header\n"); return -1; } hdr = (struct sflap_hdr *)buffer; if (buflen < ntohs(hdr->len)) { /* fake like there's a read error */ purple_debug(PURPLE_DEBUG_ERROR, "toc", "buffer too small (have %d, need %d)\n", buflen, ntohs(hdr->len)); return -1; } if (ntohs(hdr->len) > 0) { int count = 0; ret = 0; do { count += ret; ret = read(tdt->toc_fd, buffer + sizeof(struct sflap_hdr) + count, ntohs(hdr->len) - count); } while (count + ret < ntohs(hdr->len) && ret > 0); buffer[sizeof(struct sflap_hdr) + count + ret] = '\0'; return ret; } else return 0;}static unsigned char *roast_password(const char *pass){ /* Trivial "encryption" */ static unsigned char rp[256]; static char *roast = ROAST; int pos = 2; int x; strcpy(rp, "0x"); for (x = 0; (x < 150) && pass[x]; x++) pos += sprintf(&rp[pos], "%02x", pass[x] ^ roast[x % strlen(roast)]); rp[pos] = '\0'; return rp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -