Mercurial > pidgin.yaz
annotate src/protocols/simple/simple.c @ 11485:16b0da1f376f
[gaim-migrate @ 13727]
Fix the /nick weirdness bug I introduced.
Also, patch 1283539, from Peter Lawler (two changes)
1. When in a chat where Gaim can tell which users are buddies (i.e. non-Jabber chats), only the names of buddies are bolded. I'm not sure if I'll like this, but I'm committing it so we can all try it out.
2. "remove bold, underline, and italics when we're ignoring formatting, as well"
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Fri, 09 Sep 2005 20:14:32 +0000 |
parents | 0d18fa6c3b41 |
children | d37a45a53106 |
rev | line source |
---|---|
11181 | 1 /** |
2 * @file simple.c | |
3 * | |
4 * gaim | |
5 * | |
6 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de> | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
7 * |
11345 | 8 * *** |
9 * Thanks to Google's Summer of Code Program and the helpful mentors | |
10 * *** | |
11181 | 11 * |
12 * This program is free software; you can redistribute it and/or modify | |
13 * it under the terms of the GNU General Public License as published by | |
14 * the Free Software Foundation; either version 2 of the License, or | |
15 * (at your option) any later version. | |
16 * | |
17 * This program is distributed in the hope that it will be useful, | |
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 * GNU General Public License for more details. | |
21 * | |
22 * You should have received a copy of the GNU General Public License | |
23 * along with this program; if not, write to the Free Software | |
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
25 */ | |
26 | |
27 #include "internal.h" | |
28 | |
29 #include "accountopt.h" | |
30 #include "blist.h" | |
31 #include "conversation.h" | |
32 #include "debug.h" | |
33 #include "notify.h" | |
11345 | 34 #include "privacy.h" |
11181 | 35 #include "prpl.h" |
36 #include "plugin.h" | |
37 #include "util.h" | |
38 #include "version.h" | |
39 #include "network.h" | |
40 #include "xmlnode.h" | |
41 | |
42 #include "simple.h" | |
43 #include "sipmsg.h" | |
11383 | 44 #include "dnssrv.h" |
11409 | 45 #include "ntlm.h" |
11181 | 46 |
47 static char *gentag() { | |
48 return g_strdup_printf("%04d%04d", rand() & 0xFFFF, rand() & 0xFFFF); | |
49 } | |
50 | |
51 static char *genbranch() { | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
52 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X", |
11181 | 53 rand() & 0xFFFF, |
54 rand() & 0xFFFF, | |
55 rand() & 0xFFFF, | |
56 rand() & 0xFFFF, | |
57 rand() & 0xFFFF); | |
58 } | |
59 | |
60 static char *gencallid() { | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
61 return g_strdup_printf("%04Xg%04Xa%04Xi%04Xm%04Xt%04Xb%04Xx%04Xx", |
11181 | 62 rand() & 0xFFFF, |
63 rand() & 0xFFFF, | |
64 rand() & 0xFFFF, | |
65 rand() & 0xFFFF, | |
66 rand() & 0xFFFF, | |
67 rand() & 0xFFFF, | |
68 rand() & 0xFFFF, | |
69 rand() & 0xFFFF); | |
70 } | |
71 | |
72 static const char *simple_list_icon(GaimAccount *a, GaimBuddy *b) { | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
73 return "simple"; |
11181 | 74 } |
75 | |
76 static void simple_keep_alive(GaimConnection *gc) { | |
11194 | 77 struct simple_account_data *sip = gc->proto_data; |
11341 | 78 if(sip->udp) { /* in case of UDP send a packet only with a 0 byte to |
79 remain in the NAT table */ | |
11194 | 80 gchar buf[2]={0,0}; |
81 gaim_debug_info("simple", "sending keep alive\n"); | |
82 sendto(sip->fd, buf, 1, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)); | |
83 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
84 return; |
11181 | 85 } |
86 | |
87 static gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc); | |
88 static void send_notify(struct simple_account_data *sip, struct simple_watcher *); | |
89 | |
90 static void send_publish(struct simple_account_data *sip); | |
91 | |
92 static void do_notifies(struct simple_account_data *sip) { | |
93 GSList *tmp = sip->watcher; | |
94 gaim_debug_info("simple", "do_notifies()\n"); | |
11345 | 95 if((sip->republish != -1) || sip->republish < time(NULL)) { |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
96 if(gaim_account_get_bool(sip->account, "dopublish", TRUE)) { |
11345 | 97 send_publish(sip); |
98 } | |
99 } | |
11181 | 100 |
101 while(tmp) { | |
102 gaim_debug_info("simple", "notifying %s\n", ((struct simple_watcher*)tmp->data)->name); | |
103 send_notify(sip, tmp->data); | |
104 tmp = tmp->next; | |
105 } | |
106 } | |
107 | |
108 static void simple_set_status(GaimAccount *account, GaimStatus *status) { | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
109 GaimStatusPrimitive primitive = gaim_status_type_get_primitive(gaim_status_get_type(status)); |
11181 | 110 struct simple_account_data *sip = NULL; |
111 if (!gaim_status_is_active(status)) | |
112 return; | |
113 | |
114 if(account->gc) sip = account->gc->proto_data; | |
115 if(sip) { | |
116 if(sip->status) g_free(sip->status); | |
117 if(primitive == GAIM_STATUS_AVAILABLE) sip->status = g_strdup("available"); | |
118 else sip->status = g_strdup("busy"); | |
119 | |
120 do_notifies(sip); | |
121 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
122 if ((primitive != GAIM_STATUS_OFFLINE) |
11181 | 123 && (!gaim_account_is_connected(account))) { |
124 gaim_account_connect(account); | |
125 } | |
126 } | |
127 | |
128 static struct sip_connection *connection_find(struct simple_account_data *sip, int fd) { | |
129 struct sip_connection *ret = NULL; | |
130 GSList *entry = sip->openconns; | |
131 while(entry) { | |
132 ret = entry->data; | |
133 if(ret->fd == fd) return ret; | |
134 entry = entry->next; | |
135 } | |
136 return NULL; | |
137 } | |
138 | |
139 static struct simple_watcher *watcher_find(struct simple_account_data *sip, gchar *name) { | |
140 struct simple_watcher *watcher; | |
141 GSList *entry = sip->watcher; | |
142 while(entry) { | |
143 watcher = entry->data; | |
144 if(!strcmp(name, watcher->name)) return watcher; | |
145 entry = entry->next; | |
146 } | |
147 return NULL; | |
148 } | |
149 | |
150 static struct simple_watcher *watcher_create(struct simple_account_data *sip, gchar *name, gchar *callid, gchar *ourtag, gchar *theirtag) { | |
151 struct simple_watcher *watcher = g_new0(struct simple_watcher,1); | |
152 watcher->name = g_strdup(name); | |
153 watcher->dialog.callid = g_strdup(callid); | |
154 watcher->dialog.ourtag = g_strdup(ourtag); | |
155 watcher->dialog.theirtag = g_strdup(theirtag); | |
156 sip->watcher = g_slist_append(sip->watcher, watcher); | |
157 return watcher; | |
158 } | |
159 | |
160 static void watcher_remove(struct simple_account_data *sip, gchar *name) { | |
161 struct simple_watcher *watcher = watcher_find(sip, name); | |
162 sip->watcher = g_slist_remove(sip->watcher, watcher); | |
163 g_free(watcher->name); | |
164 g_free(watcher->dialog.callid); | |
165 g_free(watcher->dialog.ourtag); | |
166 g_free(watcher->dialog.theirtag); | |
167 g_free(watcher); | |
168 } | |
169 | |
170 static struct sip_connection *connection_create(struct simple_account_data *sip, int fd) { | |
171 struct sip_connection *ret = g_new0(struct sip_connection,1); | |
172 ret->fd = fd; | |
173 sip->openconns = g_slist_append(sip->openconns, ret); | |
174 return ret; | |
175 } | |
176 | |
177 static void connection_remove(struct simple_account_data *sip, int fd) { | |
178 struct sip_connection *conn = connection_find(sip, fd); | |
179 sip->openconns = g_slist_remove(sip->openconns, conn); | |
180 if(conn->inputhandler) gaim_input_remove(conn->inputhandler); | |
181 if(conn->inbuf) g_free(conn->inbuf); | |
182 g_free(conn); | |
183 } | |
184 | |
11346 | 185 static void connection_free_all(struct simple_account_data *sip) { |
186 struct sip_connection *ret = NULL; | |
187 GSList *entry = sip->openconns; | |
188 while(entry) { | |
189 ret = entry->data; | |
190 connection_remove(sip, ret->fd); | |
191 entry = sip->openconns; | |
192 } | |
193 } | |
194 | |
11181 | 195 static void simple_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) |
196 { | |
197 struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data; | |
198 struct simple_buddy *b; | |
199 if(strncmp("sip:", buddy->name,4)) { | |
200 gchar *buf = g_strdup_printf(_("Could not add the buddy %s because every simple user has to start with 'sip:'."), buddy->name); | |
201 gaim_notify_error(gc, NULL, _("Unable To Add"), buf); | |
202 g_free(buf); | |
203 gaim_blist_remove_buddy(buddy); | |
204 return; | |
205 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
206 if(!g_hash_table_lookup(sip->buddies, buddy->name)) { |
11181 | 207 b = g_new0(struct simple_buddy, 1); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
208 gaim_debug_info("simple","simple_add_buddy %s\n",buddy->name); |
11181 | 209 b->name = g_strdup(buddy->name); |
210 g_hash_table_insert(sip->buddies, b->name, b); | |
211 } else { | |
212 gaim_debug_info("simple","buddy %s already in internal list\n", buddy->name); | |
213 } | |
214 } | |
215 | |
216 static void simple_get_buddies(GaimConnection *gc) { | |
217 GaimBlistNode *gnode, *cnode, *bnode; | |
218 | |
219 gaim_debug_info("simple","simple_get_buddies\n"); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
220 |
11181 | 221 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { |
222 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) continue; | |
223 for(cnode = gnode->child; cnode; cnode = cnode->next) { | |
224 if(!GAIM_BLIST_NODE_IS_CONTACT(cnode)) continue; | |
225 for(bnode = cnode->child; bnode; bnode = bnode->next) { | |
226 if(!GAIM_BLIST_NODE_IS_BUDDY(bnode)) continue; | |
11192 | 227 if(((GaimBuddy*)bnode)->account == gc->account) |
228 simple_add_buddy(gc, (GaimBuddy*)bnode, (GaimGroup *)gnode); | |
11181 | 229 } |
230 } | |
231 } | |
232 } | |
233 | |
234 static void simple_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) | |
235 { | |
236 struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data; | |
237 struct simple_buddy *b = g_hash_table_lookup(sip->buddies, buddy->name); | |
238 g_hash_table_remove(sip->buddies, buddy->name); | |
239 g_free(b->name); | |
240 g_free(b); | |
241 } | |
242 | |
243 static GList *simple_status_types(GaimAccount *acc) { | |
244 GaimStatusType *type; | |
245 GList *types = NULL; | |
246 gaim_debug_info("simple","called simple_status_types\n"); | |
247 type = gaim_status_type_new(GAIM_STATUS_OFFLINE, "offline", _("Offline"), FALSE); | |
248 types = g_list_append(types, type); | |
249 | |
250 type = gaim_status_type_new(GAIM_STATUS_ONLINE, "online", _("Online"), FALSE); | |
251 types = g_list_append(types, type); | |
252 | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
253 type = gaim_status_type_new_with_attrs( |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
254 GAIM_STATUS_AVAILABLE, "available", _("Available"), |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
255 TRUE, TRUE, FALSE, |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
256 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
257 types = g_list_append(types, type); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
258 |
11181 | 259 return types; |
260 } | |
261 | |
11346 | 262 static gchar *auth_header(struct simple_account_data *sip, struct sip_auth *auth, gchar *method, gchar *target) { |
263 gchar noncecount[9]; | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
264 HASHHEX HA2; |
11346 | 265 HASHHEX response; |
266 gchar *ret; | |
11409 | 267 gchar *tmp; |
268 | |
269 if(auth->type == 1) { /* Digest */ | |
270 sprintf(noncecount, "%08d", auth->nc++); | |
271 DigestCalcResponse(auth->HA1, auth->nonce, noncecount, "", "", method, target, HA2, response); | |
272 gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); | |
273 ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n",sip->username, auth->realm, auth->nonce, target, noncecount, response); | |
274 return ret; | |
275 } else if(auth->type == 2) { /* NTLM */ | |
276 if(auth->nc == 3) { | |
277 ret = gaim_ntlm_gen_type3(sip->username, sip->password, "gaim", sip->servername, auth->nonce); | |
11424 | 278 tmp = g_strdup_printf("NTLM qop=\"auth\" realm=\"%s\" targetname=\"%s\" response=\"%s\"\r\n",auth->realm, auth->target, ret); |
11409 | 279 g_free(ret); |
280 return tmp; | |
281 } | |
282 ret = gaim_ntlm_gen_type1("gaim", sip->servername); | |
11483 | 283 tmp = g_strdup_printf("NTLM qop=\"auth\" realm=\"%s\" targetname=\"%s\" response=\"%s\"\r\n", auth->realm, auth->target, ret); |
11409 | 284 g_free(ret); |
285 return tmp; | |
286 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
287 |
11346 | 288 sprintf(noncecount, "%08d", auth->nc++); |
289 DigestCalcResponse(auth->HA1, auth->nonce, noncecount, "", "", method, target, HA2, response); | |
290 gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); | |
291 ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n",sip->username, auth->realm, auth->nonce, target, noncecount, response); | |
292 return ret; | |
293 } | |
294 | |
295 static void fill_auth(struct simple_account_data *sip, gchar *hdr, struct sip_auth *auth) { | |
11409 | 296 int i=0; |
11424 | 297 char *tmp; |
298 char *tmp2; | |
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
299 gchar **parts; |
11346 | 300 if(!hdr) { |
11409 | 301 gaim_debug_error("simple", "fill_auth: hdr==NULL\n"); |
11346 | 302 return; |
303 } | |
11409 | 304 |
305 if(!g_strncasecmp(hdr, "NTLM", 4)) { | |
306 gaim_debug_info("simple", "found NTLM\n"); | |
307 auth->type = 2; | |
308 if(!auth->nonce && !auth->nc) { | |
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
309 parts = g_strsplit(hdr, " ", 0); |
11424 | 310 while(parts[i]) { |
311 if(!strncmp(parts[i],"targetname",10)) { | |
312 auth->target = g_strndup(parts[i]+12,strlen(parts[i]+12)-1); | |
313 } | |
314 if(!strncmp(parts[i],"realm",5)) { | |
315 tmp = strstr(hdr, "realm="); | |
316 tmp += 7; | |
317 tmp2 = strchr(tmp, '"'); | |
318 *tmp2 = 0; | |
319 auth->realm = g_strdup(tmp); | |
320 *tmp2 = '"'; | |
321 } | |
322 i++; | |
323 } | |
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
324 g_strfreev(parts); |
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
325 parts = NULL; |
11409 | 326 auth->nc = 1; |
327 } | |
328 if(!auth->nonce && auth->nc==2) { | |
329 auth->nc = 3; | |
330 auth->nonce = gaim_ntlm_parse_type2(hdr+5); | |
331 } | |
332 return; | |
333 } | |
334 | |
335 auth->type = 1; | |
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
336 parts = g_strsplit(hdr, " ", 0); |
11346 | 337 while(parts[i]) { |
338 if(!strncmp(parts[i],"nonce",5)) { | |
339 auth->nonce = g_strndup(parts[i]+7,strlen(parts[i]+7)-1); | |
340 } | |
341 if(!strncmp(parts[i],"realm",5)) { | |
342 auth->realm = g_strndup(parts[i]+7,strlen(parts[i]+7)-2); | |
343 } | |
344 i++; | |
345 } | |
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
346 g_strfreev(parts); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
347 |
11346 | 348 gaim_debug(GAIM_DEBUG_MISC, "simple", "nonce: %s realm: %s ", auth->nonce, auth->realm); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
349 |
11346 | 350 DigestCalcHA1("md5", sip->username, auth->realm, sip->password, auth->nonce, "", auth->HA1); |
351 | |
352 auth->nc=1; | |
353 } | |
354 | |
11181 | 355 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond); |
356 | |
357 static void send_later_cb(gpointer data, gint source, GaimInputCondition cond) { | |
358 GaimConnection *gc = data; | |
359 struct simple_account_data *sip = gc->proto_data; | |
360 struct sip_connection *conn; | |
361 | |
362 if( source < 0 ) { | |
363 gaim_connection_error(gc,"Could not connect"); | |
364 return; | |
365 } | |
366 | |
367 sip->fd = source; | |
368 sip->connecting = 0; | |
369 write(sip->fd, sip->sendlater, strlen(sip->sendlater)); | |
370 conn = connection_create(sip, source); | |
371 conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc); | |
372 g_free(sip->sendlater); | |
373 sip->sendlater = 0; | |
374 } | |
375 | |
376 | |
377 static void sendlater(GaimConnection *gc, const char *buf) { | |
378 struct simple_account_data *sip = gc->proto_data; | |
379 int error = 0; | |
380 if(!sip->connecting) { | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
381 gaim_debug_info("simple","connecting to %s port %d\n", sip->realhostname ? sip->realhostname : "{NULL}", sip->realport); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
382 error = gaim_proxy_connect(sip->account, sip->realhostname, sip->realport, send_later_cb, gc); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
383 if(error) { |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
384 gaim_connection_error(gc, _("Couldn't create socket")); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
385 } |
11181 | 386 sip->connecting = 1; |
387 } | |
388 if(sip->sendlater) { | |
389 gchar *old = sip->sendlater; | |
390 sip->sendlater = g_strdup_printf("%s\r\n%s",old, buf); | |
391 } else { | |
392 sip->sendlater = g_strdup(buf); | |
393 } | |
394 } | |
395 | |
396 static int sendout_pkt(GaimConnection *gc, const char *buf) { | |
397 struct simple_account_data *sip = gc->proto_data; | |
398 time_t currtime = time(NULL); | |
11189 | 399 int ret = 0; |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
400 |
11181 | 401 gaim_debug(GAIM_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf); |
11189 | 402 if(sip->udp) { |
403 if(sendto(sip->fd, buf, strlen(buf), 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < strlen(buf)) { | |
404 gaim_debug_info("simple", "could not send packet\n"); | |
405 } | |
406 } else { | |
407 if(sip->fd <0 ) { | |
408 sendlater(gc, buf); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
409 return 0; |
11189 | 410 } |
411 ret = write(sip->fd, buf, strlen(buf)); | |
412 if(ret < 0) { | |
413 sendlater(gc,buf); | |
414 return 0; | |
415 } | |
11181 | 416 } |
417 return ret; | |
418 } | |
419 | |
11194 | 420 static void sendout_sipmsg(struct simple_account_data *sip, struct sipmsg *msg) { |
421 gchar *oldstr; | |
422 gchar *outstr = g_strdup_printf("%s %s SIP/2.0\r\n", msg->method, msg->target); | |
423 gchar *name; | |
424 gchar *value; | |
425 GSList *tmp = msg->headers; | |
426 while(tmp) { | |
427 oldstr = outstr; | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
428 name = ((struct siphdrelement*)(tmp->data))->name; |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
429 value = ((struct siphdrelement*)(tmp->data))->value; |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
430 outstr = g_strdup_printf("%s%s: %s\r\n",oldstr, name, value); |
11194 | 431 g_free(oldstr); |
432 tmp = g_slist_next(tmp); | |
433 } | |
434 oldstr = outstr; | |
435 if(msg->body) outstr = g_strdup_printf("%s\r\n%s", outstr, msg->body); | |
436 else outstr = g_strdup_printf("%s\r\n", outstr); | |
437 g_free(oldstr); | |
438 sendout_pkt(sip->gc, outstr); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
439 g_free(outstr); |
11194 | 440 } |
441 | |
11181 | 442 static void send_sip_response(GaimConnection *gc, struct sipmsg *msg, int code, char *text, char *body) { |
443 GSList *tmp = msg->headers; | |
444 char *oldstr; | |
445 char *name; | |
446 char *value; | |
447 char *outstr = g_strdup_printf("SIP/2.0 %d %s\r\n",code, text); | |
448 while(tmp) { | |
449 oldstr = outstr; | |
450 name = ((struct siphdrelement*)(tmp->data))->name; | |
451 value = ((struct siphdrelement*)(tmp->data))->value; | |
452 outstr = g_strdup_printf("%s%s: %s\r\n",oldstr, name, value); | |
453 g_free(oldstr); | |
454 tmp = g_slist_next(tmp); | |
455 } | |
456 oldstr = outstr; | |
457 if(body) outstr = g_strdup_printf("%s\r\n%s",outstr,body); | |
458 else outstr = g_strdup_printf("%s\r\n",outstr); | |
459 g_free(oldstr); | |
460 sendout_pkt(gc, outstr); | |
461 g_free(outstr); | |
462 } | |
463 | |
11194 | 464 static void transactions_remove(struct simple_account_data *sip, struct transaction *trans) { |
465 if(trans->msg) sipmsg_free(trans->msg); | |
466 sip->transactions = g_slist_remove(sip->transactions, trans); | |
467 g_free(trans); | |
468 } | |
469 | |
11181 | 470 static void transactions_add_buf(struct simple_account_data *sip, gchar *buf, void *callback) { |
471 struct transaction *trans = g_new0(struct transaction, 1); | |
472 trans->time = time(NULL); | |
473 trans->msg = sipmsg_parse_msg(buf); | |
474 trans->cseq = sipmsg_find_header(trans->msg, "CSeq"); | |
475 trans->callback = callback; | |
476 sip->transactions = g_slist_append(sip->transactions, trans); | |
477 } | |
478 | |
479 static struct transaction *transactions_find(struct simple_account_data *sip, struct sipmsg *msg) { | |
480 struct transaction *trans; | |
481 GSList *transactions = sip->transactions; | |
482 gchar *cseq = sipmsg_find_header(msg, "CSeq"); | |
483 | |
484 while(transactions) { | |
485 trans = transactions->data; | |
486 if(!strcmp(trans->cseq, cseq)) { | |
487 return trans; | |
488 } | |
489 transactions = transactions->next; | |
490 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
491 |
11181 | 492 return (struct transaction *)NULL; |
493 } | |
494 | |
495 static void send_sip_request(GaimConnection *gc, gchar *method, gchar *url, gchar *to, gchar *addheaders, gchar *body, struct sip_dialog *dialog, TransCallback tc) { | |
496 struct simple_account_data *sip = gc->proto_data; | |
497 char *callid= dialog ? g_strdup(dialog->callid) : gencallid(); | |
498 char *auth=""; | |
499 char *addh=""; | |
500 gchar *branch = genbranch(); | |
501 char *buf; | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
502 |
11181 | 503 if(addheaders) addh=addheaders; |
11409 | 504 if(sip->registrar.type && !strcmp(method,"REGISTER")) { |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
505 buf = auth_header(sip, &sip->registrar, method, url); |
11346 | 506 auth = g_strdup_printf("Authorization: %s",buf); |
507 g_free(buf); | |
11181 | 508 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth); |
509 } | |
510 | |
11409 | 511 if(sip->proxy.type && strcmp(method,"REGISTER")) { |
11346 | 512 buf = auth_header(sip, &sip->proxy, method, url); |
513 auth = g_strdup_printf("Proxy-Authorization: %s",buf); | |
514 g_free(buf); | |
11181 | 515 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth); |
516 } | |
517 | |
518 buf = g_strdup_printf("%s %s SIP/2.0\r\n" | |
11190 | 519 "Via: SIP/2.0/%s %s:%d;branch=%s\r\n" |
11181 | 520 "From: <sip:%s@%s>;tag=%s\r\n" |
521 "To: <%s>%s%s\r\n" | |
522 "Max-Forwards: 10\r\n" | |
523 "CSeq: %d %s\r\n" | |
524 "User-Agent: Gaim SIP/SIMPLE Plugin\r\n" | |
525 "Call-ID: %s\r\n" | |
526 "%s%s" | |
527 "Content-Length: %d\r\n\r\n%s", | |
528 method, | |
529 url, | |
11190 | 530 sip->udp ? "UDP" : "TCP", |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
531 sip->ip ? sip->ip : "", |
11181 | 532 sip->listenport, |
533 branch, | |
534 sip->username, | |
535 sip->servername, | |
536 dialog ? dialog->ourtag : gentag(), | |
537 to, | |
538 dialog ? ";tag=" : "", | |
539 dialog ? dialog->theirtag : "", | |
540 ++sip->cseq, | |
541 method, | |
542 callid, | |
543 auth, | |
544 addh, | |
545 strlen(body), | |
546 body); | |
547 g_free(branch); | |
548 g_free(callid); | |
549 | |
11341 | 550 /* add to ongoing transactions */ |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
551 |
11181 | 552 transactions_add_buf(sip, buf, tc); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
553 |
11181 | 554 sendout_pkt(gc,buf); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
555 |
11181 | 556 g_free(buf); |
557 } | |
558 | |
11194 | 559 static void do_register_exp(struct simple_account_data *sip, int expire) { |
11181 | 560 char *uri = g_strdup_printf("sip:%s",sip->servername); |
561 char *to = g_strdup_printf("sip:%s@%s",sip->username,sip->servername); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
562 char *contact = g_strdup_printf("Contact: <sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"\r\nExpires: %d\r\n", sip->username, sip->ip ? sip->ip : "", sip->listenport, sip->udp ? "udp" : "tcp", expire); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
563 |
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
564 sip->registerstatus = 1; |
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
565 |
11194 | 566 if(expire) { |
567 sip->reregister = time(NULL) + expire - 50; | |
568 } else { | |
569 sip->reregister = time(NULL) + 600; | |
570 } | |
571 send_sip_request(sip->gc,"REGISTER",uri,to, contact, "", NULL, process_register_response); | |
11341 | 572 g_free(contact); |
11181 | 573 g_free(uri); |
574 g_free(to); | |
575 } | |
576 | |
11194 | 577 static void do_register(struct simple_account_data *sip) { |
578 do_register_exp(sip, sip->registerexpire); | |
579 } | |
580 | |
11181 | 581 static gchar *parse_from(gchar *hdr) { |
582 gchar *from = hdr; | |
583 gchar *tmp; | |
584 | |
585 if(!from) return NULL; | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
586 gaim_debug_info("simple", "parsing address out of %s\n",from); |
11181 | 587 tmp = strchr(from, '<'); |
588 | |
11341 | 589 /* i hate the different SIP UA behaviours... */ |
590 if(tmp) { /* sip address in <...> */ | |
11181 | 591 from = tmp+1; |
592 tmp = strchr(from,'>'); | |
593 if(tmp) { | |
594 from = g_strndup(from,tmp-from); | |
595 } else { | |
596 gaim_debug_info("simple", "found < without > in From\n"); | |
597 return NULL; | |
598 } | |
599 } else { | |
600 tmp = strchr(from, ';'); | |
601 if(tmp) { | |
602 from = g_strndup(from,tmp-from); | |
11483 | 603 } else { |
604 from = g_strdup(from); | |
11181 | 605 } |
606 } | |
607 gaim_debug_info("simple", "got %s\n",from); | |
608 return from; | |
609 } | |
610 | |
611 static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
11341 | 612 gchar *to = parse_from(sipmsg_find_header(tc->msg,"To")); /* cant be NULL since it is our own msg */ |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
613 |
11181 | 614 if(msg->response==200 || msg->response==202) { |
615 return TRUE; | |
616 } | |
617 | |
11341 | 618 /* we can not subscribe -> user is offline (TODO unknown status?) */ |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
619 |
11181 | 620 gaim_prpl_got_user_status(sip->account, to, "offline", NULL); |
621 g_free(to); | |
622 return TRUE; | |
623 } | |
624 | |
625 static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) { | |
11341 | 626 gchar *contact = "Expires: 300\r\nAccept: application/pidf+xml\r\nEvent: presence\r\n"; |
11181 | 627 gchar *to; |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
628 if(strstr(buddy->name,"sip:")) to = g_strdup(buddy->name); |
11181 | 629 else to = g_strdup_printf("sip:%s",buddy->name); |
11341 | 630 contact = g_strdup_printf("%sContact: <%s@%s>\r\n", contact, sip->username, sip->servername); |
631 /* subscribe to buddy presence | |
632 * we dont need to know the status so we do not need a callback */ | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
633 |
11181 | 634 send_sip_request(sip->gc, "SUBSCRIBE",to, to, contact, "", NULL, process_subscribe_response); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
635 |
11181 | 636 g_free(to); |
11341 | 637 g_free(contact); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
638 |
11341 | 639 /* resubscribe before subscription expires */ |
640 /* add some jitter */ | |
641 buddy->resubscribe = time(NULL)+250+(rand()%50); | |
11181 | 642 } |
643 | |
644 static void simple_buddy_resub(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) { | |
645 time_t curtime = time(NULL); | |
11341 | 646 gaim_debug_info("simple","buddy resub\n"); |
11181 | 647 if(buddy->resubscribe < curtime) { |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
648 gaim_debug(GAIM_DEBUG_MISC, "simple", "simple_buddy_resub %s\n",name); |
11181 | 649 simple_subscribe(sip, buddy); |
650 } | |
651 } | |
652 | |
11194 | 653 static gboolean resend_timeout(struct simple_account_data *sip) { |
654 GSList *tmp = sip->transactions; | |
655 time_t currtime = time(NULL); | |
656 while(tmp) { | |
657 struct transaction *trans = tmp->data; | |
658 tmp = tmp->next; | |
659 gaim_debug_info("simple", "have open transaction age: %d\n", currtime- trans->time); | |
660 if((currtime - trans->time > 5) && trans->retries >= 1) { | |
11341 | 661 /* TODO 408 */ |
11194 | 662 } else { |
663 if((currtime - trans->time > 2) && trans->retries == 0) { | |
664 trans->retries++; | |
665 sendout_sipmsg(sip, trans->msg); | |
666 } | |
667 } | |
668 } | |
669 return TRUE; | |
670 } | |
671 | |
11181 | 672 static gboolean register_timeout(struct simple_account_data *sip) { |
673 GSList *tmp; | |
674 time_t curtime = time(NULL); | |
11341 | 675 /* register again if first registration expires */ |
11181 | 676 if(sip->reregister < curtime) { |
11194 | 677 do_register(sip); |
11181 | 678 } |
11341 | 679 gaim_debug_info("simple","in register timeout\n"); |
680 /* check for every subscription if we need to resubscribe */ | |
11181 | 681 g_hash_table_foreach(sip->buddies, (GHFunc)simple_buddy_resub, (gpointer)sip); |
682 | |
11341 | 683 /* remove a timed out suscriber */ |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
684 |
11181 | 685 tmp = sip->watcher; |
686 while(tmp) { | |
687 struct simple_watcher *watcher = tmp->data; | |
688 if(watcher->expire < curtime) { | |
689 watcher_remove(sip, watcher->name); | |
690 tmp = sip->watcher; | |
691 } | |
692 if(tmp) tmp = tmp->next; | |
693 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
694 |
11181 | 695 return TRUE; |
696 } | |
697 | |
698 static void simple_send_message(struct simple_account_data *sip, char *to, char *msg, char *type) { | |
699 gchar *hdr; | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
700 if(type) { |
11181 | 701 hdr = g_strdup_printf("Content-Type: %s\r\n",type); |
702 } else { | |
703 hdr = g_strdup("Content-Type: text/plain\r\n"); | |
704 } | |
705 send_sip_request(sip->gc, "MESSAGE", to, to, hdr, msg, NULL, NULL); | |
706 g_free(hdr); | |
707 } | |
708 | |
709 static int simple_im_send(GaimConnection *gc, const char *who, const char *what, GaimConvImFlags flags) { | |
710 struct simple_account_data *sip = gc->proto_data; | |
711 char *to = g_strdup(who); | |
712 char *text = g_strdup(what); | |
713 simple_send_message(sip, to, text, NULL); | |
714 g_free(to); | |
715 g_free(text); | |
716 return 1; | |
717 } | |
718 | |
719 static void process_incoming_message(struct simple_account_data *sip, struct sipmsg *msg) { | |
720 gchar *from; | |
721 gchar *contenttype; | |
722 gboolean found = FALSE; | |
723 | |
724 from = parse_from(sipmsg_find_header(msg, "From")); | |
725 | |
726 if(!from) return; | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
727 |
11181 | 728 gaim_debug(GAIM_DEBUG_MISC, "simple", "got message from %s: %s\n", from, msg->body); |
729 | |
730 contenttype = sipmsg_find_header(msg, "Content-Type"); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
731 if(!contenttype || !strncmp(contenttype, "text/plain", 10) || !strncmp(contenttype, "text/html", 9)) { |
11181 | 732 serv_got_im(sip->gc, from, msg->body, 0, time(NULL)); |
733 send_sip_response(sip->gc, msg, 200, "OK", NULL); | |
734 found = TRUE; | |
735 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
736 if(!strncmp(contenttype, "application/im-iscomposing+xml",30)) { |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
737 xmlnode *isc = xmlnode_from_str(msg->body, msg->bodylen); |
11181 | 738 xmlnode *state; |
739 gchar *statedata; | |
740 | |
741 if(!isc) { | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
742 gaim_debug_info("simple","process_incoming_message: can not parse iscomposing\n"); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
743 return; |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
744 } |
11181 | 745 |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
746 state = xmlnode_get_child(isc, "state"); |
11181 | 747 |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
748 if(!state) { |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
749 gaim_debug_info("simple","process_incoming_message: no state found\n"); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
750 return; |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
751 } |
11181 | 752 |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
753 statedata = xmlnode_get_data(state); |
11181 | 754 if(statedata) { |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
755 if(strstr(statedata,"active")) serv_got_typing(sip->gc, from, 0, GAIM_TYPING); |
11181 | 756 else serv_got_typing_stopped(sip->gc, from); |
757 } | |
758 xmlnode_free(isc); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
759 send_sip_response(sip->gc, msg, 200, "OK", NULL); |
11181 | 760 found = TRUE; |
761 } | |
762 if(!found) { | |
763 gaim_debug_info("simple", "got unknown mime-type"); | |
764 send_sip_response(sip->gc, msg, 415, "Unsupported media type", NULL); | |
765 } | |
766 g_free(from); | |
767 } | |
768 | |
769 | |
770 gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
771 gchar *tmp; | |
772 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process register response response: %d\n", msg->response); | |
773 switch (msg->response) { | |
774 case 200: | |
11341 | 775 if(sip->registerstatus<3) { /* registered */ |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
776 if(gaim_account_get_bool(sip->account, "dopublish", TRUE)) { |
11345 | 777 send_publish(sip); |
778 } | |
11181 | 779 } |
780 sip->registerstatus=3; | |
781 gaim_connection_set_state(sip->gc, GAIM_CONNECTED); | |
11341 | 782 |
783 /* get buddies from blist */ | |
784 simple_get_buddies(sip->gc); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
785 |
11181 | 786 register_timeout(sip); |
787 break; | |
788 case 401: | |
789 if(sip->registerstatus!=2) { | |
11346 | 790 gaim_debug_info("simple","REGISTER retries %d\n",sip->registrar.retries); |
791 if(sip->registrar.retries>3) { | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
792 gaim_connection_error(sip->gc,"Wrong Password"); |
11346 | 793 return TRUE; |
794 } | |
11181 | 795 tmp = sipmsg_find_header(msg, "WWW-Authenticate"); |
796 fill_auth(sip, tmp, &sip->registrar); | |
797 sip->registerstatus=2; | |
11194 | 798 do_register(sip); |
11181 | 799 } |
800 break; | |
801 } | |
802 return TRUE; | |
803 } | |
804 | |
805 static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) { | |
806 gchar *from; | |
807 gchar *fromhdr; | |
808 gchar *tmp2; | |
809 xmlnode *pidf; | |
810 xmlnode *basicstatus; | |
811 gboolean isonline = FALSE; | |
812 | |
813 fromhdr = sipmsg_find_header(msg,"From"); | |
814 from = parse_from(fromhdr); | |
815 if(!from) return; | |
816 | |
817 pidf = xmlnode_from_str(msg->body, msg->bodylen); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
818 |
11181 | 819 if(!pidf) { |
820 gaim_debug_info("simple","process_incoming_notify: no parseable pidf\n"); | |
821 return; | |
822 } | |
823 | |
824 basicstatus = xmlnode_get_child(xmlnode_get_child(xmlnode_get_child(pidf,"tuple"),"status"), "basic"); | |
825 | |
826 if(!basicstatus) { | |
827 gaim_debug_info("simple","process_incoming_notify: no basic found\n"); | |
828 return; | |
829 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
830 |
11181 | 831 tmp2 = xmlnode_get_data(basicstatus); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
832 |
11181 | 833 if(!tmp2) { |
834 gaim_debug_info("simple","process_incoming_notify: no basic data found\n"); | |
835 return; | |
836 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
837 |
11181 | 838 if(strstr(tmp2, "open")) { |
839 isonline = TRUE; | |
840 } | |
841 | |
842 if(isonline) gaim_prpl_got_user_status(sip->account, from, "available", NULL); | |
843 else gaim_prpl_got_user_status(sip->account, from, "offline", NULL); | |
844 | |
845 xmlnode_free(pidf); | |
846 | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
847 g_free(from); |
11181 | 848 send_sip_response(sip->gc, msg, 200, "OK", NULL); |
849 } | |
850 | |
851 static int simple_typing(GaimConnection *gc, const char *name, int typing) { | |
852 struct simple_account_data *sip = gc->proto_data; | |
853 | |
854 gchar *xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
855 "<isComposing xmlns=\"urn:ietf:params:xml:ns:im-iscomposing\"\n" | |
856 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" | |
857 "xsi:schemaLocation=\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\">\n" | |
858 "<state>%s</state>\n" | |
859 "<contenttype>text/plain</contenttype>\n" | |
860 "<refresh>60</refresh>\n" | |
861 "</isComposing>"; | |
862 gchar *recv = g_strdup(name); | |
863 if(typing == GAIM_TYPING) { | |
864 gchar *msg = g_strdup_printf(xml, "active"); | |
865 simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); | |
866 g_free(msg); | |
867 } else { | |
868 gchar *msg = g_strdup_printf(xml, "idle"); | |
869 simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); | |
870 g_free(msg); | |
871 } | |
872 g_free(recv); | |
873 return 1; | |
874 } | |
875 | |
876 static gchar *find_tag(gchar *hdr) { | |
877 gchar *tmp = strstr(hdr, ";tag="); | |
878 gchar *tmp2; | |
879 if(!tmp) return NULL; | |
880 tmp += 5; | |
881 if((tmp2 = strchr(tmp, ';'))) { | |
882 tmp2[0] = '\0'; | |
883 tmp = g_strdup(tmp); | |
884 tmp2[0] = ';'; | |
885 return tmp; | |
886 } | |
887 return g_strdup(tmp); | |
888 } | |
889 | |
890 static gchar* gen_pidf(struct simple_account_data *sip) { | |
891 gchar *doc = g_strdup_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
892 "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n" |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
893 "xmlns:im=\"urn:ietf:params:xml:ns:pidf:im\"\n" |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
894 "entity=\"sip:%s@%s\">\n" |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
895 "<tuple id=\"bs35r9f\">\n" |
11181 | 896 "<status>\n" |
897 "<basic>open</basic>\n" | |
898 "<im:im>%s</im:im>\n" | |
899 "</status>\n" | |
900 "</tuple>\n" | |
901 "</presence>", | |
902 sip->username, | |
903 sip->servername, | |
904 sip->status); | |
905 return doc; | |
906 } | |
907 | |
908 static void send_notify(struct simple_account_data *sip, struct simple_watcher *watcher) { | |
909 gchar *doc = gen_pidf(sip); | |
910 send_sip_request(sip->gc, "NOTIFY", watcher->name, watcher->name, "Event: presence\r\nContent-Type: application/pidf+xml\r\n", doc, &watcher->dialog, NULL); | |
911 g_free(doc); | |
912 } | |
913 | |
914 static gboolean process_publish_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
11345 | 915 if(msg->response != 200 && msg->response != 408) { |
11341 | 916 /* never send again */ |
11181 | 917 sip->republish = -1; |
918 } | |
919 return TRUE; | |
920 } | |
921 | |
922 static void send_publish(struct simple_account_data *sip) { | |
923 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); | |
924 gchar *doc = gen_pidf(sip); | |
11341 | 925 send_sip_request(sip->gc, "PUBLISH", uri, uri, "Expires: 600\r\nEvent: presence\r\nContent-Type: application/pidf+xml\r\n", doc, NULL, process_publish_response); |
11181 | 926 sip->republish = time(NULL) + 500; |
927 g_free(doc); | |
928 } | |
929 | |
930 static void process_incoming_subscribe(struct simple_account_data *sip, struct sipmsg *msg) { | |
931 gchar *from = parse_from(sipmsg_find_header(msg, "From")); | |
932 gchar *theirtag = find_tag(sipmsg_find_header(msg, "From")); | |
933 gchar *ourtag = find_tag(sipmsg_find_header(msg, "To")); | |
934 gboolean tagadded = FALSE; | |
935 gchar *callid = sipmsg_find_header(msg, "Call-ID"); | |
936 gchar *expire = sipmsg_find_header(msg, "Expire"); | |
937 gchar *tmp; | |
938 struct simple_watcher *watcher = watcher_find(sip, from); | |
939 if(!ourtag) { | |
940 tagadded = TRUE; | |
941 ourtag = gentag(); | |
942 } | |
11341 | 943 if(!watcher) { /* new subscription */ |
11345 | 944 if(!gaim_privacy_check(sip->account, from)) { |
945 send_sip_response(sip->gc, msg, 202, "Ok", NULL); | |
946 goto privend; | |
947 } | |
11181 | 948 watcher = watcher_create(sip, from, callid, ourtag, theirtag); |
949 } | |
950 if(tagadded) { | |
951 gchar *to = g_strdup_printf("%s;tag=%s", sipmsg_find_header(msg, "To"), ourtag); | |
952 sipmsg_remove_header(msg, "To"); | |
953 sipmsg_add_header(msg, "To", to); | |
954 } | |
955 if(expire) | |
956 watcher->expire = time(NULL) + strtol(expire, NULL, 10); | |
957 else | |
958 watcher->expire = time(NULL) + 600; | |
959 sipmsg_remove_header(msg, "Contact"); | |
960 tmp = g_strdup_printf("<%s@%s>",sip->username, sip->servername); | |
961 sipmsg_add_header(msg, "Contact", tmp); | |
962 gaim_debug_info("simple","got subscribe: name %s ourtag %s theirtag %s callid %s\n", watcher->name, watcher->dialog.ourtag, watcher->dialog.theirtag, watcher->dialog.callid); | |
963 send_sip_response(sip->gc, msg, 200, "Ok", NULL); | |
964 g_free(tmp); | |
965 send_notify(sip, watcher); | |
11345 | 966 privend: |
967 g_free(from); | |
968 g_free(theirtag); | |
969 g_free(ourtag); | |
970 g_free(callid); | |
971 g_free(expire); | |
11181 | 972 } |
973 | |
11189 | 974 static void process_input_message(struct simple_account_data *sip, struct sipmsg *msg) { |
975 int found = 0; | |
11341 | 976 if( msg->response == 0 ) { /* request */ |
11189 | 977 if(!strcmp(msg->method, "MESSAGE")) { |
978 process_incoming_message(sip, msg); | |
979 found = 1; | |
980 } | |
981 if(!strcmp(msg->method, "NOTIFY")) { | |
982 process_incoming_notify(sip, msg); | |
983 found = 1; | |
984 } | |
985 if(!strcmp(msg->method, "SUBSCRIBE")) { | |
986 process_incoming_subscribe(sip, msg); | |
987 found = 1; | |
988 } | |
11190 | 989 if(!found) { |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
990 send_sip_response(sip->gc, msg, 501, "Not implemented", NULL); |
11190 | 991 } |
11341 | 992 } else { /* response */ |
11189 | 993 struct transaction *trans = transactions_find(sip, msg); |
994 if(trans) { | |
995 if(msg->response == 407) { | |
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
996 gchar *resend, *auth, *ptmp; |
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
997 |
11346 | 998 if(sip->proxy.retries>3) return; |
999 sip->proxy.retries++; | |
11341 | 1000 /* do proxy authentication */ |
11189 | 1001 |
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
1002 ptmp = sipmsg_find_header(msg, "Proxy-Authenticate"); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1003 |
11189 | 1004 fill_auth(sip, ptmp, &sip->proxy); |
11346 | 1005 auth = auth_header(sip, &sip->proxy, trans->msg->method, trans->msg->target); |
11189 | 1006 sipmsg_remove_header(msg, "Proxy-Authorization"); |
1007 sipmsg_add_header(trans->msg, "Proxy-Authorization", auth); | |
1008 g_free(auth); | |
1009 resend = sipmsg_to_string(trans->msg); | |
11341 | 1010 /* resend request */ |
11189 | 1011 sendout_pkt(sip->gc, resend); |
1012 g_free(resend); | |
1013 } else { | |
11346 | 1014 sip->proxy.retries = 0; |
1015 if(msg->response == 401) sip->registrar.retries++; | |
1016 else sip->registrar.retries = 0; | |
11189 | 1017 if(trans->callback) { |
11341 | 1018 /* call the callback to process response*/ |
11189 | 1019 (trans->callback)(sip, msg, trans); |
1020 } | |
11194 | 1021 transactions_remove(sip, trans); |
11189 | 1022 } |
1023 found = 1; | |
1024 } else { | |
1025 gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction"); | |
1026 } | |
1027 } | |
1028 if(!found) { | |
1029 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %sand response %d\n",msg->method, msg->response); | |
1030 } | |
1031 } | |
1032 | |
11181 | 1033 static void process_input(struct simple_account_data *sip, struct sip_connection *conn) |
1034 { | |
1035 char *cur; | |
1036 char *dummy; | |
1037 struct sipmsg *msg; | |
1038 int restlen; | |
1039 cur = conn->inbuf; | |
1040 | |
11341 | 1041 /* according to the RFC remove CRLF at the beginning */ |
11181 | 1042 while(*cur == '\r' || *cur == '\n') { |
1043 cur++; | |
1044 } | |
1045 if(cur != conn->inbuf) { | |
1046 memmove(conn->inbuf, cur, conn->inbufused-(cur-conn->inbuf)); | |
1047 conn->inbufused=strlen(conn->inbuf); | |
1048 } | |
1049 | |
11341 | 1050 /* Received a full Header? */ |
11181 | 1051 if((cur = strstr(conn->inbuf, "\r\n\r\n"))!=NULL) { |
1052 time_t currtime = time(NULL); | |
1053 cur += 2; | |
1054 cur[0] = '\0'; | |
1055 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), conn->inbuf); | |
1056 msg = sipmsg_parse_header(conn->inbuf); | |
1057 cur[0] = '\r'; | |
1058 cur += 2; | |
1059 restlen = conn->inbufused - (cur-conn->inbuf); | |
1060 if(restlen>=msg->bodylen) { | |
1061 dummy = g_malloc(msg->bodylen+1); | |
1062 memcpy(dummy, cur, msg->bodylen); | |
1063 dummy[msg->bodylen]='\0'; | |
1064 msg->body = dummy; | |
1065 cur+=msg->bodylen; | |
1066 memmove(conn->inbuf, cur, conn->inbuflen); | |
1067 conn->inbufused=strlen(conn->inbuf); | |
1068 } else { | |
1069 sipmsg_free(msg); | |
1070 return; | |
1071 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1072 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); |
11189 | 1073 process_input_message(sip,msg); |
11181 | 1074 } else { |
1075 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a incomplete sip msg: %s\n", conn->inbuf); | |
1076 } | |
1077 } | |
1078 | |
11189 | 1079 static void simple_udp_process(gpointer data, gint source, GaimInputCondition con) { |
1080 GaimConnection *gc = data; | |
1081 struct simple_account_data *sip = gc->proto_data; | |
1082 struct sipmsg *msg; | |
1083 int len; | |
1084 time_t currtime; | |
1085 | |
1086 static char buffer[65536]; | |
1087 len = recv(source, buffer, 65536, 0); | |
1088 buffer[len] = 0; | |
1089 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), buffer); | |
1090 msg = sipmsg_parse_msg(buffer); | |
1091 if(msg) process_input_message(sip, msg); | |
1092 } | |
1093 | |
11181 | 1094 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond) |
1095 { | |
1096 GaimConnection *gc = data; | |
1097 struct simple_account_data *sip = gc->proto_data; | |
1098 int len; | |
1099 struct sip_connection *conn = connection_find(sip, source); | |
1100 if(!conn) { | |
1101 gaim_debug_error("simple", "Connection not found!\n"); | |
1102 return; | |
1103 } | |
1104 | |
1105 if (conn->inbuflen < conn->inbufused + SIMPLE_BUF_INC) { | |
1106 conn->inbuflen += SIMPLE_BUF_INC; | |
1107 conn->inbuf = g_realloc(conn->inbuf, conn->inbuflen); | |
1108 } | |
1109 | |
1110 if ((len = read(source, conn->inbuf + conn->inbufused, SIMPLE_BUF_INC - 1)) <= 0) { | |
1111 gaim_debug_info("simple","simple_input_cb: read error\n"); | |
1112 connection_remove(sip, source); | |
1113 if(sip->fd == source) sip->fd = -1; | |
1114 return; | |
1115 } | |
1116 if(len == 0) { | |
11341 | 1117 /* connection was closed */ |
11181 | 1118 connection_remove(sip, source); |
1119 if(sip->fd == source) sip->fd = -1; | |
1120 } | |
1121 | |
1122 conn->inbufused += len; | |
1123 conn->inbuf[conn->inbufused]='\0'; | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1124 |
11181 | 1125 process_input(sip, conn); |
1126 } | |
1127 | |
1128 /* Callback for new connections on incoming TCP port */ | |
1129 static void simple_newconn_cb(gpointer data, gint source, GaimInputCondition cond) { | |
1130 GaimConnection *gc = data; | |
1131 struct simple_account_data *sip = gc->proto_data; | |
1132 struct sip_connection *conn; | |
1133 | |
1134 int newfd = accept(source, NULL, NULL); | |
1135 | |
1136 conn = connection_create(sip, newfd); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1137 |
11181 | 1138 conn->inputhandler = gaim_input_add(newfd, GAIM_INPUT_READ, simple_input_cb, gc); |
1139 } | |
1140 | |
1141 static void login_cb(gpointer data, gint source, GaimInputCondition cond) { | |
1142 GaimConnection *gc = data; | |
1143 struct simple_account_data *sip = gc->proto_data; | |
1144 struct sip_connection *conn; | |
1145 | |
1146 if( source < 0 ) { | |
1147 gaim_connection_error(gc,"Could not connect"); | |
1148 return; | |
1149 } | |
1150 | |
1151 sip->fd = source; | |
1152 | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1153 conn = connection_create(sip, source); |
11181 | 1154 |
11341 | 1155 /* get the local ip */ |
11181 | 1156 sip->ip = g_strdup(gaim_network_get_my_ip(source)); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1157 |
11194 | 1158 do_register(sip); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1159 |
11181 | 1160 conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc); |
1161 } | |
1162 | |
1163 static guint simple_ht_hash_nick(const char *nick) { | |
1164 char *lc = g_utf8_strdown(nick, -1); | |
1165 guint bucket = g_str_hash(lc); | |
1166 g_free(lc); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1167 |
11181 | 1168 return bucket; |
1169 } | |
1170 | |
1171 static gboolean simple_ht_equals_nick(const char *nick1, const char *nick2) { | |
1172 return (gaim_utf8_strcasecmp(nick1, nick2) == 0); | |
1173 } | |
1174 | |
11383 | 1175 static void srvresolved(struct srv_response *resp, int results, gpointer data) { |
1176 struct simple_account_data *sip = (struct simple_account_data*) data; | |
1177 | |
1178 gchar *hostname; | |
1179 int port = 5060; | |
1180 | |
1181 int error = 0; | |
1182 struct sockaddr_in addr; | |
1183 struct hostent *h; | |
1184 | |
1185 /* find the host to connect to */ | |
1186 if(results) { | |
1187 hostname = g_strdup(resp->hostname); | |
1188 port = resp->port; | |
1189 g_free(resp); | |
1190 } else { | |
1191 if(!gaim_account_get_bool(sip->account, "useproxy", FALSE)) { | |
1192 hostname = g_strdup(sip->servername); | |
1193 } else { | |
1194 hostname = g_strdup(gaim_account_get_string(sip->account, "proxy", sip->servername)); | |
1195 } | |
1196 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1197 |
11383 | 1198 sip->realhostname = hostname; |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1199 sip->realport = port; |
11383 | 1200 /* TCP case */ |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1201 if(! sip->udp) { |
11409 | 1202 /* create socket for incoming connections */ |
1203 sip->listenfd = gaim_network_listen_range(5060, 5160); | |
1204 if(sip->listenfd == -1) { | |
1205 gaim_connection_error(sip->gc, _("Could not create listen socket")); | |
1206 return; | |
1207 } | |
1208 gaim_debug_info("simple", "listenfd: %d\n", sip->listenfd); | |
1209 sip->listenport = gaim_network_get_port_from_fd(sip->listenfd); | |
1210 sip->listenpa = gaim_input_add(sip->listenfd, GAIM_INPUT_READ, simple_newconn_cb, sip->gc); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1211 gaim_debug_info("simple","connecting to %s port %d\n", hostname, port); |
11383 | 1212 /* open tcp connection to the server */ |
1213 error = gaim_proxy_connect(sip->account, hostname, port, login_cb, sip->gc); | |
1214 if(error) { | |
1215 gaim_connection_error(sip->gc, _("Couldn't create socket")); | |
1216 } | |
1217 | |
1218 } else { /* UDP */ | |
1219 gaim_debug_info("simple", "using udp with server %s and port %d\n", hostname, port); | |
1220 sip->fd = socket(AF_INET, SOCK_DGRAM, 0); | |
1221 | |
1222 addr.sin_family = AF_INET; | |
1223 addr.sin_port = htons(5060); | |
1224 addr.sin_addr.s_addr = INADDR_ANY; | |
1225 while((bind(sip->fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) <0) && ntohs(addr.sin_port)<5160) { | |
1226 addr.sin_port = htons(ntohs(addr.sin_port)+1); | |
1227 } | |
1228 sip->listenport = ntohs(addr.sin_port); | |
1229 sip->listenfd = sip->fd; | |
1230 | |
1231 gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_udp_process, sip->gc); | |
1232 sip->serveraddr.sin_family = AF_INET; | |
1233 sip->serveraddr.sin_port = htons(port); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1234 |
11383 | 1235 h = gethostbyname(hostname); |
1236 sip->serveraddr.sin_addr.s_addr = ((struct in_addr*)h->h_addr)->s_addr; | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1237 sip->ip = g_strdup(gaim_network_get_my_ip(sip->listenfd)); |
11383 | 1238 sip->resendtimeout = gaim_timeout_add(2500, (GSourceFunc)resend_timeout, sip); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1239 do_register(sip); |
11383 | 1240 } |
1241 } | |
1242 | |
11181 | 1243 static void simple_login(GaimAccount *account, GaimStatus *status) |
1244 { | |
1245 GaimConnection *gc; | |
1246 struct simple_account_data *sip; | |
1247 gchar **userserver; | |
11210 | 1248 gchar *hosttoconnect; |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1249 |
11181 | 1250 const char *username = gaim_account_get_username(account); |
1251 | |
1252 gc = gaim_account_get_connection(account); | |
1253 gc->proto_data = sip = g_new0(struct simple_account_data,1); | |
1254 sip->gc=gc; | |
11189 | 1255 sip->account = account; |
11194 | 1256 sip->registerexpire = 900; |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1257 sip->udp = gaim_account_get_bool(account, "udp", FALSE); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1258 if (strpbrk(username, " \t\v\r\n") != NULL) { |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1259 gaim_connection_error(gc, _("SIP usernames may not contain whitespaces or @ symbols")); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1260 return; |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1261 } |
11181 | 1262 |
1263 userserver = g_strsplit(username, "@", 2); | |
1264 gaim_connection_set_display_name(gc,userserver[0]); | |
1265 sip->username = g_strdup(userserver[0]); | |
1266 sip->servername = g_strdup(userserver[1]); | |
1267 sip->password = g_strdup(gaim_connection_get_password(gc)); | |
1268 g_strfreev(userserver); | |
1269 | |
1270 sip->buddies = g_hash_table_new((GHashFunc)simple_ht_hash_nick, (GEqualFunc)simple_ht_equals_nick); | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1271 |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1272 gaim_connection_update_progress(gc, _("Connecting"), 1, 2); |
11181 | 1273 |
1274 sip->status = g_strdup("available"); | |
11189 | 1275 |
11210 | 1276 if(!gaim_account_get_bool(account, "useproxy", FALSE)) { |
1277 hosttoconnect = g_strdup(sip->servername); | |
1278 } else { | |
1279 hosttoconnect = g_strdup(gaim_account_get_string(account, "proxy", sip->servername)); | |
1280 } | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1281 |
11341 | 1282 /* TCP case */ |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1283 if(! sip->udp) { |
11383 | 1284 gaim_srv_resolve("sip","tcp",hosttoconnect,srvresolved, sip); |
11341 | 1285 } else { /* UDP */ |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1286 gaim_srv_resolve("sip","udp",hosttoconnect,srvresolved, sip); |
11181 | 1287 } |
11210 | 1288 g_free(hosttoconnect); |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1289 |
11341 | 1290 /* register timeout callback for register / subscribe renewal */ |
11194 | 1291 sip->registertimeout = gaim_timeout_add((rand()%100)+10*1000, (GSourceFunc)register_timeout, sip); |
11181 | 1292 } |
1293 | |
1294 static void simple_close(GaimConnection *gc) | |
1295 { | |
1296 struct simple_account_data *sip = gc->proto_data; | |
11194 | 1297 |
11341 | 1298 /* unregister */ |
11194 | 1299 do_register_exp(sip, 0); |
11346 | 1300 connection_free_all(sip); |
11341 | 1301 if(sip) { |
11181 | 1302 if(sip->servername) g_free(sip->servername); |
1303 if(sip->username) g_free(sip->username); | |
1304 if(sip->password) g_free(sip->password); | |
1305 if(sip->registrar.nonce) g_free(sip->registrar.nonce); | |
11341 | 1306 if(sip->registrar.realm) g_free(sip->registrar.realm); |
11181 | 1307 if(sip->proxy.nonce) g_free(sip->proxy.nonce); |
1308 if(sip->proxy.realm) g_free(sip->proxy.realm); | |
1309 if(sip->sendlater) g_free(sip->sendlater); | |
1310 if(sip->ip) g_free(sip->ip); | |
11383 | 1311 if(sip->realhostname) g_free(sip->realhostname); |
11409 | 1312 if(sip->listenpa) gaim_input_remove(sip->listenpa); |
11346 | 1313 if(sip->registertimeout) gaim_timeout_remove(sip->registertimeout); |
11383 | 1314 sip->servername = sip->username = sip->password = sip->registrar.nonce = sip->registrar.realm = sip->proxy.nonce = sip->proxy.realm = sip->sendlater = sip->ip = sip->realhostname = NULL; |
11181 | 1315 } |
11341 | 1316 if(gc->proto_data) g_free(gc->proto_data); |
1317 gc->proto_data = 0; | |
11181 | 1318 } |
1319 | |
11345 | 1320 /* not needed since privacy is checked for every subscribe */ |
1321 static void dummy_add_deny(GaimConnection *gc, const char *name) { | |
1322 } | |
1323 | |
1324 static void dummy_permit_deny(GaimConnection *gc) { | |
1325 } | |
1326 | |
11181 | 1327 static GaimPluginProtocolInfo prpl_info = |
1328 { | |
1329 0, | |
1330 NULL, /* user_splits */ | |
1331 NULL, /* protocol_options */ | |
1332 NO_BUDDY_ICONS, /* icon_spec */ | |
1333 simple_list_icon, /* list_icon */ | |
1334 NULL, /* list_emblems */ | |
1335 NULL, /* status_text */ | |
1336 NULL, /* tooltip_text */ | |
1337 simple_status_types, /* away_states */ | |
1338 NULL, /* blist_node_menu */ | |
1339 NULL, /* chat_info */ | |
1340 NULL, /* chat_info_defaults */ | |
1341 simple_login, /* login */ | |
1342 simple_close, /* close */ | |
1343 simple_im_send, /* send_im */ | |
1344 NULL, /* set_info */ | |
1345 simple_typing, /* send_typing */ | |
1346 NULL, /* get_info */ | |
1347 simple_set_status, /* set_status */ | |
1348 NULL, /* set_idle */ | |
1349 NULL, /* change_passwd */ | |
1350 simple_add_buddy, /* add_buddy */ | |
1351 NULL, /* add_buddies */ | |
1352 simple_remove_buddy, /* remove_buddy */ | |
1353 NULL, /* remove_buddies */ | |
11345 | 1354 dummy_add_deny, /* add_permit */ |
1355 dummy_add_deny, /* add_deny */ | |
1356 dummy_add_deny, /* rem_permit */ | |
1357 dummy_add_deny, /* rem_deny */ | |
1358 dummy_permit_deny, /* set_permit_deny */ | |
11181 | 1359 NULL, /* join_chat */ |
1360 NULL, /* reject_chat */ | |
1361 NULL, /* get_chat_name */ | |
1362 NULL, /* chat_invite */ | |
1363 NULL, /* chat_leave */ | |
1364 NULL, /* chat_whisper */ | |
1365 NULL, /* chat_send */ | |
1366 simple_keep_alive, /* keepalive */ | |
1367 NULL, /* register_user */ | |
1368 NULL, /* get_cb_info */ | |
1369 NULL, /* get_cb_away */ | |
1370 NULL, /* alias_buddy */ | |
1371 NULL, /* group_buddy */ | |
1372 NULL, /* rename_group */ | |
1373 NULL, /* buddy_free */ | |
1374 NULL, /* convo_closed */ | |
1375 NULL, /* normalize */ | |
1376 NULL, /* set_buddy_icon */ | |
1377 NULL, /* remove_group */ | |
1378 NULL, /* get_cb_real_name */ | |
1379 NULL, /* set_chat_topic */ | |
1380 NULL, /* find_blist_chat */ | |
1381 NULL, /* roomlist_get_list */ | |
1382 NULL, /* roomlist_cancel */ | |
1383 NULL, /* roomlist_expand_category */ | |
1384 NULL, /* can_receive_file */ | |
1385 NULL /* send_file */ | |
1386 }; | |
1387 | |
1388 | |
1389 static GaimPluginInfo info = | |
1390 { | |
1391 GAIM_PLUGIN_MAGIC, | |
1392 GAIM_MAJOR_VERSION, | |
1393 GAIM_MINOR_VERSION, | |
1394 GAIM_PLUGIN_PROTOCOL, /**< type */ | |
1395 NULL, /**< ui_requirement */ | |
1396 0, /**< flags */ | |
1397 NULL, /**< dependencies */ | |
1398 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
1399 | |
1400 "prpl-simple", /**< id */ | |
1401 "SIMPLE", /**< name */ | |
1402 VERSION, /**< version */ | |
1403 N_("SIP/SIMPLE Protocol Plugin"), /** summary */ | |
1404 N_("The SIP/SIMPLE Protocol Plugin"), /** description */ | |
1405 N_("Thomas Butter <butter@uni-mannheim.de>"), /**< author */ | |
1406 GAIM_WEBSITE, /**< homepage */ | |
1407 | |
1408 NULL, /**< load */ | |
1409 NULL, /**< unload */ | |
1410 NULL, /**< destroy */ | |
1411 | |
1412 NULL, /**< ui_info */ | |
1413 &prpl_info, /**< extra_info */ | |
1414 NULL, | |
1415 NULL | |
1416 }; | |
1417 | |
1418 static void _init_plugin(GaimPlugin *plugin) | |
1419 { | |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1420 GaimAccountUserSplit *split; |
11189 | 1421 GaimAccountOption *option; |
11181 | 1422 |
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1423 split = gaim_account_user_split_new(_("Server"), "", '@'); |
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1424 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
11181 | 1425 |
11345 | 1426 option = gaim_account_option_bool_new(_("Publish Status (note: everyone may watch you)"), "dopublish", TRUE); |
1427 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
1428 | |
11189 | 1429 option = gaim_account_option_bool_new(_("Use UDP"), "udp", FALSE); |
1430 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
11210 | 1431 option = gaim_account_option_bool_new(_("Use Proxy"), "useproxy", FALSE); |
1432 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
1433 option = gaim_account_option_string_new(_("Proxy"), "proxy", ""); | |
1434 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
11181 | 1435 } |
1436 | |
1437 GAIM_INIT_PLUGIN(simple, _init_plugin, info); |