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