00001
00024
00025
00026 #include "debug.h"
00027 #include "internal.h"
00028 #include "md5.h"
00029
00030 #ifdef _WIN32
00031 #define random rand
00032 #define srandom srand
00033 #endif
00034
00035 #include "utils.h"
00036 #include "packet_parse.h"
00037 #include "buddy_info.h"
00038 #include "buddy_opt.h"
00039 #include "group_admindlg.h"
00040 #include "group_free.h"
00041 #include "infodlg.h"
00042 #include "login_logout.h"
00043 #include "qq_proxy.h"
00044 #include "recv_core.h"
00045 #include "send_core.h"
00046 #include "sendqueue.h"
00047 #include "udp_proxy_s5.h"
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 void _qq_show_packet(gchar * desc, gchar * buf, gint len)
00063 {
00064 char buf1[4096], buf2[10];
00065 int i;
00066 buf1[0] = 0;
00067 for (i = 0; i < len; i++) {
00068 sprintf(buf2, " %02x(%d)", buf[i] & 0xff, buf[i] & 0xff);
00069 strcat(buf1, buf2);
00070 }
00071 strcat(buf1, "\n");
00072 gaim_debug(GAIM_DEBUG_INFO, desc, buf1);
00073 }
00074
00075
00076
00077 guint8 *_gen_pwkey(const gchar * pwd)
00078 {
00079 md5_state_t ctx;
00080 md5_byte_t pwkey_tmp[QQ_KEY_LENGTH];
00081
00082 md5_init(&ctx);
00083 md5_append(&ctx, pwd, strlen(pwd));
00084 md5_finish(&ctx, pwkey_tmp);
00085
00086 md5_init(&ctx);
00087 md5_append(&ctx, pwkey_tmp, QQ_KEY_LENGTH);
00088 md5_finish(&ctx, pwkey_tmp);
00089
00090 return g_memdup(pwkey_tmp, QQ_KEY_LENGTH);
00091 }
00092
00093
00094
00095 gint _qq_fill_host(struct sockaddr_in * addr, const gchar * host, guint16 port)
00096 {
00097 if (!inet_aton(host, &(addr->sin_addr))) {
00098 struct hostent *hp;
00099 if (!(hp = gethostbyname(host))) {
00100 return -1;
00101 }
00102 memset(addr, 0, sizeof(struct sockaddr_in));
00103 memcpy(&(addr->sin_addr.s_addr), hp->h_addr, hp->h_length);
00104 addr->sin_family = hp->h_addrtype;
00105 } else
00106 addr->sin_family = AF_INET;
00107
00108 addr->sin_port = htons(port);
00109 return 0;
00110 }
00111
00112
00113
00114
00115 void _qq_got_login(gpointer data, gint source, GaimInputCondition cond)
00116 {
00117 qq_data *qd;
00118 GaimConnection *gc;
00119 gchar *buf;
00120 const gchar *passwd;
00121
00122 gc = (GaimConnection *) data;
00123 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00124
00125 if (g_list_find(gaim_connections_get_all(), gc) == NULL) {
00126 close(source);
00127 return;
00128 }
00129
00130 if (source < 0) {
00131 gaim_connection_error(gc, _("Unable to connect."));
00132 return;
00133 }
00134
00135 qd = (qq_data *) gc->proto_data;
00136
00137
00138 srandom(time(NULL));
00139 qd->send_seq = random() & 0x0000ffff;
00140 qd->fd = source;
00141 qd->logged_in = FALSE;
00142 qd->channel = 1;
00143 qd->uid = strtol(gaim_account_get_username(gaim_connection_get_account(gc)), NULL, 10);
00144 qd->before_login_packets = g_queue_new();
00145
00146
00147 passwd = gaim_account_get_password(gaim_connection_get_account(gc));
00148 qd->pwkey = _gen_pwkey(passwd);
00149
00150 qd->sendqueue_timeout = gaim_timeout_add(QQ_SENDQUEUE_TIMEOUT, qq_sendqueue_timeout_callback, gc);
00151 gc->inpa = gaim_input_add(qd->fd, GAIM_INPUT_READ, qq_input_pending, gc);
00152
00153
00154 buf = g_strdup_printf("Login as %d", qd->uid);
00155 gaim_connection_update_progress(gc, buf, 1, QQ_CONNECT_STEPS);
00156 g_free(buf);
00157
00158
00159 qq_send_packet_login_token(gc);
00160 }
00161
00162
00163
00164
00165 void _qq_common_clean(GaimConnection * gc)
00166 {
00167 qq_data *qd;
00168
00169 g_return_if_fail(gc != NULL && gc->proto_data != NULL);
00170 qd = (qq_data *) gc->proto_data;
00171
00172
00173 if (qd->fd >= 0 && qd->logged_in)
00174 qq_send_packet_logout(gc);
00175 close(qd->fd);
00176
00177 if (qd->sendqueue_timeout > 0) {
00178 gaim_timeout_remove(qd->sendqueue_timeout);
00179 qd->sendqueue_timeout = 0;
00180 }
00181
00182 if (gc->inpa > 0) {
00183 gaim_input_remove(gc->inpa);
00184 gc->inpa = 0;
00185 }
00186
00187 qq_b4_packets_free(qd);
00188 qq_sendqueue_free(qd);
00189 qq_group_packets_free(qd);
00190 qq_group_free_all(qd);
00191 qq_add_buddy_request_free(qd);
00192 qq_info_query_free(qd);
00193 qq_contact_info_window_free(qd);
00194 qq_qun_info_window_free(qd);
00195 qq_buddies_list_free(qd);
00196
00197 }
00198
00199
00200 gint _qq_proxy_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
00201 {
00202 gint fd = -1;
00203
00204 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Using UDP without proxy\n");
00205 fd = socket(PF_INET, SOCK_DGRAM, 0);
00206
00207 if (fd < 0) {
00208 gaim_debug(GAIM_DEBUG_ERROR, "QQ Redirect", "Unable to create socket: %s\n", strerror(errno));
00209 return -1;
00210 }
00211
00212
00213 fcntl(fd, F_SETFL, O_NONBLOCK);
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 if (connect(fd, addr, addrlen) < 0) {
00227
00228
00229
00230
00231
00232
00233
00234
00235 if ((errno == EINPROGRESS) || (errno == EINTR))
00236 gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n");
00237 else {
00238 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Faiil connection: %d\n", strerror(errno));
00239 close(fd);
00240 return -1;
00241 }
00242 } else {
00243 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Connected.\n");
00244 fcntl(fd, F_SETFL, 0);
00245 phb->func(phb->data, fd, GAIM_INPUT_READ);
00246 }
00247
00248 return fd;
00249 }
00250
00251
00252
00253 gint _qq_udp_proxy_connect(GaimAccount * account,
00254 const gchar * server,
00255 guint16 port, void callback(gpointer, gint, GaimInputCondition), GaimConnection * gc)
00256 {
00257 struct sockaddr_in sin;
00258 struct PHB *phb;
00259 GaimProxyInfo *info;
00260 qq_data *qd;
00261
00262 g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1);
00263 qd = (qq_data *) gc->proto_data;
00264
00265 info = gaim_account_get_proxy_info(account);
00266
00267 phb = g_new0(struct PHB, 1);
00268 phb->host = g_strdup(server);
00269 phb->port = port;
00270 phb->account = account;
00271 phb->gpi = info;
00272 phb->func = callback;
00273 phb->data = gc;
00274
00275 if (_qq_fill_host(&sin, server, port) < 0) {
00276 gaim_debug(GAIM_DEBUG_ERROR, "QQ",
00277 "gethostbyname(\"%s\", %d) failed: %s\n", server, port, hstrerror(h_errno));
00278 return -1;
00279 }
00280
00281 if (info == NULL) {
00282 qd->proxy_type = GAIM_PROXY_NONE;
00283 return _qq_proxy_none(phb, (struct sockaddr *) &sin, sizeof(sin));
00284 }
00285
00286 qd->proxy_type = info->type;
00287 gaim_debug(GAIM_DEBUG_INFO, "QQ", "Choosing proxy type %d\n", info->type);
00288
00289 switch (info->type) {
00290 case GAIM_PROXY_NONE:
00291 return _qq_proxy_none(phb, (struct sockaddr *) &sin, sizeof(sin));
00292 case GAIM_PROXY_SOCKS5:
00293
00294
00295 _qq_fill_host(&qd->dest_sin, phb->host, phb->port);
00296 _qq_fill_host(&sin, phb->gpi->host, phb->gpi->port);
00297 return qq_proxy_socks5(phb, (struct sockaddr *) &sin, sizeof(sin));
00298 default:
00299 return _qq_proxy_none(phb, (struct sockaddr *) &sin, sizeof(sin));
00300 }
00301
00302 return -1;
00303 }
00304
00305
00306
00307
00308
00309
00310 gint _proxy_connect_full
00311 (GaimAccount * account, const gchar * host, guint16 port, GaimInputFunction func, gpointer data, gboolean use_tcp) {
00312
00313 GaimConnection *gc;
00314 qq_data *qd;
00315
00316 gc = gaim_account_get_connection(account);
00317 qd = (qq_data *) gc->proto_data;
00318 qd->server_ip = g_strdup(host);
00319 qd->server_port = port;
00320
00321 return use_tcp ? gaim_proxy_connect(account, host, port, func, data) :
00322 _qq_udp_proxy_connect(account, host, port, func, data);
00323
00324 }
00325
00326
00327
00328
00329
00330 gint qq_connect(GaimAccount * account, const gchar * host, guint16 port, gboolean use_tcp, gboolean is_redirect) {
00331
00332 GaimConnection *gc;
00333
00334 g_return_val_if_fail(host != NULL, -1);
00335 g_return_val_if_fail(port > 0, -1);
00336
00337 gc = gaim_account_get_connection(account);
00338 g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1);
00339
00340 if (is_redirect)
00341 _qq_common_clean(gc);
00342
00343 return _proxy_connect_full(account, host, port, _qq_got_login, gc, use_tcp);
00344 }
00345
00346
00347
00348 void qq_disconnect(GaimConnection * gc)
00349 {
00350 qq_data *qd;
00351
00352 g_return_if_fail(gc != NULL);
00353
00354 _qq_common_clean(gc);
00355
00356 qd = gc->proto_data;
00357 g_free(qd->inikey);
00358 g_free(qd->pwkey);
00359 g_free(qd->session_key);
00360 g_free(qd->my_ip);
00361 g_free(qd->ptoken);
00362 qd->ptoken = NULL;
00363 g_free(qd);
00364 gc->proto_data = NULL;
00365 }
00366
00367
00368
00369 gint qq_proxy_write(qq_data * qd, guint8 * data, gint len)
00370 {
00371 guint8 *buf;
00372 gint ret;
00373
00374 g_return_val_if_fail(qd != NULL && qd->fd >= 0 && data != NULL && len > 0, -1);
00375
00376
00377
00378 if ((!qd->use_tcp) && qd->proxy_type == GAIM_PROXY_SOCKS5) {
00379 buf = g_newa(guint8, len + 10);
00380 buf[0] = 0x00;
00381 buf[1] = 0x00;
00382 buf[2] = 0x00;
00383 buf[3] = 0x01;
00384 g_memmove(buf + 4, &(qd->dest_sin.sin_addr.s_addr), 4);
00385 g_memmove(buf + 8, &(qd->dest_sin.sin_port), 2);
00386 g_memmove(buf + 10, data, len);
00387 ret = send(qd->fd, buf, len + 10, 0);
00388 } else
00389 ret = send(qd->fd, data, len, 0);
00390
00391 return ret;
00392 }
00393
00394
00395
00396 gint qq_proxy_read(qq_data * qd, guint8 * data, gint len)
00397 {
00398 guint8 *buf;
00399 gint bytes;
00400 buf = g_newa(guint8, MAX_PACKET_SIZE + 10);
00401
00402 g_return_val_if_fail(qd != NULL && data != NULL && len > 0, -1);
00403 g_return_val_if_fail(qd->fd > 0, -1);
00404
00405 bytes = read(qd->fd, buf, len + 10);
00406 if (bytes < 0)
00407 return -1;
00408
00409 if ((!qd->use_tcp) && qd->proxy_type == GAIM_PROXY_SOCKS5) {
00410 if (bytes < 10)
00411 return -1;
00412 bytes -= 10;
00413 g_memmove(data, buf + 10, bytes);
00414 } else
00415 g_memmove(data, buf, bytes);
00416
00417 return bytes;
00418 }
00419
00420
00421