1546
|
1 /*
|
|
2 * libyay
|
|
3 *
|
|
4 * Copyright (C) 2001 Eric Warmenhoven <warmenhoven@yahoo.com>
|
|
5 *
|
|
6 * This program is free software; you can redistribute it and/or modify
|
|
7 * it under the terms of the GNU General Public License as published by
|
|
8 * the Free Software Foundation; either version 2 of the License, or
|
|
9 * (at your option) any later version.
|
|
10 *
|
|
11 * This program is distributed in the hope that it will be useful,
|
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 * GNU General Public License for more details.
|
|
15 *
|
|
16 * You should have received a copy of the GNU General Public License
|
|
17 * along with this program; if not, write to the Free Software
|
|
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
19 *
|
|
20 */
|
|
21
|
|
22 #include "internal.h"
|
|
23 #include <string.h>
|
|
24 #include <stdlib.h>
|
|
25 #include <ctype.h>
|
|
26
|
|
27 static int yahoo_parse_config(struct yahoo_session *session, struct yahoo_conn *conn, char *buf)
|
|
28 {
|
|
29 char **str_array = g_strsplit(buf, "\n", 1024);
|
|
30 char **it;
|
|
31 int state = 0;
|
|
32
|
|
33 for (it = str_array; *it; it++) {
|
|
34 if (!strncmp(*it, "ERROR", strlen("ERROR"))) {
|
|
35 yahoo_close(session, conn);
|
|
36 CALLBACK(session, YAHOO_HANDLE_BADPASSWORD);
|
|
37 return 1;
|
|
38 } else if (!strncmp(*it, "Set-Cookie: ", strlen("Set-Cookie: "))) {
|
|
39 char **sa;
|
|
40 char **m;
|
|
41
|
|
42 char *end = strchr(*it, ';');
|
|
43 if (session->cookie)
|
|
44 g_free(session->cookie);
|
|
45 session->cookie = g_strndup(*it + strlen("Set-Cookie: "),
|
|
46 end - *it - strlen("Set-Cookie: "));
|
|
47 YAHOO_PRINT(session, YAHOO_LOG_DEBUG, session->cookie);
|
|
48 if (!session->cookie) {
|
|
49 yahoo_close(session, conn);
|
|
50 CALLBACK(session, YAHOO_HANDLE_DISCONNECT);
|
|
51 return 1;
|
|
52 }
|
|
53
|
|
54 sa = g_strsplit(session->cookie, "&", 8);
|
|
55 for (m = sa; *m; m++) {
|
|
56 if (!strncmp(*m, "n=", 2)) {
|
|
57 if (session->login_cookie)
|
|
58 g_free(session->login_cookie);
|
|
59 session->login_cookie = g_strdup(*m + 2);
|
|
60 YAHOO_PRINT(session, YAHOO_LOG_DEBUG, session->login_cookie);
|
|
61 }
|
|
62 }
|
|
63 g_strfreev(sa);
|
|
64 } else if (!strncmp(*it, "BEGIN BUDDYLIST", strlen("BEGIN BUDDYLIST"))) {
|
|
65 state = 1;
|
|
66 } else if (!strncmp(*it, "END BUDDYLIST", strlen("END BUDDYLIST"))) {
|
|
67 state = 0;
|
|
68 } else if (!strncmp(*it, "BEGIN IGNORELIST", strlen("BEGIN IGNORELIST"))) {
|
|
69 state = 2;
|
|
70 } else if (!strncmp(*it, "END IGNORELIST", strlen("END IGNORELIST"))) {
|
|
71 state = 0;
|
|
72 } else if (!strncmp(*it, "BEGIN IDENTITIES", strlen("BEGIN IDENTITIES"))) {
|
|
73 state = 3;
|
|
74 } else if (!strncmp(*it, "END IDENTITIES", strlen("END IDENTITIES"))) {
|
|
75 state = 0;
|
|
76 } else if (!strncmp(*it, "Mail=", strlen("Mail="))) {
|
|
77 session->mail = atoi(*it + strlen("Mail="));
|
|
78 } else if (!strncmp(*it, "Login=", strlen("Login="))) {
|
|
79 if (session->login)
|
|
80 g_free(session->login);
|
|
81 session->login = g_strdup(*it + strlen("Login="));
|
|
82 } else {
|
|
83 if (state == 1) {
|
|
84 struct yahoo_group *grp = g_new0(struct yahoo_group, 1);
|
|
85 char *end = strchr(*it, ':');
|
|
86 grp->name = g_strndup(*it, end - *it);
|
|
87 end++;
|
|
88 grp->buddies = g_strsplit(end, ",", 1024);
|
|
89 session->groups = g_list_append(session->groups, grp);
|
|
90 } else if (state == 2) {
|
|
91 session->ignored = g_list_append(session->ignored, g_strdup(*it));
|
|
92 } else if (state == 3) {
|
|
93 session->identities = g_strsplit(*it, ",", 6);
|
|
94 }
|
|
95 }
|
|
96 }
|
|
97
|
|
98 g_strfreev(str_array);
|
|
99 yahoo_close(session, conn);
|
|
100 CALLBACK(session, YAHOO_HANDLE_LOGINCOOKIE);
|
|
101 return 0;
|
|
102 }
|
|
103
|
|
104 static void yahoo_parse_status(struct yahoo_session *sess, struct yahoo_packet *pkt)
|
|
105 {
|
|
106 char *tmp = pkt->content;
|
|
107 int count = 0;
|
|
108 char **strs;
|
|
109 int i;
|
|
110
|
|
111 YAHOO_PRINT(sess, YAHOO_LOG_DEBUG, pkt->content);
|
|
112
|
|
113 if (strstr(pkt->content, "was not AWAY"))
|
|
114 return;
|
|
115
|
|
116 while (*tmp && isdigit((int)*tmp))
|
|
117 count = count * 10 + *tmp++ - '0';
|
|
118 if (*tmp == ',')
|
|
119 tmp++;
|
|
120 count = count ? count : 1;
|
|
121
|
|
122 if (count > 1)
|
|
123 strs = g_strsplit(tmp, "),", count);
|
|
124 else
|
|
125 strs = g_strsplit(tmp, ")", count);
|
|
126
|
|
127 for (i = 0; i < count && strs[i]; i++) {
|
|
128 char **vals;
|
|
129 char *end, *who;
|
|
130 char **it;
|
|
131 int c, j;
|
|
132
|
|
133 who = strs[i];
|
|
134 end = strchr(who, '(');
|
|
135 *end++ = '\0';
|
|
136
|
|
137 vals = g_strsplit(end, ",", 1024);
|
|
138
|
|
139 for (it = vals, c = 0; *it; it++, c++);
|
|
140 if (c > 6)
|
|
141 end = g_strdup(vals[1]);
|
|
142 for (j = 2; j < c - 5; j++) {
|
|
143 char *x = end;
|
|
144 end = g_strconcat(end, ",", vals[j], NULL);
|
|
145 g_free(x);
|
|
146 }
|
|
147
|
|
148 CALLBACK(sess, YAHOO_HANDLE_STATUS, who, atoi(vals[0]), end,
|
|
149 atoi(vals[c - 3]), atoi(vals[c - 2]), atoi(vals[c - 1]));
|
|
150
|
|
151 if (c > 6)
|
|
152 g_free(end);
|
|
153 g_strfreev(vals);
|
|
154 }
|
|
155
|
|
156 g_strfreev(strs);
|
|
157 }
|
|
158
|
|
159 static void yahoo_parse_message(struct yahoo_session *sess, struct yahoo_packet *pkt)
|
|
160 {
|
|
161 char buf[256];
|
|
162 int type = yahoo_makeint(pkt->msgtype);
|
|
163 char **str_array;
|
|
164 switch(type) {
|
|
165 case YAHOO_MESSAGE_NORMAL:
|
|
166 str_array = g_strsplit(pkt->content, ",,", 2);
|
|
167 CALLBACK(sess, YAHOO_HANDLE_MESSAGE, pkt->nick2, str_array[0], str_array[1]);
|
|
168 g_strfreev(str_array);
|
|
169 break;
|
|
170 default:
|
|
171 g_snprintf(buf, sizeof(buf), "unhandled message type %d: %s", type, pkt->content);
|
|
172 YAHOO_PRINT(sess, YAHOO_LOG_WARNING, buf);
|
|
173 break;
|
|
174 }
|
|
175 }
|
|
176
|
|
177 static void yahoo_parse_packet(struct yahoo_session *sess,
|
|
178 struct yahoo_conn *conn, struct yahoo_packet *pkt)
|
|
179 {
|
|
180 char buf[256];
|
|
181 int service = yahoo_makeint(pkt->service);
|
|
182 conn->magic_id = yahoo_makeint(pkt->magic_id);
|
|
183 g_snprintf(buf, sizeof(buf), "Service %d (msgtype %d)", service, yahoo_makeint(pkt->msgtype));
|
|
184 YAHOO_PRINT(sess, YAHOO_LOG_DEBUG, buf);
|
|
185 switch(service) {
|
|
186 case YAHOO_SERVICE_LOGON:
|
|
187 if (yahoo_makeint(pkt->msgtype) == 0)
|
|
188 CALLBACK(sess, YAHOO_HANDLE_ONLINE);
|
|
189 case YAHOO_SERVICE_LOGOFF:
|
|
190 case YAHOO_SERVICE_ISAWAY:
|
|
191 case YAHOO_SERVICE_ISBACK:
|
|
192 yahoo_parse_status(sess, pkt);
|
|
193 break;
|
|
194 case YAHOO_SERVICE_IDACT:
|
|
195 CALLBACK(sess, YAHOO_HANDLE_ACTIVATE, pkt->content);
|
|
196 break;
|
|
197 case YAHOO_SERVICE_MESSAGE:
|
|
198 yahoo_parse_message(sess, pkt);
|
|
199 break;
|
|
200 case YAHOO_SERVICE_NEWMAIL:
|
|
201 CALLBACK(sess, YAHOO_HANDLE_NEWMAIL, strlen(pkt->content) ? atoi(pkt->content) : 0);
|
|
202 break;
|
|
203 default:
|
|
204 g_snprintf(buf, sizeof(buf), "unhandled service type %d: %s", service, pkt->content);
|
|
205 YAHOO_PRINT(sess, YAHOO_LOG_WARNING, buf);
|
|
206 break;
|
|
207 }
|
|
208 }
|
|
209
|
|
210 void yahoo_socket_handler(struct yahoo_session *session, int socket, int type)
|
|
211 {
|
|
212 int pos = 0;
|
|
213 struct yahoo_conn *conn;
|
|
214
|
|
215 if (!session)
|
|
216 return;
|
|
217
|
|
218 if (!(conn = yahoo_find_conn(session, socket)))
|
|
219 return;
|
|
220
|
|
221 if (type == YAHOO_SOCKET_WRITE) {
|
|
222 int error = ETIMEDOUT, len = sizeof(error);
|
|
223
|
|
224 if (getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
|
|
225 error = errno;
|
|
226 if (error) {
|
|
227 yahoo_close(session, conn);
|
|
228 YAHOO_PRINT(session, YAHOO_LOG_ERROR, "unable to connect");
|
|
229 CALLBACK(session, YAHOO_HANDLE_DISCONNECT);
|
|
230 return;
|
|
231 }
|
|
232
|
|
233 fcntl(socket, F_SETFL, 0);
|
|
234
|
|
235 YAHOO_PRINT(session, YAHOO_LOG_NOTICE, "connected");
|
|
236
|
|
237 if (yahoo_socket_notify)
|
|
238 (*yahoo_socket_notify)(session, socket, YAHOO_SOCKET_WRITE, FALSE);
|
|
239 if (yahoo_socket_notify)
|
|
240 (*yahoo_socket_notify)(session, socket, YAHOO_SOCKET_READ, TRUE);
|
|
241
|
|
242 if (conn->type == YAHOO_CONN_TYPE_AUTH) {
|
|
243 CALLBACK(session, YAHOO_HANDLE_AUTHCONNECT);
|
|
244 } else if (conn->type == YAHOO_CONN_TYPE_MAIN) {
|
|
245 CALLBACK(session, YAHOO_HANDLE_MAINCONNECT);
|
|
246 } else if (conn->type == YAHOO_CONN_TYPE_DUMB) {
|
|
247 YAHOO_PRINT(session, YAHOO_LOG_DEBUG, "sending to buddy list host");
|
|
248 yahoo_write(session, conn, conn->txqueue, strlen(conn->txqueue));
|
|
249 g_free(conn->txqueue);
|
|
250 conn->txqueue = NULL;
|
|
251 }
|
|
252
|
|
253 return;
|
|
254 }
|
|
255
|
|
256 if (conn->type == YAHOO_CONN_TYPE_AUTH) {
|
|
257 char *buf = g_malloc0(5000);
|
|
258 while (read(socket, &buf[pos++], 1) == 1);
|
|
259 if (pos == 1) {
|
|
260 g_free(buf);
|
|
261 yahoo_close(session, conn);
|
|
262 CALLBACK(session, YAHOO_HANDLE_DISCONNECT);
|
|
263 return;
|
|
264 }
|
|
265 YAHOO_PRINT(session, YAHOO_LOG_DEBUG, buf);
|
|
266 if (yahoo_parse_config(session, conn, buf))
|
|
267 CALLBACK(session, YAHOO_HANDLE_DISCONNECT);
|
|
268 g_free(buf);
|
|
269 } else if (conn->type == YAHOO_CONN_TYPE_MAIN) {
|
|
270 struct yahoo_packet pkt;
|
|
271 int len;
|
|
272
|
|
273 if ((read(socket, &pkt, 8) != 8) || strcmp(pkt.version, "YHOO1.0")) {
|
|
274 yahoo_close(session, conn);
|
|
275 CALLBACK(session, YAHOO_HANDLE_DISCONNECT);
|
|
276 return;
|
|
277 }
|
|
278
|
|
279 if (read(socket, &pkt.len, 4) != 4) {
|
|
280 yahoo_close(session, conn);
|
|
281 CALLBACK(session, YAHOO_HANDLE_DISCONNECT);
|
|
282 return;
|
|
283 }
|
|
284 len = yahoo_makeint(pkt.len);
|
|
285 len = ntohs(len) >> 8;
|
|
286
|
|
287 if (read(socket, &pkt.service, len - 12) != len - 12) {
|
|
288 yahoo_close(session, conn);
|
|
289 CALLBACK(session, YAHOO_HANDLE_DISCONNECT);
|
|
290 return;
|
|
291 }
|
|
292 yahoo_parse_packet(session, conn, &pkt);
|
|
293 } else if (conn->type == YAHOO_CONN_TYPE_DUMB) {
|
|
294 YAHOO_PRINT(session, YAHOO_LOG_DEBUG, "closing buddy list host connnection");
|
|
295 yahoo_close(session, conn);
|
|
296 }
|
|
297 }
|
|
298
|
|
299 void yahoo_add_handler(struct yahoo_session *session, int type, yahoo_callback function)
|
|
300 {
|
|
301 if (!session)
|
|
302 return;
|
|
303
|
|
304 session->callbacks[type].function = function;
|
|
305 }
|