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