comparison libpurple/protocols/oscar/oscar.c @ 27590:a08e84032814

merge of '2348ff22f0ff3453774b8b25b36238465580c609' and 'e76f11543c2a4aa05bdf584f087cbe3439029661'
author Paul Aurich <paul@darkrain42.org>
date Sun, 12 Jul 2009 05:43:38 +0000
parents 5048054d319a
children bff61dad9a6b bd9df4e45904
comparison
equal deleted inserted replaced
27104:048bcf41deef 27590:a08e84032814
143 N_("Not while on AOL") 143 N_("Not while on AOL")
144 }; 144 };
145 static const int msgerrreasonlen = G_N_ELEMENTS(msgerrreason); 145 static const int msgerrreasonlen = G_N_ELEMENTS(msgerrreason);
146 146
147 /* All the libfaim->purple callback functions */ 147 /* All the libfaim->purple callback functions */
148
149 /* Only used when connecting with the old-style BUCP login */
148 static int purple_parse_auth_resp (OscarData *, FlapConnection *, FlapFrame *, ...); 150 static int purple_parse_auth_resp (OscarData *, FlapConnection *, FlapFrame *, ...);
149 static int purple_parse_login (OscarData *, FlapConnection *, FlapFrame *, ...); 151 static int purple_parse_login (OscarData *, FlapConnection *, FlapFrame *, ...);
150 static int purple_parse_auth_securid_request(OscarData *, FlapConnection *, FlapFrame *, ...); 152 static int purple_parse_auth_securid_request(OscarData *, FlapConnection *, FlapFrame *, ...);
153
151 static int purple_handle_redirect (OscarData *, FlapConnection *, FlapFrame *, ...); 154 static int purple_handle_redirect (OscarData *, FlapConnection *, FlapFrame *, ...);
152 static int purple_info_change (OscarData *, FlapConnection *, FlapFrame *, ...); 155 static int purple_info_change (OscarData *, FlapConnection *, FlapFrame *, ...);
153 static int purple_account_confirm (OscarData *, FlapConnection *, FlapFrame *, ...); 156 static int purple_account_confirm (OscarData *, FlapConnection *, FlapFrame *, ...);
154 static int purple_parse_oncoming (OscarData *, FlapConnection *, FlapFrame *, ...); 157 static int purple_parse_oncoming (OscarData *, FlapConnection *, FlapFrame *, ...);
155 static int purple_parse_offgoing (OscarData *, FlapConnection *, FlapFrame *, ...); 158 static int purple_parse_offgoing (OscarData *, FlapConnection *, FlapFrame *, ...);
202 static void purple_icons_fetch(PurpleConnection *gc); 205 static void purple_icons_fetch(PurpleConnection *gc);
203 206
204 void oscar_set_info(PurpleConnection *gc, const char *info); 207 void oscar_set_info(PurpleConnection *gc, const char *info);
205 static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status); 208 static void oscar_set_info_and_status(PurpleAccount *account, gboolean setinfo, const char *rawinfo, gboolean setstatus, PurpleStatus *status);
206 static void oscar_set_extendedstatus(PurpleConnection *gc); 209 static void oscar_set_extendedstatus(PurpleConnection *gc);
207 static void oscar_format_username(PurpleConnection *gc, const char *nick);
208 static gboolean purple_ssi_rerequestdata(gpointer data); 210 static gboolean purple_ssi_rerequestdata(gpointer data);
209 211
210 static void oscar_free_name_data(struct name_data *data) { 212 static void oscar_free_name_data(struct name_data *data) {
211 g_free(data->name); 213 g_free(data->name);
212 g_free(data->nick); 214 g_free(data->nick);
1105 purple_debug_error("oscar", "unable to connect to FLAP " 1107 purple_debug_error("oscar", "unable to connect to FLAP "
1106 "server of type 0x%04hx\n", conn->type); 1108 "server of type 0x%04hx\n", conn->type);
1107 1109
1108 if (conn->type == SNAC_FAMILY_AUTH) 1110 if (conn->type == SNAC_FAMILY_AUTH)
1109 { 1111 {
1112 /* This only happens when connecting with the old-style BUCP login */
1110 gchar *msg; 1113 gchar *msg;
1111 msg = g_strdup_printf(_("Could not connect to authentication server:\n%s"), 1114 msg = g_strdup_printf(_("Unable to connect to authentication server: %s"),
1112 error_message); 1115 error_message);
1113 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg); 1116 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
1114 g_free(msg); 1117 g_free(msg);
1115 } 1118 }
1116 else if (conn->type == SNAC_FAMILY_LOCATE) 1119 else if (conn->type == SNAC_FAMILY_LOCATE)
1117 { 1120 {
1118 gchar *msg; 1121 gchar *msg;
1119 msg = g_strdup_printf(_("Could not connect to BOS server:\n%s"), 1122 msg = g_strdup_printf(_("Unable to connect to BOS server: %s"),
1120 error_message); 1123 error_message);
1121 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg); 1124 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
1122 g_free(msg); 1125 g_free(msg);
1123 } 1126 }
1124 else 1127 else
1150 1153
1151 if (conn->cookie == NULL) 1154 if (conn->cookie == NULL)
1152 flap_connection_send_version(od, conn); 1155 flap_connection_send_version(od, conn);
1153 else 1156 else
1154 { 1157 {
1155 flap_connection_send_version_with_cookie(od, conn, 1158 if (purple_account_get_bool(account, "use_clientlogin", OSCAR_DEFAULT_USE_CLIENTLOGIN))
1156 conn->cookielen, conn->cookie); 1159 {
1160 ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM;
1161 ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ;
1162 flap_connection_send_version_with_cookie_and_clientinfo(od,
1163 conn, conn->cookielen, conn->cookie,
1164 od->icq ? &icqinfo : &aiminfo);
1165 } else {
1166 flap_connection_send_version_with_cookie(od, conn,
1167 conn->cookielen, conn->cookie);
1168 }
1169
1170
1157 g_free(conn->cookie); 1171 g_free(conn->cookie);
1158 conn->cookie = NULL; 1172 conn->cookie = NULL;
1159 } 1173 }
1160 1174
1161 if (conn->type == SNAC_FAMILY_AUTH) 1175 if (conn->type == SNAC_FAMILY_AUTH)
1162 { 1176 {
1177 /* This only happens when connecting with the old-style BUCP login */
1163 aim_request_login(od, conn, purple_account_get_username(account)); 1178 aim_request_login(od, conn, purple_account_get_username(account));
1164 purple_debug_info("oscar", "Username sent, waiting for response\n"); 1179 purple_debug_info("oscar", "Username sent, waiting for response\n");
1165 purple_connection_update_progress(gc, _("Username sent"), 1, OSCAR_CONNECT_STEPS); 1180 purple_connection_update_progress(gc, _("Username sent"), 1, OSCAR_CONNECT_STEPS);
1166 ck[1] = 0x65; 1181 ck[1] = 0x65;
1167 } 1182 }
1428 void 1443 void
1429 oscar_login(PurpleAccount *account) 1444 oscar_login(PurpleAccount *account)
1430 { 1445 {
1431 PurpleConnection *gc; 1446 PurpleConnection *gc;
1432 OscarData *od; 1447 OscarData *od;
1433 FlapConnection *newconn;
1434 1448
1435 gc = purple_account_get_connection(account); 1449 gc = purple_account_get_connection(account);
1436 od = oscar_data_new(); 1450 od = oscar_data_new();
1437 od->gc = gc; 1451 od->gc = gc;
1438 purple_connection_set_protocol_data(gc, od); 1452 purple_connection_set_protocol_data(gc, od);
1443 oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0003, purple_info_change, 0); 1457 oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0003, purple_info_change, 0);
1444 oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0005, purple_info_change, 0); 1458 oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0005, purple_info_change, 0);
1445 oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0007, purple_account_confirm, 0); 1459 oscar_data_addhandler(od, SNAC_FAMILY_ADMIN, 0x0007, purple_account_confirm, 0);
1446 oscar_data_addhandler(od, SNAC_FAMILY_ALERT, 0x0001, purple_parse_genericerr, 0); 1460 oscar_data_addhandler(od, SNAC_FAMILY_ALERT, 0x0001, purple_parse_genericerr, 0);
1447 oscar_data_addhandler(od, SNAC_FAMILY_ALERT, SNAC_SUBTYPE_ALERT_MAILSTATUS, purple_email_parseupdate, 0); 1461 oscar_data_addhandler(od, SNAC_FAMILY_ALERT, SNAC_SUBTYPE_ALERT_MAILSTATUS, purple_email_parseupdate, 0);
1462
1463 /* These are only needed when connecting with the old-style BUCP login */
1448 oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0003, purple_parse_auth_resp, 0); 1464 oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0003, purple_parse_auth_resp, 0);
1449 oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0007, purple_parse_login, 0); 1465 oscar_data_addhandler(od, SNAC_FAMILY_AUTH, 0x0007, purple_parse_login, 0);
1450 oscar_data_addhandler(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_REQUEST, purple_parse_auth_securid_request, 0); 1466 oscar_data_addhandler(od, SNAC_FAMILY_AUTH, SNAC_SUBTYPE_AUTH_SECURID_REQUEST, purple_parse_auth_securid_request, 0);
1467
1451 oscar_data_addhandler(od, SNAC_FAMILY_BART, SNAC_SUBTYPE_BART_RESPONSE, purple_icon_parseicon, 0); 1468 oscar_data_addhandler(od, SNAC_FAMILY_BART, SNAC_SUBTYPE_BART_RESPONSE, purple_icon_parseicon, 0);
1452 oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0001, purple_parse_genericerr, 0); 1469 oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0001, purple_parse_genericerr, 0);
1453 oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0003, purple_bosrights, 0); 1470 oscar_data_addhandler(od, SNAC_FAMILY_BOS, 0x0003, purple_bosrights, 0);
1454 oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, 0x0001, purple_parse_genericerr, 0); 1471 oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, 0x0001, purple_parse_genericerr, 0);
1455 oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_RIGHTSINFO, purple_parse_buddyrights, 0); 1472 oscar_data_addhandler(od, SNAC_FAMILY_BUDDY, SNAC_SUBTYPE_BUDDY_RIGHTSINFO, purple_parse_buddyrights, 0);
1502 1519
1503 purple_debug_misc("oscar", "oscar_login: gc = %p\n", gc); 1520 purple_debug_misc("oscar", "oscar_login: gc = %p\n", gc);
1504 1521
1505 if (!oscar_util_valid_name(purple_account_get_username(account))) { 1522 if (!oscar_util_valid_name(purple_account_get_username(account))) {
1506 gchar *buf; 1523 gchar *buf;
1507 buf = g_strdup_printf(_("Unable to login: Could not sign on as %s because the username is invalid. Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account)); 1524 buf = g_strdup_printf(_("Unable to sign on as %s because the username is invalid. Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account));
1508 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, buf); 1525 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, buf);
1509 g_free(buf); 1526 g_free(buf);
1510 return; 1527 return;
1511 } 1528 }
1512 1529
1515 } else { 1532 } else {
1516 gc->flags |= PURPLE_CONNECTION_HTML; 1533 gc->flags |= PURPLE_CONNECTION_HTML;
1517 gc->flags |= PURPLE_CONNECTION_AUTO_RESP; 1534 gc->flags |= PURPLE_CONNECTION_AUTO_RESP;
1518 } 1535 }
1519 1536
1537 od->default_port = purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT);
1520 od->use_ssl = purple_account_get_bool(account, "use_ssl", OSCAR_DEFAULT_USE_SSL); 1538 od->use_ssl = purple_account_get_bool(account, "use_ssl", OSCAR_DEFAULT_USE_SSL);
1521 1539
1522 /* Connect to core Purple signals */ 1540 /* Connect to core Purple signals */
1523 purple_prefs_connect_callback(gc, "/purple/away/idle_reporting", idle_reporting_pref_cb, gc); 1541 purple_prefs_connect_callback(gc, "/purple/away/idle_reporting", idle_reporting_pref_cb, gc);
1524 purple_prefs_connect_callback(gc, "/plugins/prpl/oscar/recent_buddies", recent_buddies_pref_cb, gc); 1542 purple_prefs_connect_callback(gc, "/plugins/prpl/oscar/recent_buddies", recent_buddies_pref_cb, gc);
1525 1543
1526 newconn = flap_connection_new(od, SNAC_FAMILY_AUTH); 1544 /*
1527 if (od->use_ssl) { 1545 * On 2008-03-05 AOL released some documentation on the OSCAR protocol
1528 if (purple_ssl_is_supported()) { 1546 * which includes a new login method called clientLogin. It is similar
1529 const char *server = purple_account_get_string(account, "server", OSCAR_DEFAULT_SSL_LOGIN_SERVER); 1547 * (though not the same?) as what the AIM 6.0 series uses to
1548 * authenticate.
1549 *
1550 * AIM 5.9 and lower use an MD5-based login procedure called "BUCP".
1551 * This authentication method is used for both ICQ and AIM when
1552 * clientLogin is not enabled.
1553 */
1554 if (purple_account_get_bool(account, "use_clientlogin", OSCAR_DEFAULT_USE_CLIENTLOGIN)) {
1555 send_client_login(od, purple_account_get_username(account));
1556 } else {
1557 FlapConnection *newconn;
1558 const char *server;
1559
1560 newconn = flap_connection_new(od, SNAC_FAMILY_AUTH);
1561
1562 if (od->use_ssl) {
1563 if (!purple_ssl_is_supported()) {
1564 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
1565 _("SSL support unavailable"));
1566 return;
1567 }
1568
1569 server = purple_account_get_string(account, "server", OSCAR_DEFAULT_SSL_LOGIN_SERVER);
1570
1530 /* 1571 /*
1531 * If the account's server is what the oscar prpl has offered as 1572 * If the account's server is what the oscar prpl has offered as
1532 * the default login server through the vast eons (all two of 1573 * the default login server through the vast eons (all two of
1533 * said default options, AFAIK) and the user wants SSL, we'll 1574 * said default options, AFAIK) and the user wants SSL, we'll
1534 * do what we know is best for them and change the setting out 1575 * do what we know is best for them and change the setting out
1542 1583
1543 newconn->gsc = purple_ssl_connect(account, server, 1584 newconn->gsc = purple_ssl_connect(account, server,
1544 purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT), 1585 purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
1545 ssl_connection_established_cb, ssl_connection_error_cb, newconn); 1586 ssl_connection_established_cb, ssl_connection_error_cb, newconn);
1546 } else { 1587 } else {
1547 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT, 1588 server = purple_account_get_string(account, "server", OSCAR_DEFAULT_LOGIN_SERVER);
1548 _("SSL support unavailable")); 1589
1549 } 1590 /*
1550 } else { 1591 * See the comment above. We do the reverse here. If they don't want
1551 const char *server = purple_account_get_string(account, "server", OSCAR_DEFAULT_LOGIN_SERVER); 1592 * SSL but their server is set to OSCAR_DEFAULT_SSL_LOGIN_SERVER,
1552 1593 * set it back to the default.
1553 /* 1594 */
1554 * See the comment above. We do the reverse here. If they don't want 1595 if (!strcmp(server, OSCAR_DEFAULT_SSL_LOGIN_SERVER)) {
1555 * SSL but their server is set to OSCAR_DEFAULT_SSL_LOGIN_SERVER, 1596 purple_debug_info("oscar", "Account does not use SSL, so changing server back to non-SSL\n");
1556 * set it back to the default. 1597 purple_account_set_string(account, "server", OSCAR_DEFAULT_LOGIN_SERVER);
1557 */ 1598 server = OSCAR_DEFAULT_LOGIN_SERVER;
1558 if (!strcmp(server, OSCAR_DEFAULT_SSL_LOGIN_SERVER)) { 1599 }
1559 purple_debug_info("oscar", "Account does not use SSL, so changing server back to non-SSL\n"); 1600
1560 purple_account_set_string(account, "server", OSCAR_DEFAULT_LOGIN_SERVER); 1601 newconn->connect_data = purple_proxy_connect(NULL, account, server,
1561 server = OSCAR_DEFAULT_LOGIN_SERVER; 1602 purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
1562 } 1603 connection_established_cb, newconn);
1563 1604 }
1564 newconn->connect_data = purple_proxy_connect(NULL, account, server, 1605
1565 purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT), 1606 if (newconn->gsc == NULL && newconn->connect_data == NULL) {
1566 connection_established_cb, newconn); 1607 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
1567 } 1608 _("Unable to connect"));
1568 1609 return;
1569 if (newconn->gsc == NULL && newconn->connect_data == NULL) { 1610 }
1570 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
1571 _("Couldn't connect to host"));
1572 return;
1573 } 1611 }
1574 1612
1575 purple_connection_update_progress(gc, _("Connecting"), 0, OSCAR_CONNECT_STEPS); 1613 purple_connection_update_progress(gc, _("Connecting"), 0, OSCAR_CONNECT_STEPS);
1576 ck[0] = 0x5a; 1614 ck[0] = 0x5a;
1577 } 1615 }
1602 purple_prefs_disconnect_by_handle(gc); 1640 purple_prefs_disconnect_by_handle(gc);
1603 1641
1604 purple_debug_info("oscar", "Signed off.\n"); 1642 purple_debug_info("oscar", "Signed off.\n");
1605 } 1643 }
1606 1644
1645 /* XXX - Should use purple_util_fetch_url for the below stuff */
1646 struct pieceofcrap {
1647 PurpleConnection *gc;
1648 unsigned long offset;
1649 unsigned long len;
1650 char *modname;
1651 int fd;
1652 FlapConnection *conn;
1653 unsigned int inpa;
1654 };
1655
1656 static void damn_you(gpointer data, gint source, PurpleInputCondition c)
1657 {
1658 struct pieceofcrap *pos = data;
1659 OscarData *od = purple_connection_get_protocol_data(pos->gc);
1660 char in = '\0';
1661 int x = 0;
1662 unsigned char m[17];
1663 GString *msg;
1664
1665 while (read(pos->fd, &in, 1) == 1) {
1666 if (in == '\n')
1667 x++;
1668 else if (in != '\r')
1669 x = 0;
1670 if (x == 2)
1671 break;
1672 in = '\0';
1673 }
1674 if (in != '\n') {
1675 char buf[256];
1676 g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly. "
1677 "If so, check %s for updates."),
1678 oscar_get_ui_info_string("website", PURPLE_WEBSITE));
1679 purple_notify_warning(pos->gc, NULL,
1680 _("Unable to get a valid AIM login hash."),
1681 buf);
1682 purple_input_remove(pos->inpa);
1683 close(pos->fd);
1684 g_free(pos);
1685 return;
1686 }
1687 if (read(pos->fd, m, 16) != 16)
1688 {
1689 purple_debug_warning("oscar", "Could not read full AIM login hash "
1690 "from " AIMHASHDATA "--that's bad.\n");
1691 }
1692 m[16] = '\0';
1693
1694 msg = g_string_new("Sending hash: ");
1695 for (x = 0; x < 16; x++)
1696 g_string_append_printf(msg, "%02hhx ", (unsigned char)m[x]);
1697 g_string_append(msg, "\n");
1698 purple_debug_misc("oscar", "%s", msg->str);
1699 g_string_free(msg, TRUE);
1700
1701 purple_input_remove(pos->inpa);
1702 close(pos->fd);
1703 aim_sendmemblock(od, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);
1704 g_free(pos);
1705 }
1706
1707 static void
1708 straight_to_hell(gpointer data, gint source, const gchar *error_message)
1709 {
1710 struct pieceofcrap *pos = data;
1711 gchar *buf;
1712 gssize result;
1713
1714 pos->fd = source;
1715
1716 if (source < 0) {
1717 buf = g_strdup_printf(_("You may be disconnected shortly. "
1718 "If so, check %s for updates."),
1719 oscar_get_ui_info_string("website", PURPLE_WEBSITE));
1720 purple_notify_warning(pos->gc, NULL,
1721 _("Unable to get a valid AIM login hash."),
1722 buf);
1723 g_free(buf);
1724 g_free(pos->modname);
1725 g_free(pos);
1726 return;
1727 }
1728
1729 buf = g_strdup_printf("GET " AIMHASHDATA "?offset=%ld&len=%ld&modname=%s HTTP/1.0\n\n",
1730 pos->offset, pos->len, pos->modname ? pos->modname : "");
1731 result = send(pos->fd, buf, strlen(buf), 0);
1732 if (result != strlen(buf)) {
1733 if (result < 0)
1734 purple_debug_error("oscar", "Error writing %" G_GSIZE_FORMAT
1735 " bytes to fetch AIM hash data: %s\n",
1736 strlen(buf), g_strerror(errno));
1737 else
1738 purple_debug_error("oscar", "Tried to write %"
1739 G_GSIZE_FORMAT " bytes to fetch AIM hash data but "
1740 "instead wrote %" G_GSSIZE_FORMAT " bytes\n",
1741 strlen(buf), result);
1742 }
1743 g_free(buf);
1744 g_free(pos->modname);
1745 pos->inpa = purple_input_add(pos->fd, PURPLE_INPUT_READ, damn_you, pos);
1746 return;
1747 }
1748
1749 /* size of icbmui.ocm, the largest module in AIM 3.5 */
1750 #define AIM_MAX_FILE_SIZE 98304
1751
1752 static int purple_memrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
1753 {
1754 va_list ap;
1755 struct pieceofcrap *pos;
1756 guint32 offset, len;
1757 char *modname;
1758
1759 va_start(ap, fr);
1760 offset = va_arg(ap, guint32);
1761 len = va_arg(ap, guint32);
1762 modname = va_arg(ap, char *);
1763 va_end(ap);
1764
1765 purple_debug_misc("oscar", "offset: %u, len: %u, file: %s\n",
1766 offset, len, (modname ? modname : "aim.exe"));
1767
1768 if (len == 0) {
1769 purple_debug_misc("oscar", "len is 0, hashing NULL\n");
1770 aim_sendmemblock(od, conn, offset, len, NULL,
1771 AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
1772 return 1;
1773 }
1774 /* uncomment this when you're convinced it's right. remember, it's been wrong before. */
1775 #if 0
1776 if (offset > AIM_MAX_FILE_SIZE || len > AIM_MAX_FILE_SIZE) {
1777 char *buf;
1778 int i = 8;
1779 if (modname)
1780 i += strlen(modname);
1781 buf = g_malloc(i);
1782 i = 0;
1783 if (modname) {
1784 memcpy(buf, modname, strlen(modname));
1785 i += strlen(modname);
1786 }
1787 buf[i++] = offset & 0xff;
1788 buf[i++] = (offset >> 8) & 0xff;
1789 buf[i++] = (offset >> 16) & 0xff;
1790 buf[i++] = (offset >> 24) & 0xff;
1791 buf[i++] = len & 0xff;
1792 buf[i++] = (len >> 8) & 0xff;
1793 buf[i++] = (len >> 16) & 0xff;
1794 buf[i++] = (len >> 24) & 0xff;
1795 purple_debug_misc("oscar", "len + offset is invalid, "
1796 "hashing request\n");
1797 aim_sendmemblock(od, command->conn, offset, i, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
1798 g_free(buf);
1799 return 1;
1800 }
1801 #endif
1802
1803 pos = g_new0(struct pieceofcrap, 1);
1804 pos->gc = od->gc;
1805 pos->conn = conn;
1806
1807 pos->offset = offset;
1808 pos->len = len;
1809 pos->modname = g_strdup(modname);
1810
1811 if (purple_proxy_connect(pos->gc, pos->gc->account, "pidgin.im", 80,
1812 straight_to_hell, pos) == NULL)
1813 {
1814 char buf[256];
1815 g_free(pos->modname);
1816 g_free(pos);
1817
1818 g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly. "
1819 "If so, check %s for updates."),
1820 oscar_get_ui_info_string("website", PURPLE_WEBSITE));
1821 purple_notify_warning(pos->gc, NULL,
1822 _("Unable to get a valid login hash."),
1823 buf);
1824 }
1825
1826 return 1;
1827 }
1828
1829 int oscar_connect_to_bos(PurpleConnection *gc, OscarData *od, const char *host, guint16 port, guint8 *cookie, guint16 cookielen)
1830 {
1831 FlapConnection *conn;
1832
1833 conn = flap_connection_new(od, SNAC_FAMILY_LOCATE);
1834 conn->cookielen = cookielen;
1835 conn->cookie = g_memdup(cookie, cookielen);
1836 conn->connect_data = purple_proxy_connect(NULL,
1837 purple_connection_get_account(gc), host, port,
1838 connection_established_cb, conn);
1839 if (conn->connect_data == NULL)
1840 {
1841 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect"));
1842 return 0;
1843 }
1844
1845 od->default_port = port;
1846
1847 purple_connection_update_progress(gc, _("Received authorization"), 3, OSCAR_CONNECT_STEPS);
1848 ck[3] = 0x64;
1849
1850 return 1;
1851 }
1852
1853 /**
1854 * Only used when connecting with the old-style BUCP login.
1855 */
1607 static int 1856 static int
1608 purple_parse_auth_resp(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) 1857 purple_parse_auth_resp(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
1609 { 1858 {
1610 PurpleConnection *gc = od->gc; 1859 PurpleConnection *gc = od->gc;
1611 PurpleAccount *account = purple_connection_get_account(gc); 1860 PurpleAccount *account = purple_connection_get_account(gc);
1613 int i; 1862 int i;
1614 FlapConnection *newconn; 1863 FlapConnection *newconn;
1615 va_list ap; 1864 va_list ap;
1616 struct aim_authresp_info *info; 1865 struct aim_authresp_info *info;
1617 1866
1618 port = purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT); 1867 port = purple_account_get_int(account, "port", od->default_port);
1619 1868
1620 va_start(ap, fr); 1869 va_start(ap, fr);
1621 info = va_arg(ap, struct aim_authresp_info *); 1870 info = va_arg(ap, struct aim_authresp_info *);
1622 va_end(ap); 1871 va_end(ap);
1623 1872
1627 if (info->errorcode || !info->bosip || !info->cookielen || !info->cookie) { 1876 if (info->errorcode || !info->bosip || !info->cookielen || !info->cookie) {
1628 char buf[256]; 1877 char buf[256];
1629 switch (info->errorcode) { 1878 switch (info->errorcode) {
1630 case 0x01: 1879 case 0x01:
1631 /* Unregistered username */ 1880 /* Unregistered username */
1632 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_USERNAME, _("Invalid username.")); 1881 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_INVALID_USERNAME, _("Username does not exist"));
1633 break; 1882 break;
1634 case 0x05: 1883 case 0x05:
1635 /* Incorrect password */ 1884 /* Incorrect password */
1636 if (!purple_account_get_remember_password(account)) 1885 if (!purple_account_get_remember_password(account))
1637 purple_account_set_password(account, NULL); 1886 purple_account_set_password(account, NULL);
1638 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Incorrect password.")); 1887 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Incorrect password"));
1639 break; 1888 break;
1640 case 0x11: 1889 case 0x11:
1641 /* Suspended account */ 1890 /* Suspended account */
1642 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Your account is currently suspended.")); 1891 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Your account is currently suspended"));
1643 break; 1892 break;
1644 case 0x02: 1893 case 0x02:
1645 case 0x14: 1894 case 0x14:
1646 /* service temporarily unavailable */ 1895 /* service temporarily unavailable */
1647 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("The AOL Instant Messenger service is temporarily unavailable.")); 1896 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("The AOL Instant Messenger service is temporarily unavailable."));
1651 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); 1900 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
1652 break; 1901 break;
1653 case 0x1c: 1902 case 0x1c:
1654 { 1903 {
1655 /* client too old */ 1904 /* client too old */
1656 GHashTable *ui_info = purple_core_get_ui_info();
1657 g_snprintf(buf, sizeof(buf), _("The client version you are using is too old. Please upgrade at %s"), 1905 g_snprintf(buf, sizeof(buf), _("The client version you are using is too old. Please upgrade at %s"),
1658 ((ui_info && g_hash_table_lookup(ui_info, "website")) ? (char *)g_hash_table_lookup(ui_info, "website") : PURPLE_WEBSITE)); 1906 oscar_get_ui_info_string("website", PURPLE_WEBSITE));
1659 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, buf); 1907 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, buf);
1660 break; 1908 break;
1661 } 1909 }
1662 case 0x1d: 1910 case 0x1d:
1663 /* IP address connecting too frequently */ 1911 /* IP address connecting too frequently */
1664 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); 1912 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer."));
1665 break; 1913 break;
1666 default: 1914 default:
1667 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Authentication failed")); 1915 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("Unknown reason"));
1668 break; 1916 break;
1669 } 1917 }
1670 purple_debug_info("oscar", "Login Error Code 0x%04hx\n", info->errorcode); 1918 purple_debug_info("oscar", "Login Error Code 0x%04hx\n", info->errorcode);
1671 purple_debug_info("oscar", "Error URL: %s\n", info->errorurl ? info->errorurl : ""); 1919 purple_debug_info("oscar", "Error URL: %s\n", info->errorurl ? info->errorurl : "");
1672 return 1; 1920 return 1;
1709 } 1957 }
1710 1958
1711 g_free(host); 1959 g_free(host);
1712 if (newconn->connect_data == NULL) 1960 if (newconn->connect_data == NULL)
1713 { 1961 {
1714 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Could Not Connect")); 1962 purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Unable to connect"));
1715 return 0; 1963 return 0;
1716 } 1964 }
1717 1965
1718 purple_connection_update_progress(gc, _("Received authorization"), 3, OSCAR_CONNECT_STEPS); 1966 purple_connection_update_progress(gc, _("Received authorization"), 3, OSCAR_CONNECT_STEPS);
1719 ck[3] = 0x64; 1967 ck[3] = 0x64;
1720 1968
1721 return 1; 1969 return 1;
1722 } 1970 }
1723 1971
1972 /**
1973 * Only used when connecting with the old-style BUCP login.
1974 */
1724 static void 1975 static void
1725 purple_parse_auth_securid_request_yes_cb(gpointer user_data, const char *msg) 1976 purple_parse_auth_securid_request_yes_cb(gpointer user_data, const char *msg)
1726 { 1977 {
1727 PurpleConnection *gc = user_data; 1978 PurpleConnection *gc = user_data;
1728 OscarData *od = purple_connection_get_protocol_data(gc); 1979 OscarData *od = purple_connection_get_protocol_data(gc);
1729 1980
1730 aim_auth_securid_send(od, msg); 1981 aim_auth_securid_send(od, msg);
1731 } 1982 }
1732 1983
1984 /**
1985 * Only used when connecting with the old-style BUCP login.
1986 */
1733 static void 1987 static void
1734 purple_parse_auth_securid_request_no_cb(gpointer user_data, const char *value) 1988 purple_parse_auth_securid_request_no_cb(gpointer user_data, const char *value)
1735 { 1989 {
1736 PurpleConnection *gc = user_data; 1990 PurpleConnection *gc = user_data;
1737 1991
1738 /* Disconnect */ 1992 /* Disconnect */
1739 purple_connection_error_reason(gc, 1993 purple_connection_error_reason(gc,
1740 PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, 1994 PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1741 _("The SecurID key entered is invalid.")); 1995 _("The SecurID key entered is invalid"));
1742 } 1996 }
1743 1997
1998 /**
1999 * Only used when connecting with the old-style BUCP login.
2000 */
1744 static int 2001 static int
1745 purple_parse_auth_securid_request(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) 2002 purple_parse_auth_securid_request(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
1746 { 2003 {
1747 PurpleConnection *gc = od->gc; 2004 PurpleConnection *gc = od->gc;
1748 PurpleAccount *account = purple_connection_get_account(gc); 2005 PurpleAccount *account = purple_connection_get_account(gc);
1761 g_free(primary); 2018 g_free(primary);
1762 2019
1763 return 1; 2020 return 1;
1764 } 2021 }
1765 2022
1766 /* XXX - Should use purple_util_fetch_url for the below stuff */ 2023 /**
1767 struct pieceofcrap { 2024 * Only used when connecting with the old-style BUCP login.
1768 PurpleConnection *gc; 2025 */
1769 unsigned long offset;
1770 unsigned long len;
1771 char *modname;
1772 int fd;
1773 FlapConnection *conn;
1774 unsigned int inpa;
1775 };
1776
1777 static void damn_you(gpointer data, gint source, PurpleInputCondition c)
1778 {
1779 struct pieceofcrap *pos = data;
1780 OscarData *od = purple_connection_get_protocol_data(pos->gc);
1781 char in = '\0';
1782 int x = 0;
1783 unsigned char m[17];
1784 GString *msg;
1785
1786 while (read(pos->fd, &in, 1) == 1) {
1787 if (in == '\n')
1788 x++;
1789 else if (in != '\r')
1790 x = 0;
1791 if (x == 2)
1792 break;
1793 in = '\0';
1794 }
1795 if (in != '\n') {
1796 char buf[256];
1797 GHashTable *ui_info = purple_core_get_ui_info();
1798 g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly. "
1799 "If so, check %s for updates."),
1800 ((ui_info && g_hash_table_lookup(ui_info, "website")) ? (char *)g_hash_table_lookup(ui_info, "website") : PURPLE_WEBSITE));
1801 purple_notify_warning(pos->gc, NULL,
1802 _("Unable to get a valid AIM login hash."),
1803 buf);
1804 purple_input_remove(pos->inpa);
1805 close(pos->fd);
1806 g_free(pos);
1807 return;
1808 }
1809 if (read(pos->fd, m, 16) != 16)
1810 {
1811 purple_debug_warning("oscar", "Could not read full AIM login hash "
1812 "from " AIMHASHDATA "--that's bad.\n");
1813 }
1814 m[16] = '\0';
1815
1816 msg = g_string_new("Sending hash: ");
1817 for (x = 0; x < 16; x++)
1818 g_string_append_printf(msg, "%02hhx ", (unsigned char)m[x]);
1819 g_string_append(msg, "\n");
1820 purple_debug_misc("oscar", "%s", msg->str);
1821 g_string_free(msg, TRUE);
1822
1823 purple_input_remove(pos->inpa);
1824 close(pos->fd);
1825 aim_sendmemblock(od, pos->conn, 0, 16, m, AIM_SENDMEMBLOCK_FLAG_ISHASH);
1826 g_free(pos);
1827 }
1828
1829 static void
1830 straight_to_hell(gpointer data, gint source, const gchar *error_message)
1831 {
1832 struct pieceofcrap *pos = data;
1833 gchar *buf;
1834 gssize result;
1835
1836 if (!PURPLE_CONNECTION_IS_VALID(pos->gc))
1837 {
1838 g_free(pos->modname);
1839 g_free(pos);
1840 return;
1841 }
1842
1843 pos->fd = source;
1844
1845 if (source < 0) {
1846 GHashTable *ui_info = purple_core_get_ui_info();
1847 buf = g_strdup_printf(_("You may be disconnected shortly. "
1848 "Check %s for updates."),
1849 ((ui_info && g_hash_table_lookup(ui_info, "website")) ? (char *)g_hash_table_lookup(ui_info, "website") : PURPLE_WEBSITE));
1850 purple_notify_warning(pos->gc, NULL,
1851 _("Unable to get a valid AIM login hash."),
1852 buf);
1853 g_free(buf);
1854 g_free(pos->modname);
1855 g_free(pos);
1856 return;
1857 }
1858
1859 buf = g_strdup_printf("GET " AIMHASHDATA "?offset=%ld&len=%ld&modname=%s HTTP/1.0\n\n",
1860 pos->offset, pos->len, pos->modname ? pos->modname : "");
1861 result = send(pos->fd, buf, strlen(buf), 0);
1862 if (result != strlen(buf)) {
1863 if (result < 0)
1864 purple_debug_error("oscar", "Error writing %" G_GSIZE_FORMAT
1865 " bytes to fetch AIM hash data: %s\n",
1866 strlen(buf), g_strerror(errno));
1867 else
1868 purple_debug_error("oscar", "Tried to write %"
1869 G_GSIZE_FORMAT " bytes to fetch AIM hash data but "
1870 "instead wrote %" G_GSSIZE_FORMAT " bytes\n",
1871 strlen(buf), result);
1872 }
1873 g_free(buf);
1874 g_free(pos->modname);
1875 pos->inpa = purple_input_add(pos->fd, PURPLE_INPUT_READ, damn_you, pos);
1876 return;
1877 }
1878
1879 /* size of icbmui.ocm, the largest module in AIM 3.5 */
1880 #define AIM_MAX_FILE_SIZE 98304
1881
1882 int purple_memrequest(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
1883 va_list ap;
1884 struct pieceofcrap *pos;
1885 guint32 offset, len;
1886 char *modname;
1887
1888 va_start(ap, fr);
1889 offset = va_arg(ap, guint32);
1890 len = va_arg(ap, guint32);
1891 modname = va_arg(ap, char *);
1892 va_end(ap);
1893
1894 purple_debug_misc("oscar", "offset: %u, len: %u, file: %s\n",
1895 offset, len, (modname ? modname : "aim.exe"));
1896
1897 if (len == 0) {
1898 purple_debug_misc("oscar", "len is 0, hashing NULL\n");
1899 aim_sendmemblock(od, conn, offset, len, NULL,
1900 AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
1901 return 1;
1902 }
1903 /* uncomment this when you're convinced it's right. remember, it's been wrong before. */
1904 #if 0
1905 if (offset > AIM_MAX_FILE_SIZE || len > AIM_MAX_FILE_SIZE) {
1906 char *buf;
1907 int i = 8;
1908 if (modname)
1909 i += strlen(modname);
1910 buf = g_malloc(i);
1911 i = 0;
1912 if (modname) {
1913 memcpy(buf, modname, strlen(modname));
1914 i += strlen(modname);
1915 }
1916 buf[i++] = offset & 0xff;
1917 buf[i++] = (offset >> 8) & 0xff;
1918 buf[i++] = (offset >> 16) & 0xff;
1919 buf[i++] = (offset >> 24) & 0xff;
1920 buf[i++] = len & 0xff;
1921 buf[i++] = (len >> 8) & 0xff;
1922 buf[i++] = (len >> 16) & 0xff;
1923 buf[i++] = (len >> 24) & 0xff;
1924 purple_debug_misc("oscar", "len + offset is invalid, "
1925 "hashing request\n");
1926 aim_sendmemblock(od, command->conn, offset, i, buf, AIM_SENDMEMBLOCK_FLAG_ISREQUEST);
1927 g_free(buf);
1928 return 1;
1929 }
1930 #endif
1931
1932 pos = g_new0(struct pieceofcrap, 1);
1933 pos->gc = od->gc;
1934 pos->conn = conn;
1935
1936 pos->offset = offset;
1937 pos->len = len;
1938 pos->modname = g_strdup(modname);
1939
1940 /* TODO: Keep track of this return value. */
1941 if (purple_proxy_connect(NULL, pos->gc->account, "pidgin.im", 80,
1942 straight_to_hell, pos) == NULL)
1943 {
1944 char buf[256];
1945 GHashTable *ui_info = purple_core_get_ui_info();
1946 g_free(pos->modname);
1947 g_free(pos);
1948
1949 g_snprintf(buf, sizeof(buf), _("You may be disconnected shortly. "
1950 "Check %s for updates."),
1951 ((ui_info && g_hash_table_lookup(ui_info, "website")) ? (char *)g_hash_table_lookup(ui_info, "website") : PURPLE_WEBSITE));
1952 purple_notify_warning(pos->gc, NULL,
1953 _("Unable to get a valid login hash."),
1954 buf);
1955 }
1956
1957 return 1;
1958 }
1959
1960 static int 2026 static int
1961 purple_parse_login(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) 2027 purple_parse_login(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
1962 { 2028 {
1963 PurpleConnection *gc; 2029 PurpleConnection *gc;
1964 PurpleAccount *account; 2030 PurpleAccount *account;
2000 2066
2001 va_start(ap, fr); 2067 va_start(ap, fr);
2002 redir = va_arg(ap, struct aim_redirect_data *); 2068 redir = va_arg(ap, struct aim_redirect_data *);
2003 va_end(ap); 2069 va_end(ap);
2004 2070
2005 port = purple_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT); 2071 port = od->default_port;
2006 separator = strchr(redir->ip, ':'); 2072 separator = strchr(redir->ip, ':');
2007 if (separator != NULL) 2073 if (separator != NULL)
2008 { 2074 {
2009 host = g_strndup(redir->ip, separator - redir->ip); 2075 host = g_strndup(redir->ip, separator - redir->ip);
2010 port = atoi(separator + 1); 2076 port = atoi(separator + 1);
2150 if (info->status != NULL && info->status[0] != '\0') 2216 if (info->status != NULL && info->status[0] != '\0')
2151 /* Grab the available message */ 2217 /* Grab the available message */
2152 message = oscar_encoding_to_utf8(account, info->status_encoding, 2218 message = oscar_encoding_to_utf8(account, info->status_encoding,
2153 info->status, info->status_len); 2219 info->status, info->status_len);
2154 2220
2155 tmp2 = tmp = (message ? g_markup_escape_text(message, -1) : NULL); 2221 tmp2 = tmp = (message ? purple_markup_escape_text(message, -1) : NULL);
2156 2222
2157 if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0) { 2223 if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0) {
2158 if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len) 2224 if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len)
2159 /* Grab the iTunes Music Store URL */ 2225 /* Grab the iTunes Music Store URL */
2160 itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding, 2226 itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding,
2833 gchar *uin = NULL, *message = NULL; 2899 gchar *uin = NULL, *message = NULL;
2834 2900
2835 /* From libicq2000-0.3.2/src/ICQ.cpp */ 2901 /* From libicq2000-0.3.2/src/ICQ.cpp */
2836 byte_stream_init(&qbs, (guint8 *)args->msg, args->msglen); 2902 byte_stream_init(&qbs, (guint8 *)args->msg, args->msglen);
2837 byte_stream_advance(&qbs, 21); 2903 byte_stream_advance(&qbs, 21);
2904 /* expected: 01 00 00 20 00 0e 28 f6 00 11 e7 d3 11 bc f3 00 04 ac 96 9d c2 | 00 00 | 06 00 00 00 | 49 43 51 53 43 53 ...*/
2905 /* unexpected: 00 00 26 00 81 1a 18 bc 0e 6c 18 47 a5 91 6f 18 dc c7 6f 1a | 00 00 | 0d 00 00 00 | 49 43 51 57 65 62 4d 65 73 73 61 67 65 ... */
2838 smstype = byte_stream_getle16(&qbs); 2906 smstype = byte_stream_getle16(&qbs);
2907 if (smstype != 0)
2908 break;
2839 taglen = byte_stream_getle32(&qbs); 2909 taglen = byte_stream_getle32(&qbs);
2840 tagstr = byte_stream_getstr(&qbs, taglen); 2910 tagstr = byte_stream_getstr(&qbs, taglen);
2911 if (tagstr == NULL)
2912 break;
2841 byte_stream_advance(&qbs, 3); 2913 byte_stream_advance(&qbs, 3);
2842 byte_stream_advance(&qbs, 4); 2914 byte_stream_advance(&qbs, 4);
2843 smslen = byte_stream_getle32(&qbs); 2915 smslen = byte_stream_getle32(&qbs);
2844 smsmsg = byte_stream_getstr(&qbs, smslen); 2916 smsmsg = byte_stream_getstr(&qbs, smslen);
2845 2917
3853 3925
3854 static int purple_bosrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) { 3926 static int purple_bosrights(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) {
3855 PurpleConnection *gc; 3927 PurpleConnection *gc;
3856 PurpleAccount *account; 3928 PurpleAccount *account;
3857 PurpleStatus *status; 3929 PurpleStatus *status;
3930 gboolean is_available;
3858 PurplePresence *presence; 3931 PurplePresence *presence;
3859 const char *username, *message, *itmsurl; 3932 const char *username, *message, *itmsurl;
3860 char *tmp; 3933 char *tmp;
3861 va_list ap; 3934 va_list ap;
3862 guint16 maxpermits, maxdenies; 3935 guint16 maxpermits, maxdenies;
3893 */ 3966 */
3894 oscar_format_username(gc, username); 3967 oscar_format_username(gc, username);
3895 3968
3896 /* Set our available message based on the current status */ 3969 /* Set our available message based on the current status */
3897 status = purple_account_get_active_status(account); 3970 status = purple_account_get_active_status(account);
3898 if (purple_status_is_available(status)) 3971 is_available = purple_status_is_available(status);
3972 if (is_available)
3899 message = purple_status_get_attr_string(status, "message"); 3973 message = purple_status_get_attr_string(status, "message");
3900 else 3974 else
3901 message = NULL; 3975 message = NULL;
3902 tmp = purple_markup_strip_html(message); 3976 tmp = purple_markup_strip_html(message);
3903 itmsurl = purple_status_get_attr_string(status, "itmsurl"); 3977 itmsurl = purple_status_get_attr_string(status, "itmsurl");
3904 aim_srv_setextrainfo(od, FALSE, 0, TRUE, tmp, itmsurl); 3978 aim_srv_setextrainfo(od, FALSE, 0, is_available, tmp, itmsurl);
3905 g_free(tmp); 3979 g_free(tmp);
3906 3980
3907 presence = purple_status_get_presence(status); 3981 presence = purple_status_get_presence(status);
3908 aim_srv_setidle(od, !purple_presence_is_idle(presence) ? 0 : time(NULL) - purple_presence_get_idle_time(presence)); 3982 aim_srv_setidle(od, !purple_presence_is_idle(presence) ? 0 : time(NULL) - purple_presence_get_idle_time(presence));
3909 3983
3918 aim_icq_setsecurity(od, 3992 aim_icq_setsecurity(od,
3919 purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION), 3993 purple_account_get_bool(account, "authorization", OSCAR_DEFAULT_AUTHORIZATION),
3920 purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE)); 3994 purple_account_get_bool(account, "web_aware", OSCAR_DEFAULT_WEB_AWARE));
3921 } 3995 }
3922 3996
3997 aim_srv_requestnew(od, SNAC_FAMILY_ALERT);
3923 aim_srv_requestnew(od, SNAC_FAMILY_CHATNAV); 3998 aim_srv_requestnew(od, SNAC_FAMILY_CHATNAV);
3924
3925 /*
3926 * The "if" statement here is a pathetic attempt to not attempt to
3927 * connect to the alerts servce (aka email notification) if this
3928 * username does not support it. I think mail notification
3929 * works for @mac.com accounts but does not work for the newer
3930 * @anythingelse.com accounts. If that's true then this change
3931 * breaks mail notification for @mac.com accounts, but it gets rid
3932 * of an annoying error at signon for @anythingelse.com accounts.
3933 */
3934 if (od->authinfo->email != NULL && strchr(username, '@') == NULL)
3935 aim_srv_requestnew(od, SNAC_FAMILY_ALERT);
3936 3999
3937 return 1; 4000 return 1;
3938 } 4001 }
3939 4002
3940 #ifdef OLDSTYLE_ICQ_OFFLINEMSGS 4003 #ifdef OLDSTYLE_ICQ_OFFLINEMSGS
4434 msg = g_string_append_len(msg, data->str, data->len); 4497 msg = g_string_append_len(msg, data->str, data->len);
4435 msg = g_string_append(msg, "</BINARY>"); 4498 msg = g_string_append(msg, "</BINARY>");
4436 } 4499 }
4437 g_string_free(data, TRUE); 4500 g_string_free(data, TRUE);
4438 4501
4439 peer_odc_send_im(conn, msg->str, msg->len, charset, (imflags & PURPLE_MESSAGE_AUTO_RESP)); 4502 peer_odc_send_im(conn, msg->str, msg->len, charset,
4503 imflags & PURPLE_MESSAGE_AUTO_RESP);
4440 g_string_free(msg, TRUE); 4504 g_string_free(msg, TRUE);
4441 } 4505 }
4442 4506
4443 int 4507 int
4444 oscar_send_im(PurpleConnection *gc, const char *name, const char *message, PurpleMessageFlags imflags) 4508 oscar_send_im(PurpleConnection *gc, const char *name, const char *message, PurpleMessageFlags imflags)
4908 bname = purple_buddy_get_name(buddy); 4972 bname = purple_buddy_get_name(buddy);
4909 gname = purple_group_get_name(group); 4973 gname = purple_group_get_name(group);
4910 4974
4911 if (!oscar_util_valid_name(bname)) { 4975 if (!oscar_util_valid_name(bname)) {
4912 gchar *buf; 4976 gchar *buf;
4913 buf = g_strdup_printf(_("Could not add the buddy %s because the username is invalid. Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), bname); 4977 buf = g_strdup_printf(_("Unable to add the buddy %s because the username is invalid. Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), bname);
4914 if (!purple_conv_present_error(bname, account, buf)) 4978 if (!purple_conv_present_error(bname, account, buf))
4915 purple_notify_error(gc, NULL, _("Unable to Add"), buf); 4979 purple_notify_error(gc, NULL, _("Unable to Add"), buf);
4916 g_free(buf); 4980 g_free(buf);
4917 4981
4918 /* Remove from local list */ 4982 /* Remove from local list */
5393 case 0x0000: { /* added successfully */ 5457 case 0x0000: { /* added successfully */
5394 } break; 5458 } break;
5395 5459
5396 case 0x000c: { /* you are over the limit, the cheat is to the limit, come on fhqwhgads */ 5460 case 0x000c: { /* you are over the limit, the cheat is to the limit, come on fhqwhgads */
5397 gchar *buf; 5461 gchar *buf;
5398 buf = g_strdup_printf(_("Could not add the buddy %s because you have too many buddies in your buddy list. Please remove one and try again."), (retval->name ? retval->name : _("(no name)"))); 5462 buf = g_strdup_printf(_("Unable to add the buddy %s because you have too many buddies in your buddy list. Please remove one and try again."), (retval->name ? retval->name : _("(no name)")));
5399 if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf)) 5463 if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf))
5400 purple_notify_error(gc, NULL, _("Unable to Add"), buf); 5464 purple_notify_error(gc, NULL, _("Unable to Add"), buf);
5401 g_free(buf); 5465 g_free(buf);
5402 } 5466 }
5403 5467
5407 } break; 5471 } break;
5408 5472
5409 default: { /* La la la */ 5473 default: { /* La la la */
5410 gchar *buf; 5474 gchar *buf;
5411 purple_debug_error("oscar", "ssi: Action 0x%04hx was unsuccessful with error 0x%04hx\n", retval->action, retval->ack); 5475 purple_debug_error("oscar", "ssi: Action 0x%04hx was unsuccessful with error 0x%04hx\n", retval->action, retval->ack);
5412 buf = g_strdup_printf(_("Could not add the buddy %s for an unknown reason."), 5476 buf = g_strdup_printf(_("Unable to add the buddy %s for an unknown reason."),
5413 (retval->name ? retval->name : _("(no name)"))); 5477 (retval->name ? retval->name : _("(no name)")));
5414 if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf)) 5478 if ((retval->name != NULL) && !purple_conv_present_error(retval->name, purple_connection_get_account(gc), buf))
5415 purple_notify_error(gc, NULL, _("Unable to Add"), buf); 5479 purple_notify_error(gc, NULL, _("Unable to Add"), buf);
5416 g_free(buf); 5480 g_free(buf);
5417 } break; 5481 } break;
6382 #endif 6446 #endif
6383 } 6447 }
6384 6448
6385 if (od->ssi.received_data && purple_buddy_get_group(buddy) != NULL) 6449 if (od->ssi.received_data && purple_buddy_get_group(buddy) != NULL)
6386 { 6450 {
6451 /*
6452 * We only do this if the user is in our buddy list and we're
6453 * waiting for authorization.
6454 */
6387 char *gname; 6455 char *gname;
6388 gname = aim_ssi_itemlist_findparentname(od->ssi.local, bname); 6456 gname = aim_ssi_itemlist_findparentname(od->ssi.local, bname);
6389 if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, bname)) 6457 if (gname && aim_ssi_waitingforauth(od->ssi.local, gname, bname))
6390 { 6458 {
6391 act = purple_menu_action_new(_("Re-request Authorization"), 6459 act = purple_menu_action_new(_("Re-request Authorization"),
6461 _("Cancel"), NULL, 6529 _("Cancel"), NULL,
6462 purple_connection_get_account(gc), NULL, NULL, 6530 purple_connection_get_account(gc), NULL, NULL,
6463 gc); 6531 gc);
6464 } 6532 }
6465 6533
6466 static void oscar_format_username(PurpleConnection *gc, const char *nick) { 6534 void oscar_format_username(PurpleConnection *gc, const char *nick) {
6467 OscarData *od = purple_connection_get_protocol_data(gc); 6535 OscarData *od = purple_connection_get_protocol_data(gc);
6468 if (!oscar_util_name_compare(purple_account_get_username(purple_connection_get_account(gc)), nick)) { 6536 if (!oscar_util_name_compare(purple_account_get_username(purple_connection_get_account(gc)), nick)) {
6469 if (!flap_connection_getbytype(od, SNAC_FAMILY_ADMIN)) { 6537 if (!flap_connection_getbytype(od, SNAC_FAMILY_ADMIN)) {
6470 od->setnick = TRUE; 6538 od->setnick = TRUE;
6471 g_free(od->newformatting); 6539 g_free(od->newformatting);
6622 { 6690 {
6623 PurpleConnection *gc = (PurpleConnection *) action->context; 6691 PurpleConnection *gc = (PurpleConnection *) action->context;
6624 purple_account_request_change_password(purple_connection_get_account(gc)); 6692 purple_account_request_change_password(purple_connection_get_account(gc));
6625 } 6693 }
6626 6694
6695 /**
6696 * Only used when connecting with the old-style BUCP login.
6697 */
6627 static void oscar_show_chpassurl(PurplePluginAction *action) 6698 static void oscar_show_chpassurl(PurplePluginAction *action)
6628 { 6699 {
6629 PurpleConnection *gc = (PurpleConnection *) action->context; 6700 PurpleConnection *gc = (PurpleConnection *) action->context;
6630 OscarData *od = purple_connection_get_protocol_data(gc); 6701 OscarData *od = purple_connection_get_protocol_data(gc);
6631 gchar *substituted = purple_strreplace(od->authinfo->chpassurl, "%s", purple_account_get_username(purple_connection_get_account(gc))); 6702 gchar *substituted = purple_strreplace(od->authinfo->chpassurl, "%s", purple_account_get_username(purple_connection_get_account(gc)));
6762 6833
6763 act = purple_plugin_action_new(_("Change Password..."), 6834 act = purple_plugin_action_new(_("Change Password..."),
6764 oscar_change_pass); 6835 oscar_change_pass);
6765 menu = g_list_prepend(menu, act); 6836 menu = g_list_prepend(menu, act);
6766 6837
6767 if (od->authinfo->chpassurl != NULL) 6838 if (od->authinfo != NULL && od->authinfo->chpassurl != NULL)
6768 { 6839 {
6840 /* This only happens when connecting with the old-style BUCP login */
6769 act = purple_plugin_action_new(_("Change Password (web)"), 6841 act = purple_plugin_action_new(_("Change Password (web)"),
6770 oscar_show_chpassurl); 6842 oscar_show_chpassurl);
6771 menu = g_list_prepend(menu, act); 6843 menu = g_list_prepend(menu, act);
6772 6844 }
6845
6846 if (!od->icq)
6847 {
6773 act = purple_plugin_action_new(_("Configure IM Forwarding (web)"), 6848 act = purple_plugin_action_new(_("Configure IM Forwarding (web)"),
6774 oscar_show_imforwardingurl); 6849 oscar_show_imforwardingurl);
6775 menu = g_list_prepend(menu, act); 6850 menu = g_list_prepend(menu, act);
6776 } 6851 }
6777 6852
7004 7079
7005 option = purple_account_option_bool_new(_("Use SSL"), "use_ssl", 7080 option = purple_account_option_bool_new(_("Use SSL"), "use_ssl",
7006 OSCAR_DEFAULT_USE_SSL); 7081 OSCAR_DEFAULT_USE_SSL);
7007 prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); 7082 prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
7008 7083
7084 option = purple_account_option_bool_new(_("Use clientLogin"), "use_clientlogin",
7085 OSCAR_DEFAULT_USE_CLIENTLOGIN);
7086 prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
7087
7009 option = purple_account_option_bool_new( 7088 option = purple_account_option_bool_new(
7010 _("Always use AIM/ICQ proxy server for\nfile transfers and direct IM (slower,\nbut does not reveal your IP address)"), "always_use_rv_proxy", 7089 _("Always use AIM/ICQ proxy server for\nfile transfers and direct IM (slower,\nbut does not reveal your IP address)"), "always_use_rv_proxy",
7011 OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY); 7090 OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY);
7012 prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option); 7091 prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, option);
7013 7092
7021 7100
7022 /* Preferences */ 7101 /* Preferences */
7023 purple_prefs_add_none("/plugins/prpl/oscar"); 7102 purple_prefs_add_none("/plugins/prpl/oscar");
7024 purple_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE); 7103 purple_prefs_add_bool("/plugins/prpl/oscar/recent_buddies", FALSE);
7025 7104
7026 /*
7027 * These two preferences will normally not be changed. UIs can optionally
7028 * use them to override these two version fields which are sent to the
7029 * server when logging in. AOL requested this change to allow clients to
7030 * use custom values.
7031 */
7032 purple_prefs_add_string("/plugins/prpl/oscar/clientstring", NULL);
7033 purple_prefs_add_int("/plugins/prpl/oscar/distid", -1);
7034
7035 purple_prefs_remove("/plugins/prpl/oscar/show_idle"); 7105 purple_prefs_remove("/plugins/prpl/oscar/show_idle");
7036 purple_prefs_remove("/plugins/prpl/oscar/always_use_rv_proxy"); 7106 purple_prefs_remove("/plugins/prpl/oscar/always_use_rv_proxy");
7037 7107
7038 /* protocol handler */ 7108 /* protocol handler */
7039 /* TODO: figure out a good instance to use here */ 7109 /* TODO: figure out a good instance to use here */