comparison libpurple/protocols/myspace/myspace.c @ 16404:47e07438f01c

Use g_convert for UTF-16LE conversion instead of converting manually. Add missing \n to purple_debug_info calls.
author Jeffrey Connelly <jaconnel@calpoly.edu>
date Sat, 28 Apr 2007 20:46:31 +0000
parents 10d2958bd632
children 8063f163f411
comparison
equal deleted inserted replaced
16403:48dbaace4e13 16404:47e07438f01c
195 195
196 /* All messages begin with a \ */ 196 /* All messages begin with a \ */
197 if (msg[0] != '\\' || msg[1] == 0) 197 if (msg[0] != '\\' || msg[1] == 0)
198 { 198 {
199 purple_debug_info("msim", "msim_parse: incomplete/bad msg, " 199 purple_debug_info("msim", "msim_parse: incomplete/bad msg, "
200 "missing initial backslash: <%s>", msg); 200 "missing initial backslash: <%s>\n", msg);
201 /* XXX: Should we try to recover, and read to first backslash? */ 201 /* XXX: Should we try to recover, and read to first backslash? */
202 202
203 g_free(msg); 203 g_free(msg);
204 return NULL; 204 return NULL;
205 } 205 }
224 g_hash_table_insert(table, g_strdup(key), g_strdup(value)); 224 g_hash_table_insert(table, g_strdup(key), g_strdup(value));
225 } else { 225 } else {
226 /* TODO: Some dictionaries have multiple values for the same 226 /* TODO: Some dictionaries have multiple values for the same
227 * key. Should append to a GList to handle this case. */ 227 * key. Should append to a GList to handle this case. */
228 purple_debug_info("msim", "msim_parse: key %s already exists, " 228 purple_debug_info("msim", "msim_parse: key %s already exists, "
229 "not overwriting or replacing; ignoring new value %s", key, 229 "not overwriting or replacing; ignoring new value %s\n", key,
230 value); 230 value);
231 } 231 }
232 } else { 232 } else {
233 key = token; 233 key = token;
234 } 234 }
249 * @param password User's cleartext password. 249 * @param password User's cleartext password.
250 * 250 *
251 * @return Encoded login challenge response, ready to send to the server. Must be g_free()'d 251 * @return Encoded login challenge response, ready to send to the server. Must be g_free()'d
252 * when finished. 252 * when finished.
253 */ 253 */
254 static gchar* msim_compute_login_response(guchar nonce[2*NONCE_HALF_SIZE], gchar* email, gchar* password) 254 static gchar* msim_compute_login_response(guchar nonce[2*NONCE_HALF_SIZE],
255 gchar* email, gchar* password)
255 { 256 {
256 PurpleCipherContext *key_context; 257 PurpleCipherContext *key_context;
257 PurpleCipher *sha1; 258 PurpleCipher *sha1;
258 PurpleCipherContext *rc4; 259 PurpleCipherContext *rc4;
259 guchar hash_pw[HASH_SIZE]; 260 guchar hash_pw[HASH_SIZE];
260 guchar key[HASH_SIZE]; 261 guchar key[HASH_SIZE];
261 gchar* password_utf16le; 262 gchar* password_utf16le;
262 guchar* data; 263 guchar* data;
263 guchar* data_out; 264 guchar* data_out;
264 gchar* response; 265 gchar* response;
265 int i;
266 size_t data_len, data_out_len; 266 size_t data_len, data_out_len;
267 gsize conv_bytes_read, conv_bytes_written;
268 GError* conv_error;
267 269
268 //memset(nonce, 0, NONCE_HALF_SIZE); 270 //memset(nonce, 0, NONCE_HALF_SIZE);
269 //memset(nonce + NONCE_HALF_SIZE, 1, NONCE_HALF_SIZE); 271 //memset(nonce + NONCE_HALF_SIZE, 1, NONCE_HALF_SIZE);
270 272
271 /* Convert ASCII password to UTF16 little endian */ 273 /* Convert ASCII password to UTF16 little endian */
272 /* TODO: use the built-in facility to do this, like Nathan Peterson does. */ 274 purple_debug_info("msim", "converting password to UTF-16LE\n");
273 purple_debug_info("msim", "converting password to utf16le\n"); 275 conv_error = NULL;
274 //printf("pw=<%s>\n",password); 276 password_utf16le = g_convert(password, -1, "UTF-16LE", "UTF-8",
277 &conv_bytes_read, &conv_bytes_written, &conv_error);
278 g_assert(conv_bytes_read == strlen(password));
279 if (conv_error != NULL)
280 {
281 purple_debug_error("msim",
282 "g_convert password UTF8->UTF16LE failed: %s",
283 conv_error->message);
284 g_error_free(conv_error);
285 }
286
287 #if 0
275 password_utf16le = g_new0(gchar, strlen(password) * 2); 288 password_utf16le = g_new0(gchar, strlen(password) * 2);
276 for (i = 0; i < strlen(password) * 2; i += 2) 289 for (i = 0; i < strlen(password) * 2; i += 2)
277 { 290 {
278 password_utf16le[i] = password[i / 2]; 291 password_utf16le[i] = password[i / 2];
279 password_utf16le[i + 1] = 0; 292 password_utf16le[i + 1] = 0;
280 } 293 }
294 #endif
281 295
282 /* Compute password hash */ 296 /* Compute password hash */
283 purple_cipher_digest_region("sha1", (guchar*)password_utf16le, strlen(password) * 2, 297 purple_cipher_digest_region("sha1", (guchar*)password_utf16le,
284 sizeof(hash_pw), hash_pw, NULL); 298 conv_bytes_written, sizeof(hash_pw), hash_pw, NULL);
299 g_free(password_utf16le);
285 300
286 #ifdef MSIM_DEBUG_LOGIN_CHALLENGE 301 #ifdef MSIM_DEBUG_LOGIN_CHALLENGE
287 printf("pwhash = "); 302 printf("pwhash = ");
288 for (i = 0; i < sizeof(hash_pw); i++) 303 for (i = 0; i < sizeof(hash_pw); i++)
289 printf("%.2x ", hash_pw[i]); 304 printf("%.2x ", hash_pw[i]);
369 384
370 ret = send(session->fd, msg, strlen(msg), 0); 385 ret = send(session->fd, msg, strlen(msg), 0);
371 386
372 if (ret != strlen(msg)) 387 if (ret != strlen(msg))
373 { 388 {
374 purple_debug_info("msim", "msim_send(%s): strlen=%d, but only wrote %s\n", 389 purple_debug_info("msim",
390 "msim_send(%s): strlen=%d, but only wrote %s\n",
375 msg, strlen(msg), ret); 391 msg, strlen(msg), ret);
376 /* TODO: better error */ 392 /* TODO: better error */
377 } 393 }
378 } 394 }
379 395
469 elements = g_strsplit(item, "=", 2); 485 elements = g_strsplit(item, "=", 2);
470 486
471 key = elements[0]; 487 key = elements[0];
472 if (!key) 488 if (!key)
473 { 489 {
474 purple_debug_info("msim", "msim_parse_body(%s): null key", body_str); 490 purple_debug_info("msim", "msim_parse_body(%s): null key\n",
491 body_str);
475 g_strfreev(elements); 492 g_strfreev(elements);
476 break; 493 break;
477 } 494 }
478 495
479 value = elements[1]; 496 value = elements[1];
480 if (!value) 497 if (!value)
481 { 498 {
482 purple_debug_info("msim", "msim_parse_body(%s): null value", body_str); 499 purple_debug_info("msim", "msim_parse_body(%s): null value\n",
500 body_str);
483 g_strfreev(elements); 501 g_strfreev(elements);
484 break; 502 break;
485 } 503 }
486 504
487 //printf("-- %s: %s\n", key, value); 505 //printf("-- %s: %s\n", key, value);
610 username = g_hash_table_lookup(body, "UserName"); 628 username = g_hash_table_lookup(body, "UserName");
611 if (username) 629 if (username)
612 { 630 {
613 g_hash_table_insert(session->user_lookup_cache, g_strdup(username), body); 631 g_hash_table_insert(session->user_lookup_cache, g_strdup(username), body);
614 } else { 632 } else {
615 purple_debug_info("msim", "msim_process_reply: not caching <%s>, no UserName", 633 purple_debug_info("msim",
634 "msim_process_reply: not caching <%s>, no UserName\n",
616 g_hash_table_lookup(table, "body")); 635 g_hash_table_lookup(table, "body"));
617 } 636 }
618 637
619 /* If a callback is registered for this userid lookup, call it. */ 638 /* If a callback is registered for this userid lookup, call it. */
620 639
621 cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid)); 640 cb = g_hash_table_lookup(session->user_lookup_cb, GUINT_TO_POINTER(rid));
622 data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid)); 641 data = g_hash_table_lookup(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
623 642
624 if (cb) 643 if (cb)
625 { 644 {
626 purple_debug_info("msim", "msim_process_body: calling callback now\n"); 645 purple_debug_info("msim",
646 "msim_process_body: calling callback now\n");
627 cb(session, table, data); 647 cb(session, table, data);
628 g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid)); 648 g_hash_table_remove(session->user_lookup_cb, GUINT_TO_POINTER(rid));
629 g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid)); 649 g_hash_table_remove(session->user_lookup_cb_data, GUINT_TO_POINTER(rid));
630 650
631 /* Return 1 to tell caller of msim_process (msim_input_cb) to 651 /* Return 1 to tell caller of msim_process (msim_input_cb) to
632 * not destroy 'table'; allow 'cb' to hang on to it and destroy 652 * not destroy 'table'; allow 'cb' to hang on to it and destroy
633 * it when it wants. */ 653 * it when it wants. */
634 return 1; 654 return 1;
635 } else { 655 } else {
636 purple_debug_info("msim", "msim_process_body: no callback for rid %d\n", rid); 656 purple_debug_info("msim",
657 "msim_process_body: no callback for rid %d\n", rid);
637 } 658 }
638 } 659 }
639 return 0; 660 return 0;
640 } 661 }
641 662
723 744
724 745
725 userid = g_hash_table_lookup(table, "f"); 746 userid = g_hash_table_lookup(table, "f");
726 msg = g_hash_table_lookup(table, "msg"); 747 msg = g_hash_table_lookup(table, "msg");
727 748
728 purple_debug_info("msim", "msim_incoming_im: got msg <%s> from <%s>, resolving username\n", 749 purple_debug_info("msim",
750 "msim_incoming_im: got msg <%s> from <%s>, resolving username\n",
729 msg, userid); 751 msg, userid);
730 752
731 msim_lookup_user(session, userid, msim_incoming_im_cb, g_strdup(msg)); 753 msim_lookup_user(session, userid, msim_incoming_im_cb, g_strdup(msg));
732 754
733 return 0; 755 return 0;
779 { 801 {
780 purple_debug_info("msim", "msim_status_cb: no username?!\n"); 802 purple_debug_info("msim", "msim_status_cb: no username?!\n");
781 return; 803 return;
782 } 804 }
783 805
784 purple_debug_info("msim", "msim_status_cb: updating status for <%s> to <%s>\n", username, status_str); 806 purple_debug_info("msim",
807 "msim_status_cb: updating status for <%s> to <%s>\n",
808 username, status_str);
785 809
786 /* TODO: generic functions to split into a GList */ 810 /* TODO: generic functions to split into a GList */
787 status_array = g_strsplit(status_str, "|", 0); 811 status_array = g_strsplit(status_str, "|", 0);
788 for (list = NULL, i = 0; 812 for (list = NULL, i = 0;
789 status_array[i]; 813 status_array[i];
801 /* Add buddy if not found */ 825 /* Add buddy if not found */
802 buddy = purple_find_buddy(session->account, username); 826 buddy = purple_find_buddy(session->account, username);
803 if (!buddy) 827 if (!buddy)
804 { 828 {
805 /* TODO: purple aliases, userids and usernames */ 829 /* TODO: purple aliases, userids and usernames */
806 purple_debug_info("msim", "msim_status: making new buddy for %s\n", username); 830 purple_debug_info("msim",
831 "msim_status: making new buddy for %s\n", username);
807 buddy = purple_buddy_new(session->account, username, NULL); 832 buddy = purple_buddy_new(session->account, username, NULL);
808 833
809 /* TODO: sometimes (when click on it), buddy list disappears. Fix. */ 834 /* TODO: sometimes (when click on it), buddy list disappears. Fix. */
810 purple_blist_add_buddy(buddy, NULL, NULL, NULL); 835 purple_blist_add_buddy(buddy, NULL, NULL, NULL);
811 } else { 836 } else {
855 return 0; 880 return 0;
856 } 881 }
857 882
858 /* TODO: if buddies were identified on buddy list by uid, wouldn't have to lookup 883 /* TODO: if buddies were identified on buddy list by uid, wouldn't have to lookup
859 * before updating the status! Much more efficient. */ 884 * before updating the status! Much more efficient. */
860 purple_debug_info("msim", "msim_status: got status msg <%s> for <%s>, scheduling lookup\n", 885 purple_debug_info("msim",
886 "msim_status: got status msg <%s> for <%s>, scheduling lookup\n",
861 status_str, userid); 887 status_str, userid);
862 888
863 /* Actually update status once obtain username */ 889 /* Actually update status once obtain username */
864 msim_lookup_user(session, userid, msim_status_cb, g_strdup(status_str)); 890 msim_lookup_user(session, userid, msim_status_cb, g_strdup(status_str));
865 891
982 close(source); 1008 close(source);
983 return; 1009 return;
984 } 1010 }
985 1011
986 purple_debug_info("msim", "buffer at %d (max %d), reading up to %d\n", 1012 purple_debug_info("msim", "buffer at %d (max %d), reading up to %d\n",
987 session->rxoff, MSIM_READ_BUF_SIZE, MSIM_READ_BUF_SIZE - session->rxoff); 1013 session->rxoff, MSIM_READ_BUF_SIZE,
1014 MSIM_READ_BUF_SIZE - session->rxoff);
988 1015
989 /* Read into buffer. On Win32, need recv() not read(). session->fd also holds 1016 /* Read into buffer. On Win32, need recv() not read(). session->fd also holds
990 * the file descriptor, but it sometimes differs from the 'source' parameter. 1017 * the file descriptor, but it sometimes differs from the 'source' parameter.
991 */ 1018 */
992 n = recv(session->fd, session->rxbuf + session->rxoff, MSIM_READ_BUF_SIZE - session->rxoff, 0); 1019 n = recv(session->fd, session->rxbuf + session->rxoff, MSIM_READ_BUF_SIZE - session->rxoff, 0);
1017 /* Check for embedded NULs. I don't handle them, and they shouldn't occur. */ 1044 /* Check for embedded NULs. I don't handle them, and they shouldn't occur. */
1018 if (strlen(session->rxbuf + session->rxoff) != n) 1045 if (strlen(session->rxbuf + session->rxoff) != n)
1019 { 1046 {
1020 /* Occurs after login, but it is not a null byte. */ 1047 /* Occurs after login, but it is not a null byte. */
1021 purple_debug_info("msim", "msim_input_cb: strlen=%d, but read %d bytes" 1048 purple_debug_info("msim", "msim_input_cb: strlen=%d, but read %d bytes"
1022 "--null byte encountered?\n", strlen(session->rxbuf + session->rxoff), n); 1049 "--null byte encountered?\n",
1050 strlen(session->rxbuf + session->rxoff), n);
1023 //purple_connection_error(gc, "Invalid message - null byte on input"); 1051 //purple_connection_error(gc, "Invalid message - null byte on input");
1024 return; 1052 return;
1025 } 1053 }
1026 1054
1027 session->rxoff += n; 1055 session->rxoff += n;
1037 //printf("in loop: buf=<%s>\n", session->rxbuf); 1065 //printf("in loop: buf=<%s>\n", session->rxbuf);
1038 *end = 0; 1066 *end = 0;
1039 table = msim_parse(g_strdup(session->rxbuf)); 1067 table = msim_parse(g_strdup(session->rxbuf));
1040 if (!table) 1068 if (!table)
1041 { 1069 {
1042 purple_debug_info("msim", "msim_input_cb: couldn't parse <%s>\n", session->rxbuf); 1070 purple_debug_info("msim", "msim_input_cb: couldn't parse <%s>\n",
1071 session->rxbuf);
1043 purple_connection_error(gc, "Unparseable message"); 1072 purple_connection_error(gc, "Unparseable message");
1044 } 1073 }
1045 else 1074 else
1046 { 1075 {
1047 /* Process message. Returns 0 to free */ 1076 /* Process message. Returns 0 to free */
1266 1295
1267 g_return_if_fail(MSIM_SESSION_VALID(session)); 1296 g_return_if_fail(MSIM_SESSION_VALID(session));
1268 g_return_if_fail(user != NULL); 1297 g_return_if_fail(user != NULL);
1269 g_return_if_fail(cb != NULL); 1298 g_return_if_fail(cb != NULL);
1270 1299
1271 purple_debug_info("msim", "msim_lookup_userid", "asynchronously looking up <%s>\n", user); 1300 purple_debug_info("msim", "msim_lookup_userid",
1301 "asynchronously looking up <%s>\n", user);
1272 1302
1273 /* TODO: check if this user's info was cached and fresh; if so return immediately */ 1303 /* TODO: check if this user's info was cached and fresh; if so return immediately */
1274 #if 0 1304 #if 0
1275 /* If already know userid, then call callback immediately */ 1305 /* If already know userid, then call callback immediately */
1276 cached_userid = g_hash_table_lookup(session->userid_cache, who); 1306 cached_userid = g_hash_table_lookup(session->userid_cache, who);
1350 session = gc->proto_data; 1380 session = gc->proto_data;
1351 1381
1352 /* If numeric ID, can send message immediately without userid lookup */ 1382 /* If numeric ID, can send message immediately without userid lookup */
1353 if (msim_is_userid(who)) 1383 if (msim_is_userid(who))
1354 { 1384 {
1355 purple_debug_info("msim", "msim_send_im: numeric 'who' detected, sending asap\n"); 1385 purple_debug_info("msim",
1386 "msim_send_im: numeric 'who' detected, sending asap\n");
1356 msim_send_im_by_userid(session, who, message, flags); 1387 msim_send_im_by_userid(session, who, message, flags);
1357 return 1; 1388 return 1;
1358 } 1389 }
1359 1390
1360 /* Otherwise, add callback to IM when userid of destination is available */ 1391 /* Otherwise, add callback to IM when userid of destination is available */