1 /*
2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4 *
5 * Version: MPL 1.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18 *
19 * The Initial Developer of the Original Code is
20 * Anthony Minessale II <anthm@freeswitch.org>
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Anthony Minessale II <anthm@freeswitch.org>
27 * Ken Rice <krice@freeswitch.org>
28 * Paul D. Tinsley <pdt at jackhammer.org>
29 * Bret McDanel <trixter AT 0xdecafbad.com>
30 * Raymond Chandler <intralanman@freeswitch.org>
31 * William King <william.king@quentustech.com>
32 * Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
33 * David Knell <david.knell@telng.com>
34 *
35 * sofia_presence.c -- SOFIA SIP Endpoint (presence code)
36 *
37 */
38 #include "mod_sofia.h"
39 #include "switch_stun.h"
40
41 #define SUB_OVERLAP 300
42 struct state_helper {
43 switch_hash_t *hash;
44 sofia_profile_t *profile;
45 switch_memory_pool_t *pool;
46 int total;
47 };
48
49
50 static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char **columnNames);
51 static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char **columnNames);
52 static int sofia_presence_sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames);
53 static int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames);
54 static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames);
55 static int broadsoft_sla_gather_state_callback(void *pArg, int argc, char **argv, char **columnNames);
56 static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char **columnNames);
57 static int sync_sla(sofia_profile_t *profile, const char *to_user, const char *to_host, switch_bool_t clear, switch_bool_t unseize, const char *call_id);
58 static int sofia_dialog_probe_callback(void *pArg, int argc, char **argv, char **columnNames);
59 static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, char **columnNames);
60
61 struct pres_sql_cb {
62 sofia_profile_t *profile;
63 int ttl;
64 };
65
66 static int sofia_presence_send_sql(void *pArg, int argc, char **argv, char **columnNames);
67
68 struct dialog_helper {
69 char state[128];
70 char status[512];
71 char rpid[512];
72 char presence_id[1024];
73 int hits;
74 };
75
76 struct resub_helper {
77 sofia_profile_t *profile;
78 switch_event_t *event;
79 int rowcount;
80 int noreg;
81 };
82
83 struct rfc4235_helper {
84 switch_hash_t *hash;
85 sofia_profile_t *profile;
86 switch_memory_pool_t *pool;
87 switch_event_t *event;
88 int rowcount;
89 };
90
91 struct presence_helper {
92 sofia_profile_t *profile;
93 switch_event_t *event;
94 switch_stream_handle_t stream;
95 char last_uuid[512];
96 int hup;
97 int calls_up;
98
99 };
100
sofia_presence_chat_send(switch_event_t * message_event)101 switch_status_t sofia_presence_chat_send(switch_event_t *message_event)
102
103 {
104 char *prof = NULL, *user = NULL, *host = NULL;
105 sofia_profile_t *profile = NULL;
106 char *ffrom = NULL;
107 nua_handle_t *msg_nh;
108 char *contact = NULL;
109 char *dup = NULL;
110 switch_status_t status = SWITCH_STATUS_FALSE;
111 const char *ct = "text/html";
112 sofia_destination_t *dst = NULL;
113 char *to_uri = NULL;
114 switch_console_callback_match_t *list = NULL;
115 switch_console_callback_match_node_t *m;
116 char *remote_ip = NULL;
117 char *user_via = NULL;
118 //char *contact_str = NULL;
119 char *dup_dest = NULL;
120 char *p = NULL;
121 char *remote_host = NULL;
122 const char *proto;
123 const char *from;
124 const char *to;
125 //const char *subject;
126 const char *body;
127 const char *type;
128 const char *from_full;
129 char header[256] = "";
130 char *route_uri = NULL;
131 const char *network_ip = NULL, *network_port = NULL, *from_proto;
132 char *extra_headers = NULL;
133 char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
134 int mstatus = 0, sanity = 0;
135 const char *blocking;
136 int is_blocking = 0;
137
138 proto = switch_event_get_header(message_event, "proto");
139 from_proto = switch_event_get_header(message_event, "from_proto");
140 from = switch_event_get_header(message_event, "from");
141 to = switch_event_get_header(message_event, "to");
142 //subject = switch_event_get_header(message_event, "subject");
143 body = switch_event_get_body(message_event);
144 type = switch_event_get_header(message_event, "type");
145 from_full = switch_event_get_header(message_event, "from_full");
146 blocking = switch_event_get_header(message_event, "blocking");
147 is_blocking = switch_true(blocking);
148
149 network_ip = switch_event_get_header(message_event, "to_sip_ip");
150 network_port = switch_event_get_header(message_event, "to_sip_port");
151
152 extra_headers = sofia_glue_get_extra_headers_from_event(message_event, SOFIA_SIP_HEADER_PREFIX);
153
154 if (!to) {
155 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing To: header.\n");
156 goto end;
157 }
158
159 if (!from) {
160 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing From: header.\n");
161 goto end;
162 }
163
164 if (!zstr(type)) {
165 ct = type;
166 }
167
168 dup = strdup(to);
169 switch_assert(dup);
170 prof = dup;
171
172 /* Do we have a user of the form profile/user[@host]? */
173 if ((user = strchr(prof, '/'))) {
174 *user++ = '\0';
175 } else {
176 user = prof;
177 prof = NULL;
178 }
179
180 if (!prof) {
181 prof = switch_event_get_header(message_event, "sip_profile");
182 }
183
184 if (!strncasecmp(user, "sip:", 4)) {
185 to_uri = user;
186 }
187
188 if ((host = strchr(user, '@'))) {
189 if (!to_uri) {
190 *host++ = '\0';
191 } else {
192 host++;
193 }
194 if (!prof) {
195 prof = host;
196 }
197 }
198
199 if (!prof || !(profile = sofia_glue_find_profile(prof))) {
200 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
201 "Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n", proto, from, to,
202 body ? body : "[no body]", prof ? prof : "NULL");
203 goto end;
204 }
205
206 if (zstr(host)) {
207 host = profile->domain_name;
208 if (zstr(host)) {
209 host = prof;
210 }
211 }
212
213
214 if (to_uri) {
215 switch_console_push_match(&list, to_uri);
216 } else if (!(list = sofia_reg_find_reg_url_multi(profile, user, host))) {
217 sofia_profile_t *test;
218
219 if ((test = sofia_glue_find_profile(host))) {
220 sofia_glue_release_profile(test);
221 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not sending to local box for %s@%s\n", user, host);
222 /* our box let's not send it */
223 } else {
224 char *tmp;
225 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Can't find registered user %s@%s\n", user, host);
226 tmp = switch_mprintf("sip:%s@%s", user, host);
227 switch_console_push_match(&list, tmp);
228 free(tmp);
229 }
230
231 }
232
233 if (!strcasecmp(proto, SOFIA_CHAT_PROTO)) {
234 from = from_full;
235 } else {
236 char *fp, *p = NULL;
237
238
239 fp = strdup(from);
240 switch_assert(fp);
241
242
243 if ((p = strchr(fp, '@'))) {
244 *p++ = '\0';
245 }
246
247 if (zstr(p)) {
248 p = profile->domain_name;
249 if (zstr(p)) {
250 p = host;
251 }
252 }
253
254 if (switch_stristr("global", proto)) {
255 if (!from_proto || !strcasecmp(from_proto, SOFIA_CHAT_PROTO)) {
256 ffrom = switch_mprintf("\"%s\" <sip:%s@%s>", fp, fp, p);
257 } else {
258 ffrom = switch_mprintf("\"%s\" <sip:%s+%s@%s>", fp, from_proto, fp, p);
259 }
260
261 } else {
262 ffrom = switch_mprintf("\"%s\" <sip:%s+%s@%s>", fp, from_proto ? from_proto : proto, fp, p);
263 }
264
265 from = ffrom;
266 switch_safe_free(fp);
267 }
268
269 if (!list) {
270 switch_event_t *event;
271
272 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
273 "Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nNobody to send to: Profile %s\n", proto, from, to,
274 body ? body : "[no body]", prof);
275 // emit no recipient event
276 if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_ERROR) == SWITCH_STATUS_SUCCESS) {
277 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Error-Type", "chat");
278 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Error-Reason", "no recipient");
279 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Chat-Send-To", to);
280 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Chat-Send-From", from);
281 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Chat-Send-Profile", prof);
282 switch_event_add_body(event, "%s", body);
283 switch_event_fire(&event);
284 }
285
286 goto end;
287 }
288
289 for (m = list->head; m; m = m->next) {
290
291 if (!(dst = sofia_glue_get_destination(m->val))) {
292 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
293 break;
294 }
295
296 /* sofia_glue is running sofia_overcome_sip_uri_weakness we do not, not sure if it matters */
297
298 if (dst->route_uri) {
299 dup_dest = strdup(dst->route_uri);
300 } else {
301 dup_dest = strdup(dst->to);
302 }
303
304 switch_assert(dup_dest);
305
306 remote_host = strdup(dup_dest);
307 if (!zstr(remote_host)) {
308 switch_split_user_domain(remote_host, NULL, &remote_ip);
309 }
310
311 if (!zstr(remote_ip) && sofia_glue_check_nat(profile, remote_ip)) {
312 char *ptr = NULL;
313 if ((ptr = sofia_glue_find_parameter(dst->contact, "transport="))) {
314 sofia_transport_t transport = sofia_glue_str2transport( ptr + 10 );
315 user_via = sofia_glue_create_external_via(NULL, profile, transport);
316 } else {
317 user_via = sofia_glue_create_external_via(NULL, profile, SOFIA_TRANSPORT_UDP);
318 }
319 }
320
321 status = SWITCH_STATUS_SUCCESS;
322
323 if ((p = strstr(dup_dest, ";fs_"))) {
324 *p = '\0';
325 }
326
327 /* if this cries, add contact here too, change the 1 to 0 and omit the safe_free */
328
329 //printf("DEBUG To: [%s] From: [%s] Contact: [%s] RURI [%s] ip [%s] port [%s]\n", to, from, contact, dst->route_uri, network_ip, network_port);
330
331 //DUMP_EVENT(message_event);
332
333 if (zstr(dst->route_uri) && !zstr(user) && !zstr(network_ip) && (zstr(host) || strcmp(network_ip, host))) {
334 route_uri = switch_mprintf("sip:%s@%s:%s", user, network_ip, network_port);
335 }
336
337 msg_nh = nua_handle(profile->nua, NULL,
338 TAG_END());
339
340 nua_handle_bind(msg_nh, &mod_sofia_globals.destroy_private);
341
342 switch_snprintf(header, sizeof(header), "X-FS-Sending-Message: %s", switch_core_get_uuid());
343
344 switch_uuid_str(uuid_str, sizeof(uuid_str));
345
346 if (is_blocking) {
347 switch_mutex_lock(profile->flag_mutex);
348 switch_core_hash_insert(profile->chat_hash, uuid_str, &mstatus);
349 switch_mutex_unlock(profile->flag_mutex);
350 }
351
352 nua_message(msg_nh,
353 TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)),
354 TAG_IF(route_uri, NUTAG_PROXY(route_uri)),
355 TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
356 SIPTAG_FROM_STR(from),
357 TAG_IF(contact, NUTAG_URL(contact)),
358 SIPTAG_TO_STR(dup_dest),
359 SIPTAG_CALL_ID_STR(uuid_str),
360 TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
361 SIPTAG_CONTENT_TYPE_STR(ct),
362 SIPTAG_PAYLOAD_STR(body),
363 SIPTAG_HEADER_STR(header),
364 TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
365 TAG_END());
366
367
368 if (is_blocking) {
369 sanity = 200;
370
371 while(!mstatus && --sanity && !msg_nh->nh_destroyed) {
372 switch_yield(100000);
373 }
374
375 if (!(mstatus > 199 && mstatus < 300)) {
376 status = SWITCH_STATUS_FALSE;
377 }
378
379 switch_event_add_header(message_event, SWITCH_STACK_BOTTOM, "Delivery-Result-Code", "%d", mstatus);
380
381 switch_mutex_lock(profile->flag_mutex);
382 switch_core_hash_delete(profile->chat_hash, uuid_str);
383 switch_mutex_unlock(profile->flag_mutex);
384 }
385
386 sofia_glue_free_destination(dst);
387 switch_safe_free(dup_dest);
388 switch_safe_free(user_via);
389 switch_safe_free(remote_host);
390 }
391
392 end:
393
394 if (list) {
395 switch_console_free_matches(&list);
396 }
397
398 switch_safe_free(contact);
399 switch_safe_free(route_uri);
400 switch_safe_free(ffrom);
401 switch_safe_free(dup);
402
403 if (profile) {
404 switch_thread_rwlock_unlock(profile->rwlock);
405 }
406
407 return status;
408 }
409
sofia_presence_cancel(void)410 void sofia_presence_cancel(void)
411 {
412 char *sql;
413 sofia_profile_t *profile;
414 struct presence_helper helper = { 0 };
415 switch_console_callback_match_t *matches;
416 switch_bool_t r;
417
418 if (!mod_sofia_globals.profile_hash) {
419 return;
420 }
421
422 if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
423 switch_console_callback_match_node_t *m;
424
425
426 for (m = matches->head; m; m = m->next) {
427 if ((profile = sofia_glue_find_profile(m->val))) {
428 if (profile->pres_type == PRES_TYPE_FULL) {
429 helper.profile = profile;
430 helper.event = NULL;
431
432 sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,"
433 "full_via,expires,user_agent,accept,profile_name,network_ip"
434 ",-1,'unavailable','unavailable' from sip_subscriptions where "
435 "event='presence' and hostname='%q' and profile_name='%q'",
436 mod_sofia_globals.hostname, profile->name);
437
438 r = sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_sub_callback, &helper);
439 switch_safe_free(sql);
440
441 if (r != SWITCH_TRUE) {
442 sofia_glue_release_profile(profile);
443 continue;
444 }
445 }
446 sofia_glue_release_profile(profile);
447 }
448 }
449
450 switch_console_free_matches(&matches);
451
452 }
453 }
454
sofia_presence_translate_rpid(char * in,char * ext)455 char *sofia_presence_translate_rpid(char *in, char *ext)
456 {
457 char *r = in;
458
459 if (in && (switch_stristr("null", in))) {
460 in = NULL;
461 }
462
463 if (!in) {
464 in = ext;
465 }
466
467 if (!in) {
468 return NULL;
469 }
470
471 if (!strcasecmp(in, "dnd") || !strcasecmp(in, "idle")) {
472 r = "busy";
473 }
474
475 return r;
476 }
477
478 struct mwi_helper {
479 sofia_profile_t *profile;
480 int total;
481 };
482
actual_sofia_presence_mwi_event_handler(switch_event_t * event)483 static void actual_sofia_presence_mwi_event_handler(switch_event_t *event)
484 {
485 char *account, *dup_account, *yn, *host, *user;
486 char *sql;
487 sofia_profile_t *profile = NULL;
488 switch_stream_handle_t stream = { 0 };
489 switch_event_header_t *hp;
490 struct mwi_helper h = { 0 };
491 const char *pname = NULL;
492 const char *call_id;
493 const char *sub_call_id;
494 int for_everyone = 0;
495
496 switch_assert(event != NULL);
497
498 if (!(account = switch_event_get_header(event, "mwi-message-account"))) {
499 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required Header 'MWI-Message-Account'\n");
500 return;
501 }
502
503 if (!(yn = switch_event_get_header(event, "mwi-messages-waiting"))) {
504 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing required Header 'MWI-Messages-Waiting'\n");
505 return;
506 }
507
508 call_id = switch_event_get_header(event, "call-id");
509 sub_call_id = switch_event_get_header(event, "sub-call-id");
510
511 if (!call_id && !sub_call_id) {
512 for_everyone = 1;
513 }
514
515
516 dup_account = strdup(account);
517 switch_assert(dup_account != NULL);
518 switch_split_user_domain(dup_account, &user, &host);
519
520
521 if ((pname = switch_event_get_header(event, "sofia-profile"))) {
522 profile = sofia_glue_find_profile(pname);
523 }
524
525 if (!profile) {
526 if (!host || !(profile = sofia_glue_find_profile(host))) {
527 char *sql;
528 char buf[512] = "";
529 switch_console_callback_match_t *matches;
530
531 sql = switch_mprintf("select profile_name from sip_registrations where hostname='%q' and (sip_host='%q' or mwi_host='%q')",
532 mod_sofia_globals.hostname, host, host);
533
534 if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
535 switch_console_callback_match_node_t *m;
536
537 for (m = matches->head; m; m = m->next) {
538 if ((profile = sofia_glue_find_profile(m->val))) {
539
540 sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, buf, sizeof(buf));
541 if (!zstr(buf)) {
542 break;
543 }
544 sofia_glue_release_profile(profile);
545 }
546 }
547
548 switch_console_free_matches(&matches);
549 }
550
551 switch_safe_free(sql);
552
553 if (!(profile = sofia_glue_find_profile(buf))) {
554 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find profile %s\n", switch_str_nil(host));
555 switch_safe_free(dup_account);
556 return;
557 }
558 }
559 }
560
561
562 if (profile->domain_name && strcasecmp(profile->domain_name, host)) {
563 host = profile->domain_name;
564 }
565
566 h.profile = profile;
567 h.total = 0;
568
569 SWITCH_STANDARD_STREAM(stream);
570
571 for (hp = event->headers; hp; hp = hp->next) {
572 if (!strncasecmp(hp->name, "mwi-", 4)) {
573 char *tmp = NULL;
574 char *value = hp->value;
575 if (!strcasecmp(hp->name, "mwi-message-account") && strncasecmp(hp->value, "sip:", 4)) {
576 tmp = switch_mprintf("sip:%s", hp->value);
577 value = tmp;
578 }
579 stream.write_function(&stream, "%s: %s\r\n", hp->name + 4, value);
580 switch_safe_free(tmp);
581 }
582 }
583
584 stream.write_function(&stream, "\r\n");
585
586 sql = NULL;
587
588 if (for_everyone) {
589 sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,"
590 "full_via,expires,user_agent,accept,profile_name,network_ip"
591 ",'%q',full_to,network_ip,network_port from sip_subscriptions "
592 "where hostname='%q' and event='message-summary' "
593 "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%')",
594 stream.data, mod_sofia_globals.hostname, user, host, host);
595 } else if (sub_call_id) {
596 sql = switch_mprintf("select proto,sip_user,sip_host,sub_to_user,sub_to_host,event,contact,call_id,full_from,"
597 "full_via,expires,user_agent,accept,profile_name,network_ip"
598 ",'%q',full_to,network_ip,network_port from sip_subscriptions where "
599 "hostname='%q' and event='message-summary' "
600 "and sub_to_user='%q' and (sub_to_host='%q' or presence_hosts like '%%%q%%') and call_id='%q'",
601 stream.data, mod_sofia_globals.hostname, user, host, host, sub_call_id);
602 }
603
604
605 if (sql) {
606 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_mwi_callback, &h);
607 free(sql);
608 sql = NULL;
609
610 }
611
612 if (for_everyone) {
613 sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,network_ip,'%q',call_id "
614 "from sip_registrations where hostname='%q' and mwi_user='%q' and mwi_host='%q'",
615 stream.data, mod_sofia_globals.hostname, user, host);
616 } else if (call_id) {
617 sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,network_ip,'%q',call_id "
618 "from sip_registrations where hostname='%q' and call_id='%q'",
619 stream.data, mod_sofia_globals.hostname, call_id);
620 }
621
622 if (sql) {
623 switch_assert(sql != NULL);
624 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_mwi_callback2, &h);
625 free(sql);
626 sql = NULL;
627 }
628
629 switch_safe_free(stream.data);
630 switch_safe_free(dup_account);
631 sofia_glue_release_profile(profile);
632 }
633
sofia_presence_dialog_callback(void * pArg,int argc,char ** argv,char ** columnNames)634 static int sofia_presence_dialog_callback(void *pArg, int argc, char **argv, char **columnNames)
635 {
636 struct dialog_helper *helper = (struct dialog_helper *) pArg;
637 switch_core_session_t *session = NULL;
638 switch_channel_t *channel = NULL;
639 int done = 0;
640
641 if (argc >= 4) {
642
643 if (argc == 5 && !zstr(argv[4])) {
644 if ((session = switch_core_session_locate(argv[4]))) {
645 channel = switch_core_session_get_channel(session);
646
647 if (!switch_channel_test_flag(channel, CF_ANSWERED) &&
648 switch_true(switch_channel_get_variable_dup(channel, "presence_disable_early", SWITCH_FALSE, -1))) {
649 done++;
650 }
651
652 switch_core_session_rwunlock(session);
653 } else {
654 return 0;
655 }
656 }
657
658 if (done) {
659 return 0;
660 }
661
662 if (mod_sofia_globals.debug_presence > 0) {
663 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "CHECK DIALOG state[%s] status[%s] rpid[%s] pres[%s] uuid[%s]\n",
664 argv[0], argv[1], argv[2], argv[3], argv[4]);
665 }
666
667 if (!helper->hits) {
668 switch_set_string(helper->state, argv[0]);
669 switch_set_string(helper->status, argv[1]);
670 switch_set_string(helper->rpid, argv[2]);
671 switch_set_string(helper->presence_id, argv[3]);
672 }
673 helper->hits++;
674 }
675
676 return 0;
677 }
678
679
do_normal_probe(switch_event_t * event)680 static void do_normal_probe(switch_event_t *event)
681 {
682 char *sql;
683 struct resub_helper h = { 0 };
684 char *to = switch_event_get_header(event, "to");
685 char *proto = switch_event_get_header(event, "proto");
686 char *profile_name = switch_event_get_header(event, "sip_profile");
687 char *probe_user = NULL, *probe_euser, *probe_host, *p;
688 struct dialog_helper dh = { { 0 } };
689 char *sub_call_id = switch_event_get_header(event, "sub-call-id");
690 sofia_profile_t *profile;
691
692 //DUMP_EVENT(event);
693
694 if (!proto || strcasecmp(proto, SOFIA_CHAT_PROTO) != 0) {
695 return;
696 }
697
698 if (!to || !(probe_user = strdup(to))) {
699 return;
700 }
701
702 if ((probe_host = strchr(probe_user, '@'))) {
703 *probe_host++ = '\0';
704 }
705 probe_euser = probe_user;
706 if ((p = strchr(probe_euser, '+')) && p != probe_euser) {
707 probe_euser = (p + 1);
708 }
709
710 if (probe_host &&
711 ((profile = sofia_glue_find_profile(probe_host)) || (profile_name && (profile = sofia_glue_find_profile(profile_name))))) {
712 sql = switch_mprintf("select state,status,rpid,presence_id,uuid from sip_dialogs "
713 "where hostname='%q' and profile_name='%q' and call_info_state != 'seized' and "
714 "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc",
715 mod_sofia_globals.hostname, profile->name, probe_euser, probe_host, probe_euser, probe_host);
716
717
718 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_dialog_callback, &dh);
719
720 h.profile = profile;
721
722 switch_safe_free(sql);
723
724 sql = switch_mprintf("select sip_registrations.sip_user, "
725 "sip_registrations.sub_host, "
726 "sip_registrations.status, "
727 "sip_registrations.rpid, "
728 "'', "
729 "sip_dialogs.uuid, "
730 "sip_dialogs.state, "
731 "sip_dialogs.direction, "
732 "sip_dialogs.sip_to_user, "
733 "sip_dialogs.sip_to_host, "
734
735 "sip_presence.status,"
736 "sip_presence.rpid,"
737 "sip_dialogs.presence_id, "
738 "sip_presence.open_closed,"
739 "'%q','%q','%q' "
740 "from sip_registrations "
741
742 "left join sip_dialogs on "
743 "sip_dialogs.hostname = sip_registrations.hostname and sip_dialogs.profile_name = sip_registrations.profile_name and ("
744 "sip_dialogs.presence_id = sip_registrations.sip_user %q '@' %q sip_registrations.sub_host "
745 "or (sip_dialogs.sip_from_user = sip_registrations.sip_user "
746 "and sip_dialogs.sip_from_host = sip_registrations.sip_host)) "
747
748 "left join sip_presence on "
749 "sip_presence.hostname=sip_registrations.hostname and "
750 "(sip_registrations.sip_user=sip_presence.sip_user and sip_registrations.orig_server_host=sip_presence.sip_host and "
751 "sip_registrations.profile_name=sip_presence.profile_name) "
752 "where sip_registrations.hostname='%q' and sip_registrations.profile_name='%q' and sip_dialogs.call_info_state != 'seized' "
753 "and sip_dialogs.presence_id='%q@%q' or (sip_registrations.sip_user='%q' and "
754 "(sip_registrations.orig_server_host='%q' or sip_registrations.sub_host='%q' "
755 "))",
756 dh.status, dh.rpid, switch_str_nil(sub_call_id),
757 switch_sql_concat(), switch_sql_concat(),
758 mod_sofia_globals.hostname, profile->name, probe_euser, probe_host, probe_euser, probe_host, probe_host);
759
760
761
762 switch_assert(sql);
763
764 if (mod_sofia_globals.debug_presence > 0) {
765 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s START_PRESENCE_PROBE_SQL\n", profile->name);
766 }
767
768 if (mod_sofia_globals.debug_presence > 1) {
769 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s DUMP PRESENCE_PROBE_SQL:\n%s\n", profile->name, sql);
770 }
771
772 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_resub_callback, &h);
773 switch_safe_free(sql);
774
775 if (!h.rowcount) {
776 h.noreg++;
777
778 /* find ones with presence_id defined that are not registred */
779 sql = switch_mprintf("select sip_from_user, sip_from_host, 'Registered', '', '', "
780 "uuid, state, direction, "
781 "sip_to_user, sip_to_host,"
782 "'%q','%q',presence_id, '','','' "
783
784 "from sip_dialogs "
785
786 "where call_info_state != 'seized' and hostname='%q' and profile_name='%q' and (presence_id='%q@%q' or "
787 "(sip_from_user='%q' and (sip_from_host='%q' or sip_to_host='%q')))",
788 mod_sofia_globals.hostname, profile->name,
789 dh.status, dh.rpid, probe_euser, probe_host, probe_euser, probe_host, probe_host);
790
791 if (mod_sofia_globals.debug_presence > 0) {
792 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s START_PRESENCE_PROBE_SQL\n", profile->name);
793 }
794
795 if (mod_sofia_globals.debug_presence > 1) {
796 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s DUMP PRESENCE_PROBE_SQL:\n%s\n", profile->name, sql);
797 }
798
799 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_resub_callback, &h);
800 switch_safe_free(sql);
801
802 if (mod_sofia_globals.debug_presence > 0) {
803 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s END_PRESENCE_PROBE_SQL\n\n", profile->name);
804 }
805 }
806
807 if (!h.rowcount) {
808 switch_event_t *sevent;
809 if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
810 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
811 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
812 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
813 switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", probe_euser, probe_host);
814 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "status", "Unregistered");
815 switch_event_fire(&sevent);
816 }
817 }
818
819
820 sofia_glue_release_profile(profile);
821 }
822
823
824 switch_safe_free(probe_user);
825 }
826
do_dialog_probe(switch_event_t * event)827 static void do_dialog_probe(switch_event_t *event)
828 {
829 // Received SUBSCRIBE for "dialog" events.
830 // Return a complete list of dialogs for the monitored entity.
831 char *sql;
832 char *to = switch_event_get_header(event, "to");
833 char *probe_user = NULL, *probe_euser, *probe_host, *p;
834
835 if (!to || !(probe_user = strdup(to))) {
836 return;
837 }
838
839 if ((probe_host = strchr(probe_user, '@'))) {
840 *probe_host++ = '\0';
841 }
842 probe_euser = probe_user;
843 if ((p = strchr(probe_euser, '+')) && p != probe_euser) {
844 probe_euser = (p + 1);
845 }
846
847 if (probe_host) {
848 char *sub_call_id = switch_event_get_header(event, "sub-call-id");
849 char *profile_name = switch_event_get_header(event, "sip_profile");
850 sofia_profile_t *profile = sofia_glue_find_profile(probe_host);
851 struct rfc4235_helper *h4235 = {0};
852 switch_memory_pool_t *pool;
853
854 if (!profile && profile_name) {
855 profile = sofia_glue_find_profile(profile_name);
856 }
857
858 if (!profile) {
859 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot find profile for domain %s\n", probe_host);
860 goto end;
861 }
862
863 // We need all dialogs with presence_id matching the subscription entity,
864 // or from a registered set matching the subscription entity.
865 // We need the "proto" of the subscription in case it is for the special "conf" or "park".
866 sql = switch_mprintf(
867 "select sip_subscriptions.proto, '%q','%q',"
868 "sip_dialogs.uuid, sip_dialogs.call_id, sip_dialogs.state, sip_dialogs.direction, "
869 "sip_dialogs.sip_to_user, sip_dialogs.sip_to_host, "
870 "sip_dialogs.sip_from_user, sip_dialogs.sip_from_host, "
871 "sip_dialogs.contact, sip_dialogs.contact_user, sip_dialogs.contact_host, "
872 "sip_dialogs.sip_to_tag, sip_dialogs.sip_from_tag, sip_subscriptions.orig_proto "
873 "from sip_dialogs "
874 "left join sip_subscriptions on sip_subscriptions.hostname=sip_dialogs.hostname and "
875 "sip_subscriptions.profile_name=sip_dialogs.profile_name and "
876 "sip_subscriptions.call_id='%q' "
877 "left join sip_registrations on sip_registrations.hostname=sip_dialogs.hostname and "
878 "sip_registrations.profile_name=sip_dialogs.profile_name and "
879 "(sip_dialogs.sip_from_user = sip_registrations.sip_user and sip_dialogs.sip_from_host = '%q' and "
880 "(sip_dialogs.sip_from_host = sip_registrations.orig_server_host or "
881 "sip_dialogs.sip_from_host = sip_registrations.sip_host) ) "
882 "where sip_dialogs.hostname='%q' and sip_dialogs.profile_name='%q' and "
883 "sip_dialogs.call_info_state != 'seized' and sip_dialogs.presence_id='%q@%q' or (sip_registrations.sip_user='%q' and "
884 "(sip_registrations.orig_server_host='%q' or sip_registrations.sub_host='%q' "
885 "or sip_registrations.presence_hosts like '%%%q%%'))",
886 probe_euser, probe_host,
887 sub_call_id, probe_host,
888 mod_sofia_globals.hostname, profile->name,
889 probe_euser, probe_host,
890 probe_euser, probe_host, probe_host, probe_host);
891 switch_assert(sql);
892
893 if (mod_sofia_globals.debug_presence > 0) {
894 switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_INFO, "%s START DIALOG_PROBE_SQL %s@%s\n", profile->name,probe_euser, probe_host);
895 }
896
897 if (mod_sofia_globals.debug_presence > 1) {
898 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s DUMP DIALOG_PROBE_SQL:\n%s\n", profile->name, sql);
899 }
900
901 switch_core_new_memory_pool(&pool);
902 h4235 = switch_core_alloc(pool, sizeof(*h4235));
903 h4235->pool = pool;
904 h4235->profile = profile;
905 switch_core_hash_init(&h4235->hash);
906 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_dialog_probe_callback, h4235);
907 switch_safe_free(sql);
908 if (mod_sofia_globals.debug_presence > 0) {
909 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s END DIALOG_PROBE_SQL\n\n", profile->name);
910 }
911
912
913 sql = switch_mprintf("update sip_subscriptions set version=version+1 where call_id='%q'", sub_call_id);
914
915 if (mod_sofia_globals.debug_presence > 1) {
916 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s DUMP DIALOG_PROBE set version sql:\n%s\n", profile->name, sql);
917 }
918 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
919 switch_safe_free(sql);
920
921
922 // The dialog_probe_callback has built up the dialogs to be included in the NOTIFY.
923 // Now send the "full" dialog event to the triggering subscription.
924 sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,version, "
925 "'full',full_to,full_from,contact,network_ip,network_port "
926 "from sip_subscriptions "
927 "where hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and call_id='%q'",
928 mod_sofia_globals.hostname, profile->name, probe_euser, probe_host, sub_call_id);
929
930 if (mod_sofia_globals.debug_presence > 1) {
931 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s DUMP DIALOG_PROBE subscription sql:\n%s\n", profile->name, sql);
932 }
933
934 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_dialog_probe_notify_callback, h4235);
935 switch_safe_free(sql);
936
937 sofia_glue_release_profile(profile);
938 switch_core_hash_destroy(&h4235->hash);
939 h4235 = NULL;
940 switch_core_destroy_memory_pool(&pool);
941 }
942
943 end:
944
945 switch_safe_free(probe_user);
946 }
947
send_conference_data(sofia_profile_t * profile,switch_event_t * event)948 static void send_conference_data(sofia_profile_t *profile, switch_event_t *event)
949 {
950 char *sql;
951 struct pres_sql_cb cb = {profile, 0};
952 const char *call_id = switch_event_get_header(event, "call_id");
953 const char *from_user = switch_event_get_header(event, "conference-name");
954 const char *from_host = switch_event_get_header(event, "conference-domain");
955 const char *event_str = switch_event_get_header(event, "conference-event");
956 const char *notfound = switch_event_get_header(event, "notfound");
957 const char *body = switch_event_get_body(event);
958 const char *type = "application/conference-info+xml";
959 const char *final = switch_event_get_header(event, "final");
960
961 if (!event_str) {
962 event_str = "conference";
963 }
964
965 if (!strcasecmp(event_str, "refer")) {
966 type = "message/sipfrag";
967 }
968
969
970 if (!(from_user && from_host)) {
971 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event information not given\n");
972 return;
973 }
974
975 if (switch_true(notfound)) {
976 sql = switch_mprintf("update sip_subscriptions set expires=%ld where "
977 "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'",
978 (long)switch_epoch_time_now(NULL),
979 mod_sofia_globals.hostname, profile->name,
980 from_user, from_host, event_str);
981
982 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
983 }
984
985 if (call_id) {
986 if (switch_true(final)) {
987 sql = switch_mprintf("update sip_subscriptions set expires=%ld where "
988 "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' "
989 "and call_id = '%q' ",
990 (long)0,
991 mod_sofia_globals.hostname, profile->name,
992 from_user, from_host, event_str, call_id);
993
994 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
995 }
996
997 sql = switch_mprintf("select full_to, full_from, contact %q ';_;isfocus', expires, call_id, event, network_ip, network_port, "
998 "'%q' as ct,'%q' as pt "
999 " from sip_subscriptions where "
1000 "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' "
1001 "and call_id = '%q' ",
1002 switch_sql_concat(),
1003 type,
1004 switch_str_nil(body),
1005 mod_sofia_globals.hostname, profile->name,
1006 from_user, from_host, event_str, call_id);
1007 } else {
1008 if (switch_true(final)) {
1009 sql = switch_mprintf("update sip_subscriptions set expires=%ld where "
1010 "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'",
1011 (long)0,
1012 mod_sofia_globals.hostname, profile->name,
1013 from_user, from_host, event_str);
1014
1015 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
1016 }
1017
1018 sql = switch_mprintf("select full_to, full_from, contact %q ';_;isfocus', expires, call_id, event, network_ip, network_port, "
1019 "'%q' as ct,'%q' as pt "
1020 " from sip_subscriptions where "
1021 "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'",
1022 switch_sql_concat(),
1023 type,
1024 switch_str_nil(body),
1025 mod_sofia_globals.hostname, profile->name,
1026 from_user, from_host, event_str);
1027 }
1028
1029 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_send_sql, &cb);
1030 switch_safe_free(sql);
1031
1032 if (switch_true(final)) {
1033 if (call_id) {
1034 sql = switch_mprintf("delete from sip_subscriptions where "
1035 "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q' "
1036 "and call_id = '%q' ",
1037 mod_sofia_globals.hostname, profile->name,
1038 from_user, from_host, event_str, call_id);
1039
1040 } else {
1041 sql = switch_mprintf("delete from sip_subscriptions where "
1042 "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'",
1043 mod_sofia_globals.hostname, profile->name,
1044 from_user, from_host, event_str);
1045 }
1046
1047 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
1048 }
1049
1050
1051 }
1052
conference_data_event_handler(switch_event_t * event)1053 static void conference_data_event_handler(switch_event_t *event)
1054 {
1055 const char *pname;
1056 //const char *from_user = switch_event_get_header(event, "conference-name");
1057 //const char *from_host = switch_event_get_header(event, "conference-domain");
1058 const char *host = switch_event_get_header(event, "conference-domain");
1059 char *dup_domain = NULL;
1060 sofia_profile_t *profile = NULL;
1061
1062 if (zstr(host)) {
1063 dup_domain = switch_core_get_domain(SWITCH_TRUE);
1064 host = dup_domain;
1065 }
1066
1067 if ((pname = switch_event_get_header(event, "sofia-profile"))) {
1068 profile = sofia_glue_find_profile(pname);
1069 }
1070
1071 if (host && !profile) {
1072 profile = sofia_glue_find_profile(host);
1073 }
1074
1075 if (profile) {
1076 send_conference_data(profile, event);
1077 sofia_glue_release_profile(profile);
1078 } else {
1079 switch_console_callback_match_t *matches;
1080
1081 if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
1082 switch_console_callback_match_node_t *m;
1083
1084 for (m = matches->head; m; m = m->next) {
1085 if ((profile = sofia_glue_find_profile(m->val))) {
1086 send_conference_data(profile, event);
1087 sofia_glue_release_profile(profile);
1088 }
1089 }
1090
1091 switch_console_free_matches(&matches);
1092 }
1093 }
1094
1095 switch_safe_free(dup_domain);
1096 }
1097
actual_sofia_presence_event_handler(switch_event_t * event)1098 static switch_event_t *actual_sofia_presence_event_handler(switch_event_t *event)
1099 {
1100 sofia_profile_t *profile = NULL;
1101 char *from = switch_event_get_header(event, "from");
1102 char *proto = switch_event_get_header(event, "proto");
1103 char *rpid = switch_event_get_header(event, "rpid");
1104 char *status = switch_event_get_header(event, "status");
1105 char *event_type = switch_event_get_header(event, "event_type");
1106 char *alt_event_type = switch_event_get_header(event, "alt_event_type");
1107 //char *event_subtype = switch_event_get_header(event, "event_subtype");
1108 char *sql = NULL;
1109 char *euser = NULL, *user = NULL, *host = NULL;
1110 char *call_info = switch_event_get_header(event, "presence-call-info");
1111 char *call_id = switch_event_get_header(event, "call-id");
1112 char *presence_source = switch_event_get_header(event, "presence-source");
1113 char *call_info_state = switch_event_get_header(event, "presence-call-info-state");
1114 const char *uuid = switch_event_get_header(event, "unique-id");
1115 switch_console_callback_match_t *matches = NULL;
1116 struct presence_helper helper = { 0 };
1117 int hup = 0;
1118 switch_event_t *s_event = NULL;
1119
1120 if (!mod_sofia_globals.running) {
1121 goto done;
1122 }
1123
1124 if (zstr(proto) || !strcasecmp(proto, "any")) {
1125 proto = SOFIA_CHAT_PROTO;
1126 }
1127
1128 //DUMP_EVENT(event);
1129
1130 if (rpid && !strcasecmp(rpid, "n/a")) {
1131 rpid = NULL;
1132 }
1133
1134 if (status && !strcasecmp(status, "n/a")) {
1135 status = NULL;
1136 }
1137
1138 if (!zstr(uuid) && !switch_ivr_uuid_exists(uuid)) {
1139 status = "CS_HANGUP";
1140 }
1141
1142
1143 if ((status && switch_stristr("CS_HANGUP", status)) || (!zstr(uuid) && !switch_ivr_uuid_exists(uuid))) {
1144 status = "Available";
1145 hup = 1;
1146 }
1147
1148 if (rpid) {
1149 rpid = sofia_presence_translate_rpid(rpid, status);
1150 }
1151
1152 if (event->event_id == SWITCH_EVENT_ROSTER) {
1153 if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
1154 switch_console_callback_match_node_t *m;
1155
1156 for (m = matches->head; m; m = m->next) {
1157 if ((profile = sofia_glue_find_profile(m->val))) {
1158 if (profile->pres_type != PRES_TYPE_FULL) {
1159
1160
1161 if (!mod_sofia_globals.profile_hash) {
1162 switch_console_free_matches(&matches);
1163 sofia_glue_release_profile(profile);
1164 goto done;
1165 }
1166
1167 if (from) {
1168
1169 sql = switch_mprintf("update sip_subscriptions set version=version+1 where hostname='%q' and profile_name='%q' and "
1170 "sip_subscriptions.event='presence' and sip_subscriptions.full_from like '%%%q%%'",
1171 mod_sofia_globals.hostname, profile->name, from);
1172
1173 if (mod_sofia_globals.debug_presence > 1) {
1174 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql);
1175 }
1176
1177 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
1178
1179
1180 sql = switch_mprintf("select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,"
1181 "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,"
1182 "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
1183 "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
1184 "sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip"
1185 ",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'','','','','sip',"
1186 " sip_subscriptions.full_to,sip_subscriptions.network_ip,sip_subscriptions.network_port "
1187 "from sip_subscriptions left join sip_presence on "
1188 "(sip_subscriptions.sub_to_user=sip_presence.sip_user and "
1189 "sip_subscriptions.sub_to_host=sip_presence.sip_host and "
1190 "sip_subscriptions.profile_name=sip_presence.profile_name and "
1191 "sip_presence.profile_name=sip_subscriptions.profile_name) "
1192 "where sip_subscriptions.hostname='%q' and sip_subscriptions.profile_name='%q' and "
1193 "sip_subscriptions.event='presence' and sip_subscriptions.full_from like '%%%q%%'",
1194 switch_str_nil(status), switch_str_nil(rpid), mod_sofia_globals.hostname, profile->name, from);
1195 } else {
1196
1197 sql = switch_mprintf("update sip_subscriptions set version=version+1 where hostname='%q' and profile_name='%q' and "
1198 "sip_subscriptions.event='presence'", mod_sofia_globals.hostname, profile->name);
1199
1200 if (mod_sofia_globals.debug_presence > 1) {
1201 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql);
1202 }
1203
1204 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
1205
1206 sql = switch_mprintf("select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,"
1207 "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,"
1208 "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
1209 "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
1210 "sip_subscriptions.accept,sip_subscriptions.profile_name,sip_subscriptions.network_ip"
1211 ",1,'%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'','','','','sip',"
1212 "sip_subscriptions.full_to,sip_subscriptions.network_ip,sip_subscriptions.network_port "
1213 "from sip_subscriptions left join sip_presence on "
1214 "(sip_subscriptions.sub_to_user=sip_presence.sip_user and "
1215 "sip_subscriptions.sub_to_host=sip_presence.sip_host and "
1216 "sip_subscriptions.profile_name=sip_presence.profile_name and "
1217 "sip_subscriptions.hostname = sip_presence.hostname) "
1218 "where sip_subscriptions.hostname='%q' and sip_subscriptions.profile_name='%q' and "
1219 "sip_subscriptions.event='presence'", switch_str_nil(status),
1220 switch_str_nil(rpid), mod_sofia_globals.hostname, profile->name);
1221 }
1222
1223 switch_assert(sql != NULL);
1224
1225
1226 if (mod_sofia_globals.debug_presence > 0) {
1227 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s is passive, skipping\n", (char *) profile->name);
1228 }
1229 sofia_glue_release_profile(profile);
1230 continue;
1231 }
1232 memset(&helper, 0, sizeof(helper));
1233 helper.profile = profile;
1234 helper.event = NULL;
1235 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_sub_callback, &helper);
1236 switch_safe_free(sql);
1237 sofia_glue_release_profile(profile);
1238 }
1239 }
1240 switch_console_free_matches(&matches);
1241 }
1242
1243 switch_safe_free(sql);
1244 goto done;
1245 }
1246
1247 if (zstr(event_type)) {
1248 event_type = "presence";
1249 }
1250
1251 if (zstr(alt_event_type)) {
1252 if (!strcasecmp(event_type, "presence")) {
1253 alt_event_type = "dialog";
1254 } else {
1255 alt_event_type = "presence";
1256 }
1257 }
1258
1259 if (from && (user = strdup(from))) {
1260 if ((host = strchr(user, '@'))) {
1261 char *p;
1262 *host++ = '\0';
1263 if ((p = strchr(host, '/'))) {
1264 *p = '\0';
1265 }
1266 } else {
1267 switch_safe_free(user);
1268 goto done;
1269 }
1270 if ((euser = strchr(user, '+')) && euser != user) {
1271 euser++;
1272 } else {
1273 euser = user;
1274 }
1275 } else {
1276 goto done;
1277 }
1278
1279 switch (event->event_id) {
1280 case SWITCH_EVENT_PRESENCE_PROBE:
1281 {
1282 char *probe_type = switch_event_get_header(event, "probe-type");
1283
1284 if (!probe_type || strcasecmp(probe_type, "dialog")) {
1285 /* NORMAL PROBE */
1286 do_normal_probe(event);
1287 } else {
1288 /* DIALOG PROBE */
1289 do_dialog_probe(event);
1290 }
1291 }
1292 goto done;
1293
1294 default:
1295 break;
1296 }
1297
1298 if (!mod_sofia_globals.profile_hash) {
1299 goto done;
1300 }
1301
1302 if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
1303 switch_console_callback_match_node_t *m;
1304
1305 for (m = matches->head; m; m = m->next) {
1306 struct dialog_helper dh = { { 0 } };
1307
1308 if ((profile = sofia_glue_find_profile(m->val))) {
1309 if (profile->pres_type != PRES_TYPE_FULL) {
1310 if (mod_sofia_globals.debug_presence > 0) {
1311 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s is passive, skipping\n", (char *) profile->name);
1312 }
1313 sofia_glue_release_profile(profile);
1314 continue;
1315 }
1316
1317
1318 if (mod_sofia_globals.debug_sla > 1) {
1319 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SLA EVENT:\n");
1320 DUMP_EVENT(event);
1321
1322 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CHECK CALL_INFO [%s]\n", switch_str_nil(call_info));
1323 }
1324
1325 if (call_info) {
1326
1327 if (uuid) {
1328 sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' where "
1329 "hostname='%q' and profile_name='%q' and uuid='%q'",
1330 call_info, call_info_state, mod_sofia_globals.hostname, profile->name, uuid);
1331 } else {
1332 sql = switch_mprintf("update sip_dialogs set call_info='%q', call_info_state='%q' where hostname='%q' and profile_name='%q' and "
1333 "((sip_dialogs.sip_from_user='%q' and sip_dialogs.sip_from_host='%q') or presence_id='%q@%q') and call_info='%q'",
1334
1335 call_info, call_info_state, mod_sofia_globals.hostname, profile->name, euser, host, euser, host, call_info);
1336
1337 }
1338
1339 if (mod_sofia_globals.debug_sla > 1) {
1340 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STATE SQL %s\n", sql);
1341 }
1342 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
1343
1344
1345
1346 if (mod_sofia_globals.debug_sla > 1) {
1347 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PROCESS PRESENCE EVENT\n");
1348 }
1349
1350 sync_sla(profile, euser, host, SWITCH_TRUE, SWITCH_TRUE, call_id);
1351 }
1352
1353 if (!strcmp(proto, "dp")) {
1354 sql = switch_mprintf("update sip_presence set rpid='%q',status='%q' where hostname='%q' and profile_name='%q' and "
1355 "sip_user='%q' and sip_host='%q'",
1356 rpid, status, mod_sofia_globals.hostname, profile->name, euser, host);
1357 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
1358 proto = SOFIA_CHAT_PROTO;
1359 }
1360
1361 if (zstr(uuid)) {
1362
1363 sql = switch_mprintf("select state,status,rpid,presence_id,uuid from sip_dialogs "
1364 "where call_info_state != 'seized' and hostname='%q' and profile_name='%q' and "
1365 "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc",
1366 mod_sofia_globals.hostname, profile->name, euser, host, euser, host);
1367 } else {
1368 sql = switch_mprintf("select state,status,rpid,presence_id,uuid from sip_dialogs "
1369 "where uuid != '%q' and call_info_state != 'seized' and hostname='%q' and profile_name='%q' and "
1370 "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') order by rcd desc",
1371 uuid, mod_sofia_globals.hostname, profile->name, euser, host, euser, host);
1372 }
1373
1374 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_dialog_callback, &dh);
1375
1376 if (mod_sofia_globals.debug_presence > 0) {
1377 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "CHECK SQL: %s@%s [%s]\nhits: %d\n", euser, host, sql, dh.hits);
1378 }
1379
1380 switch_safe_free(sql);
1381
1382 if (hup && dh.hits > 0) {
1383 /* sigh, mangle this packet to simulate a call that is up instead of hungup */
1384 hup = 0;
1385 event->flags |= EF_UNIQ_HEADERS;
1386
1387 if (!strcasecmp(dh.state, "early")) {
1388 status = "CS_ROUTING";
1389 if (rpid) {
1390 rpid = sofia_presence_translate_rpid(rpid, status);
1391 }
1392
1393 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Answer-State", "early");
1394 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", status);
1395 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-State", status);
1396 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Call-State", "EARLY");
1397 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "astate", "early");
1398 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "early");
1399 } else {
1400 status = "CS_EXECUTE";
1401 if (rpid) {
1402 rpid = sofia_presence_translate_rpid(rpid, status);
1403 }
1404
1405 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Answer-State", "answered");
1406 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", status);
1407 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-State", status);
1408 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Channel-Call-State", "ACTIVE");
1409 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "astate", "confirmed");
1410 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed");
1411 }
1412 }
1413
1414
1415
1416 if (zstr(call_id) && (dh.hits && presence_source && (!strcasecmp(presence_source, "register") || switch_stristr("register", status)))) {
1417 sofia_glue_release_profile(profile);
1418 goto done;
1419 }
1420
1421 if (zstr(call_id)) {
1422
1423 sql = switch_mprintf("update sip_subscriptions set version=version+1 where hostname='%q' and profile_name='%q' and "
1424 "sip_subscriptions.event != 'line-seize' "
1425 "and sip_subscriptions.proto='%q' and (event='%q' or event='%q') and sub_to_user='%q' and "
1426 "(sub_to_host='%q' or sub_to_host='%q' or sub_to_host='%q' or "
1427 "presence_hosts like '%%%q%%') and "
1428 "(sip_subscriptions.profile_name = '%q' or presence_hosts like '%%%q%%')",
1429 mod_sofia_globals.hostname, profile->name,
1430 proto, event_type, alt_event_type, euser, host, profile->sipip,
1431 profile->extsipip ? profile->extsipip : "N/A", host, profile->name, host);
1432
1433
1434 if (mod_sofia_globals.debug_presence > 1) {
1435 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql);
1436 }
1437
1438 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
1439
1440
1441
1442 sql = switch_mprintf("select distinct sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,"
1443 "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,"
1444 "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
1445 "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
1446 "sip_subscriptions.accept,sip_subscriptions.profile_name"
1447 ",'%q','%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'%q','%q',"
1448 "sip_subscriptions.version, '%q',sip_subscriptions.orig_proto,sip_subscriptions.full_to,"
1449 "sip_subscriptions.network_ip, sip_subscriptions.network_port "
1450 "from sip_subscriptions "
1451 "left join sip_presence on "
1452 "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
1453 "sip_subscriptions.profile_name=sip_presence.profile_name and sip_subscriptions.hostname=sip_presence.hostname) "
1454
1455 "where sip_subscriptions.hostname='%q' and sip_subscriptions.profile_name='%q' and "
1456 "sip_subscriptions.event != 'line-seize' and "
1457 "sip_subscriptions.proto='%q' and "
1458 "(event='%q' or event='%q') and sub_to_user='%q' "
1459 "and (sub_to_host='%q' or sub_to_host='%q' or sub_to_host='%q' or presence_hosts like '%%%q%%') ",
1460
1461
1462 switch_str_nil(status), switch_str_nil(rpid), host,
1463 dh.status,dh.rpid,dh.presence_id, mod_sofia_globals.hostname, profile->name, proto,
1464 event_type, alt_event_type, euser, host, profile->sipip,
1465 profile->extsipip ? profile->extsipip : "N/A", host);
1466 } else {
1467
1468 sql = switch_mprintf("update sip_subscriptions set version=version+1 where sip_subscriptions.event != 'line-seize' and "
1469 "sip_subscriptions.call_id='%q'", call_id);
1470
1471
1472
1473 if (mod_sofia_globals.debug_presence > 1) {
1474 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql);
1475 }
1476
1477 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
1478
1479
1480 sql = switch_mprintf("select distinct sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host,"
1481 "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event,"
1482 "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from,"
1483 "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent,"
1484 "sip_subscriptions.accept,sip_subscriptions.profile_name"
1485 ",'%q','%q','%q',sip_presence.status,sip_presence.rpid,sip_presence.open_closed,'%q','%q',"
1486 "sip_subscriptions.version, '%q',sip_subscriptions.orig_proto,sip_subscriptions.full_to,"
1487 "sip_subscriptions.network_ip, sip_subscriptions.network_port "
1488 "from sip_subscriptions "
1489 "left join sip_presence on "
1490 "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and "
1491 "sip_subscriptions.profile_name=sip_presence.profile_name and sip_subscriptions.hostname=sip_presence.hostname) "
1492
1493 "where sip_subscriptions.hostname='%q' and sip_subscriptions.profile_name='%q' and "
1494 "sip_subscriptions.event != 'line-seize' and "
1495 "sip_subscriptions.call_id='%q'",
1496
1497 switch_str_nil(status), switch_str_nil(rpid), host,
1498 dh.status,dh.rpid,dh.presence_id, mod_sofia_globals.hostname, profile->name, call_id);
1499
1500 }
1501
1502 helper.hup = hup;
1503 helper.calls_up = dh.hits;
1504 helper.profile = profile;
1505 helper.event = event;
1506 SWITCH_STANDARD_STREAM(helper.stream);
1507 switch_assert(helper.stream.data);
1508
1509 if (mod_sofia_globals.debug_presence > 0) {
1510 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s START_PRESENCE_SQL (%s)\n",
1511 event->event_id == SWITCH_EVENT_PRESENCE_IN ? "IN" : "OUT", profile->name);
1512 }
1513
1514 if (mod_sofia_globals.debug_presence) {
1515 char *buf;
1516 switch_event_serialize(event, &buf, SWITCH_FALSE);
1517 switch_assert(buf);
1518 if (mod_sofia_globals.debug_presence > 1) {
1519 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DUMP PRESENCE SQL:\n%s\nEVENT DUMP:\n%s\n", sql, buf);
1520 } else {
1521 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "EVENT DUMP:\n%s\n", buf);
1522 }
1523 free(buf);
1524 }
1525
1526 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_sub_callback, &helper);
1527 switch_safe_free(sql);
1528
1529 if (mod_sofia_globals.debug_presence > 0) {
1530 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s END_PRESENCE_SQL (%s)\n",
1531 event->event_id == SWITCH_EVENT_PRESENCE_IN ? "IN" : "OUT", profile->name);
1532 }
1533
1534 #if 0
1535 if (hup && dh.hits < 1) {
1536 /* so many phones get confused when whe hangup we have to reprobe to get them all to reset to absolute states so the lights stay correct */
1537 if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
1538 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
1539 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name);
1540 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
1541 switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", euser, host);
1542 switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", euser, host);
1543 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event_type", "presence");
1544 switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
1545 sofia_event_fire(profile, &s_event);
1546 }
1547 }
1548 #endif
1549
1550 if (!zstr((char *) helper.stream.data)) {
1551 char *this_sql = (char *) helper.stream.data;
1552 char *next = NULL;
1553 char *last = NULL;
1554
1555 do {
1556 if ((next = strchr(this_sql, ';'))) {
1557 *next++ = '\0';
1558 while (*next == '\n' || *next == ' ' || *next == '\r') {
1559 *next++ = '\0';
1560 }
1561 }
1562
1563 if (!zstr(this_sql) && (!last || strcmp(last, this_sql))) {
1564 sofia_glue_execute_sql(profile, &this_sql, SWITCH_FALSE);
1565 last = this_sql;
1566 }
1567 this_sql = next;
1568 } while (this_sql);
1569 }
1570 switch_safe_free(helper.stream.data);
1571 helper.stream.data = NULL;
1572
1573 sofia_glue_release_profile(profile);
1574 }
1575 }
1576 switch_console_free_matches(&matches);
1577 }
1578
1579 done:
1580
1581 switch_safe_free(sql);
1582 switch_safe_free(user);
1583
1584 return s_event;
1585 }
1586
1587 static int EVENT_THREAD_RUNNING = 0;
1588 static int EVENT_THREAD_STARTED = 0;
1589
do_flush(void)1590 static void do_flush(void)
1591 {
1592 void *pop = NULL;
1593
1594 while (mod_sofia_globals.presence_queue && switch_queue_trypop(mod_sofia_globals.presence_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
1595 switch_event_t *event = (switch_event_t *) pop;
1596 switch_event_destroy(&event);
1597 }
1598
1599 }
1600
sofia_presence_event_thread_run(switch_thread_t * thread,void * obj)1601 void *SWITCH_THREAD_FUNC sofia_presence_event_thread_run(switch_thread_t *thread, void *obj)
1602 {
1603 void *pop;
1604 int done = 0;
1605
1606 switch_mutex_lock(mod_sofia_globals.mutex);
1607 if (!EVENT_THREAD_RUNNING) {
1608 EVENT_THREAD_RUNNING++;
1609 mod_sofia_globals.threads++;
1610 } else {
1611 done = 1;
1612 }
1613 switch_mutex_unlock(mod_sofia_globals.mutex);
1614
1615 if (done) {
1616 return NULL;
1617 }
1618
1619 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Thread Started\n");
1620
1621 while (mod_sofia_globals.running == 1) {
1622 int count = 0;
1623
1624 if (switch_queue_pop(mod_sofia_globals.presence_queue, &pop) == SWITCH_STATUS_SUCCESS) {
1625 switch_event_t *event = (switch_event_t *) pop;
1626
1627 if (!pop) {
1628 break;
1629 }
1630
1631 if (mod_sofia_globals.presence_flush) {
1632 switch_mutex_lock(mod_sofia_globals.mutex);
1633 if (mod_sofia_globals.presence_flush) {
1634 do_flush();
1635 mod_sofia_globals.presence_flush = 0;
1636 }
1637 switch_mutex_unlock(mod_sofia_globals.mutex);
1638 }
1639
1640 switch(event->event_id) {
1641 case SWITCH_EVENT_MESSAGE_WAITING:
1642 actual_sofia_presence_mwi_event_handler(event);
1643 break;
1644 case SWITCH_EVENT_CONFERENCE_DATA:
1645 conference_data_event_handler(event);
1646 break;
1647 default:
1648 do {
1649 switch_event_t *ievent = event;
1650 event = actual_sofia_presence_event_handler(ievent);
1651 switch_event_destroy(&ievent);
1652 } while (event);
1653 break;
1654 }
1655
1656 switch_event_destroy(&event);
1657 count++;
1658 }
1659 }
1660
1661 do_flush();
1662
1663 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Event Thread Ended\n");
1664
1665 switch_mutex_lock(mod_sofia_globals.mutex);
1666 mod_sofia_globals.threads--;
1667 EVENT_THREAD_RUNNING = EVENT_THREAD_STARTED = 0;
1668 switch_mutex_unlock(mod_sofia_globals.mutex);
1669
1670 return NULL;
1671 }
1672
sofia_presence_event_thread_start(void)1673 void sofia_presence_event_thread_start(void)
1674 {
1675 //switch_thread_t *thread;
1676 switch_threadattr_t *thd_attr = NULL;
1677 int done = 0;
1678
1679 switch_mutex_lock(mod_sofia_globals.mutex);
1680 if (!EVENT_THREAD_STARTED) {
1681 EVENT_THREAD_STARTED++;
1682 } else {
1683 done = 1;
1684 }
1685 switch_mutex_unlock(mod_sofia_globals.mutex);
1686
1687 if (done) {
1688 return;
1689 }
1690
1691 switch_threadattr_create(&thd_attr, mod_sofia_globals.pool);
1692 //switch_threadattr_detach_set(thd_attr, 1);
1693 switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
1694 switch_threadattr_priority_set(thd_attr, SWITCH_PRI_IMPORTANT);
1695 switch_thread_create(&mod_sofia_globals.presence_thread, thd_attr, sofia_presence_event_thread_run, NULL, mod_sofia_globals.pool);
1696 }
1697
1698
sofia_presence_event_handler(switch_event_t * event)1699 void sofia_presence_event_handler(switch_event_t *event)
1700 {
1701 switch_event_t *cloned_event;
1702
1703 if (!EVENT_THREAD_STARTED) {
1704 sofia_presence_event_thread_start();
1705 switch_yield(500000);
1706 }
1707
1708 switch_event_dup(&cloned_event, event);
1709 switch_assert(cloned_event);
1710
1711 if (switch_queue_trypush(mod_sofia_globals.presence_queue, cloned_event) != SWITCH_STATUS_SUCCESS) {
1712 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Presence queue overloaded.... Flushing queue\n");
1713 switch_mutex_lock(mod_sofia_globals.mutex);
1714 mod_sofia_globals.presence_flush = 1;
1715 switch_mutex_unlock(mod_sofia_globals.mutex);
1716 switch_event_destroy(&cloned_event);
1717 }
1718
1719
1720 }
1721
1722
sofia_presence_sub_reg_callback(void * pArg,int argc,char ** argv,char ** columnNames)1723 static int sofia_presence_sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
1724 {
1725 sofia_profile_t *profile = (sofia_profile_t *) pArg;
1726 char *user = argv[3];
1727 char *host = argv[2];
1728 switch_event_t *event;
1729 char *event_name = argv[5];
1730 char *expires = argv[10];
1731
1732
1733
1734 if (!strcasecmp(event_name, "message-summary")) {
1735
1736 if (switch_event_create(&event, SWITCH_EVENT_MESSAGE_QUERY) == SWITCH_STATUS_SUCCESS) {
1737 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Message-Account", "sip:%s@%s", user, host);
1738 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "VM-Sofia-Profile", profile->name);
1739 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "VM-sub-call-id", argv[7]);
1740
1741 if (mod_sofia_globals.debug_presence > 0) {
1742 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Create MESSAGE QUERY EVENT...\n");
1743 DUMP_EVENT(event);
1744 }
1745
1746
1747 sofia_event_fire(profile, &event);
1748 }
1749 return 0;
1750 }
1751
1752 if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
1753 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
1754 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
1755 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
1756 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
1757 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
1758 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe");
1759 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event_name);
1760 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "expires", expires);
1761 sofia_event_fire(profile, &event);
1762 }
1763
1764 return 0;
1765 }
1766
sofia_presence_resub_callback(void * pArg,int argc,char ** argv,char ** columnNames)1767 static int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames)
1768 {
1769 struct resub_helper *h = (struct resub_helper *) pArg;
1770 sofia_profile_t *profile = h->profile;
1771 char *user = argv[0];
1772 char *host = argv[1];
1773 char *status = argv[2];
1774 char *rpid = argv[3];
1775 char *proto = argv[4];
1776 char *call_id = NULL;
1777 char *presence_id = NULL;
1778 char *to_user = NULL;
1779 char *uuid = NULL;
1780 char *state = NULL;
1781 char *direction = NULL;
1782 switch_event_t *event;
1783 char to_buf[128] = "";
1784 switch_event_header_t *hp;
1785 char *free_me = NULL;
1786 int do_event = 1, i;
1787
1788
1789 if (mod_sofia_globals.debug_presence > 1) {
1790 for (i = 0; i < argc; i++) {
1791 switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_WARNING, "sofia_presence_resub_callback: %d [%s]=[%s]\n", i, columnNames[i], argv[i]);
1792 }
1793 }
1794
1795 if (argc > 5) {
1796 uuid = argv[5];
1797 state = switch_str_nil(argv[6]);
1798 direction = switch_str_nil(argv[7]);
1799 if (argc > 8) {
1800 switch_set_string(to_buf, argv[8]);
1801 switch_url_decode(to_buf);
1802 to_user = to_buf;
1803 }
1804 if (argc > 10 && !zstr(argv[10]) && !zstr(argv[11])) {
1805 status = argv[10];
1806 rpid = argv[11];
1807 }
1808
1809 if (argc > 12 && !zstr(argv[12]) && strchr(argv[12], '@')) {
1810 char *p;
1811
1812 presence_id = argv[12];
1813 free_me = strdup(presence_id);
1814 switch_assert(free_me);
1815 if ((p = strchr(free_me, '@'))) *p = '\0';
1816 user = free_me;
1817 }
1818
1819 if (argc > 16) {
1820 call_id = argv[16];
1821 }
1822
1823 }
1824
1825 if (!zstr(uuid) && !switch_ivr_uuid_exists(uuid)) {
1826 if (mod_sofia_globals.debug_presence > 0) {
1827 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s SKIPPING NOT FOUND UUID %s\n", profile->name, uuid);
1828 }
1829 do_event = 0;
1830 }
1831
1832 if (zstr(proto)) {
1833 proto = NULL;
1834 }
1835
1836 if (mod_sofia_globals.debug_presence > 0) {
1837 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s PRESENCE_PROBE %s@%s\n", profile->name, user, host);
1838 }
1839
1840 if (do_event && switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
1841 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", proto ? proto : SOFIA_CHAT_PROTO);
1842 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
1843 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
1844
1845 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
1846
1847 if (h->noreg) {
1848 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Force-Direction", "inbound");
1849 }
1850
1851 if (!zstr(call_id)) {
1852 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-id", call_id);
1853 }
1854
1855 //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "resub", "true");
1856 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", status);
1857 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
1858 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
1859 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
1860 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", 0);
1861
1862 if (!zstr(to_user)) {
1863 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to-user", to_user);
1864 }
1865
1866 if (zstr(state)) {
1867 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
1868 //switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "resubscribe");
1869 } else {
1870 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
1871 if (uuid) {
1872 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", uuid);
1873 }
1874 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", state);
1875 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "astate", state);
1876 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "presence-call-direction", direction);
1877 }
1878
1879 if (h->event) {
1880 for (hp = h->event->headers; hp; hp = hp->next) {
1881 if (!strncasecmp(hp->name, "fwd-", 4)) {
1882 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, hp->name + 4, hp->value);
1883 }
1884 }
1885 }
1886
1887 sofia_event_fire(profile, &event);
1888 }
1889
1890 switch_safe_free(free_me);
1891
1892
1893 h->rowcount++;
1894
1895
1896 return 0;
1897 }
1898
get_display_name_from_contact(const char * in,char * dst)1899 char *get_display_name_from_contact(const char *in, char* dst)
1900 {
1901 // name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
1902 // display-name = *(token LWS)/ quoted-string
1903 // return whatever comes before the left angle bracket, stripped of whitespace and quotes
1904 char *p;
1905 char *buf;
1906
1907 strcpy(dst, "");
1908 if (strchr(in, '<') && strchr(in, '>')) {
1909 buf = strdup(in);
1910 switch_assert(buf);
1911 p = strchr(buf, '<');
1912 *p = '\0';
1913 if (!zstr(buf)) {
1914 p = switch_strip_whitespace(buf);
1915 if (p) {
1916 if (*p == '"') {
1917 if (end_of(p+1) == '"') {
1918 char *q = strdup(p + 1);
1919 switch_assert(q);
1920 end_of(q) = '\0';
1921 strcpy(dst, q);
1922 switch_safe_free(q);
1923 }
1924 } else {
1925 strcpy(dst, p);
1926 }
1927 switch_safe_free(p);
1928 }
1929 }
1930 switch_safe_free(buf);
1931 }
1932 return dst;
1933 }
1934
sofia_dialog_probe_callback(void * pArg,int argc,char ** argv,char ** columnNames)1935 static int sofia_dialog_probe_callback(void *pArg, int argc, char **argv, char **columnNames)
1936 {
1937 struct rfc4235_helper *h = (struct rfc4235_helper *) pArg;
1938
1939 char *proto = argv[0];
1940 char *user = argv[1];
1941 char *host = argv[2];
1942 char *uuid = argv[3];
1943 char *call_id = argv[4];
1944 char *state = argv[5];
1945 char *direction = argv[6];
1946 char *to_user = argv[7];
1947 char *to_host = argv[8];
1948 char *from_user = argv[9];
1949 // char *from_host = argv[10];
1950 char *contact = switch_str_nil(argv[11]);
1951 char *contact_user = switch_str_nil(argv[12]);
1952 char *contact_host = switch_str_nil(argv[13]);
1953 char *to_tag = switch_str_nil(argv[14]);
1954 char *from_tag = switch_str_nil(argv[15]);
1955 char *orig_proto = switch_str_nil(argv[16]);
1956
1957 const char *event_status = "";
1958 char *data = NULL, *tmp;
1959 char key[256] = "";
1960 char *local_user;
1961 char *local_host;
1962 char *remote_user;
1963 char *remote_host;
1964 char *remote_uri;
1965 char *local_user_param = NULL;
1966 char remote_display_buf[512];
1967 char *buf_to_free = NULL;
1968 int bInternal = 0;
1969 int i;
1970 int skip_proto = 0;
1971
1972 if (mod_sofia_globals.debug_presence > 1) {
1973 for (i = 0; i < argc; i++) {
1974 switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_WARNING, "sofia_dialog_probe_callback: %d [%s]=[%s]\n", i, columnNames[i], argv[i]);
1975 }
1976 }
1977
1978 if (zstr(to_user) || zstr(contact_user)) {
1979 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "sofia_dialog_probe_callback: not enough info to generate a dialog entry\n");
1980 return 0;
1981 }
1982
1983 // Usually we report the dialogs FROM the probed user. The exception is when the monitored endpoint is internal,
1984 // and its presence_id is set in the dialplan. Reverse the direction if this is not a registered entity.
1985 if (!strcmp(direction, "inbound") && strcmp(user, from_user) ) {
1986 // If inbound and the entity is not the caller (i.e. internal to FS), then the direction is reversed
1987 // because it is not going through the B2BUA
1988 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sofia_dialog_probe_callback: endpt is internal\n");
1989 direction = !strcasecmp(direction, "outbound") ? "inbound" : "outbound";
1990 bInternal = 1;
1991 }
1992
1993 if (!strcasecmp(direction, "outbound")) {
1994 direction = "recipient";
1995 }
1996 else {
1997 direction = "initiator";
1998 }
1999
2000 if (!zstr(orig_proto) && !strcmp(orig_proto, SOFIA_CHAT_PROTO)) {
2001 skip_proto = 1;
2002 }
2003
2004 local_host = to_host;
2005 if (proto && !strcasecmp(proto, "queue")) {
2006 local_user = to_user;
2007 local_user_param = switch_mprintf(";proto=%s", proto);
2008 event_status = "hold";
2009 if (skip_proto) {
2010 buf_to_free = switch_mprintf("sip:%s", to_user);
2011 } else {
2012 buf_to_free = switch_mprintf("sip:queue+%s", to_user);
2013 }
2014 remote_uri = buf_to_free;
2015 strcpy(remote_display_buf, "queue");
2016 remote_user = to_user;
2017 remote_host = local_host;
2018 }
2019 else if (proto && !strcasecmp(proto, "park")) {
2020 local_user = to_user;
2021 local_user_param = switch_mprintf(";proto=%s", proto);
2022 event_status = "hold";
2023 if (skip_proto) {
2024 buf_to_free = switch_mprintf("sip:%s", to_user);
2025 } else {
2026 buf_to_free = switch_mprintf("sip:park+%s", to_user);
2027 }
2028 remote_uri = buf_to_free;
2029 strcpy(remote_display_buf, "park");
2030 remote_user = to_user;
2031 remote_host = local_host;
2032 }
2033 else if (proto && !strcasecmp(proto, "pickup")) {
2034 local_user = to_user;
2035 local_user_param = switch_mprintf(";proto=%s", proto);
2036 event_status = "hold";
2037 if (skip_proto) {
2038 buf_to_free = switch_mprintf("sip:%s", to_user);
2039 } else {
2040 buf_to_free = switch_mprintf("sip:pickup+%s", to_user);
2041 }
2042 remote_uri = buf_to_free;
2043 strcpy(remote_display_buf, "pickup");
2044 remote_user = to_user;
2045 remote_host = local_host;
2046 }
2047 else if (proto && !strcasecmp(proto, "conf")) {
2048 local_user = to_user;
2049 local_user_param = switch_mprintf(";proto=%s", proto);
2050 if (skip_proto) {
2051 buf_to_free = switch_mprintf("sip:%s@%s", to_user, host);
2052 } else {
2053 buf_to_free = switch_mprintf("sip:conf+%s@%s", to_user, host);
2054 }
2055 remote_uri = buf_to_free;
2056 strcpy(remote_display_buf, "conference");
2057 remote_user = to_user;
2058 remote_host = local_host;
2059 }
2060 else if (bInternal) {
2061 local_user = to_user;
2062 get_display_name_from_contact(contact, remote_display_buf);
2063 buf_to_free = sofia_glue_strip_uri(contact);
2064 remote_uri = buf_to_free;
2065 remote_user = contact_user;
2066 remote_host = contact_host;
2067 } else {
2068 local_user = from_user;
2069 buf_to_free = switch_mprintf("**%s@%s", from_user, local_host);
2070 remote_uri = buf_to_free;
2071 strcpy(remote_display_buf, to_user);
2072 remote_user = to_user;
2073 remote_host = local_host;
2074 }
2075
2076 switch_snprintf(key, sizeof(key), "%s%s", user, host);
2077 data = switch_core_hash_find(h->hash, key);
2078 if (!data) {
2079 data = "";
2080 }
2081 tmp = switch_core_sprintf(h->pool, "%s"
2082 "<dialog id=\"%s\" call-id=\"%s\" local-tag=\"%s\" remote-tag=\"%s\" direction=\"%s\">\n"
2083 " <state>%s</state>\n"
2084 " <local>\n"
2085 " <identity display=\"%s\">sip:%s@%s%s</identity>\n"
2086 " <target uri=\"sip:%s@%s\">\n"
2087 " <param pname=\"+sip.rendering\" pvalue=\"%s\"/>\n"
2088 " </target>\n"
2089 " </local>\n"
2090 " <remote>\n"
2091 " <identity display=\"%s\">sip:%s@%s</identity>\n"
2092 " <target uri=\"%s\"/>\n"
2093 " </remote>\n"
2094 "</dialog>\n",
2095 data,
2096 uuid, call_id, to_tag, from_tag, direction,
2097 state,
2098 local_user, local_user, local_host, switch_str_nil(local_user_param),
2099 local_user, local_host,
2100 !strcasecmp(event_status, "hold") ? "no" : "yes",
2101 remote_display_buf, remote_user, remote_host,
2102 remote_uri
2103 );
2104 switch_core_hash_insert(h->hash, key, tmp);
2105 switch_safe_free(local_user_param);
2106 switch_safe_free(buf_to_free);
2107
2108 h->rowcount++;
2109
2110 return 0;
2111 }
2112
2113 #define SOFIA_PRESENCE_COLLISION_DELTA 50
2114 #define SOFIA_PRESENCE_ROLLOVER_YEAR (86400 * 365 * SOFIA_PRESENCE_COLLISION_DELTA)
check_presence_epoch(void)2115 static uint32_t check_presence_epoch(void)
2116 {
2117 time_t now = switch_epoch_time_now(NULL);
2118 uint32_t callsequence = (uint32_t)((now - mod_sofia_globals.presence_epoch) * SOFIA_PRESENCE_COLLISION_DELTA);
2119
2120 if (!mod_sofia_globals.presence_year || callsequence >= SOFIA_PRESENCE_ROLLOVER_YEAR) {
2121 struct tm tm;
2122 switch_mutex_lock(mod_sofia_globals.mutex);
2123 tm = *(localtime(&now));
2124
2125 if (tm.tm_year != mod_sofia_globals.presence_year) {
2126 mod_sofia_globals.presence_epoch = (uint32_t)now - (tm.tm_yday * 86400) - (tm.tm_hour * 60 * 60) - (tm.tm_min * 60) - tm.tm_sec;
2127 mod_sofia_globals.presence_year = tm.tm_year;
2128 callsequence = (uint32_t)(((uint32_t)now - mod_sofia_globals.presence_epoch) * SOFIA_PRESENCE_COLLISION_DELTA);
2129 }
2130
2131 switch_mutex_unlock(mod_sofia_globals.mutex);
2132 }
2133
2134 return callsequence;
2135 }
2136
sofia_presence_get_cseq(sofia_profile_t * profile)2137 uint32_t sofia_presence_get_cseq(sofia_profile_t *profile)
2138 {
2139 uint32_t callsequence;
2140 int diff = 0;
2141
2142 switch_mutex_lock(profile->ireg_mutex);
2143
2144 callsequence = check_presence_epoch();
2145
2146 if (profile->last_cseq) {
2147 diff = callsequence - profile->last_cseq;
2148 if (diff <= 0 && diff > -100000) {
2149 callsequence = ++profile->last_cseq;
2150 }
2151 }
2152
2153 profile->last_cseq = callsequence;
2154
2155 switch_mutex_unlock(profile->ireg_mutex);
2156
2157 return callsequence;
2158
2159 }
2160
2161
2162 #define send_presence_notify(_a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l) \
2163 _send_presence_notify(_a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l,__FILE__, __SWITCH_FUNC__, __LINE__)
2164
_send_presence_notify(sofia_profile_t * profile,const char * full_to,const char * full_from,const char * o_contact,const char * expires,const char * call_id,const char * event,const char * remote_ip,const char * remote_port,const char * ct,const char * pl,const char * call_info,const char * file,const char * func,int line)2165 static void _send_presence_notify(sofia_profile_t *profile,
2166 const char *full_to,
2167 const char *full_from,
2168 const char *o_contact,
2169 const char *expires,
2170 const char *call_id,
2171 const char *event,
2172 const char *remote_ip,
2173 const char *remote_port,
2174 const char *ct,
2175 const char *pl,
2176 const char *call_info,
2177 const char *file, const char *func, int line
2178 )
2179 {
2180 char sstr[128] = "";
2181 nua_handle_t *nh;
2182 int exptime = 0;
2183 char expires_str[10] = "";
2184 sip_cseq_t *cseq = NULL;
2185 uint32_t callsequence;
2186 uint32_t now = (uint32_t) switch_epoch_time_now(NULL);
2187
2188 sofia_destination_t *dst = NULL;
2189 char *contact_str, *contact, *user_via = NULL, *send_contact = NULL;
2190 char *route_uri = NULL, *o_contact_dup = NULL, *tmp, *to_uri, *dcs = NULL;
2191 const char *tp;
2192 char *cparams = NULL;
2193 char *path = NULL;
2194
2195 if (zstr(full_to) || zstr(full_from) || zstr(o_contact)) {
2196 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "MISSING DATA TO SEND NOTIFY.\n");
2197 return;
2198 }
2199
2200 if ((cparams = strstr(o_contact, ";_;"))) {
2201 cparams += 3;
2202 }
2203
2204 if (!switch_stristr("fs_nat=yes", o_contact)) {
2205 path = sofia_glue_get_path_from_contact((char *) o_contact);
2206 }
2207
2208 dst = sofia_glue_get_destination((char *) o_contact);
2209 switch_assert(dst);
2210
2211 if (!zstr(dst->contact)) {
2212 contact = sofia_glue_get_url_from_contact(dst->contact, 1);
2213 } else {
2214 contact = strdup(o_contact);
2215 }
2216
2217 if (dst->route_uri) {
2218 route_uri = sofia_glue_strip_uri(dst->route_uri);
2219 tmp = (char *)route_uri;
2220 } else {
2221 tmp = (char *)o_contact;
2222 }
2223
2224 o_contact_dup = sofia_glue_get_url_from_contact(tmp, 1);
2225
2226 if ((tp = switch_stristr("transport=", o_contact_dup))) {
2227 tp += 10;
2228 }
2229
2230 if (zstr(tp)) {
2231 tp = "udp";
2232 }
2233
2234 if (!zstr(remote_ip) && sofia_glue_check_nat(profile, remote_ip)) {
2235 sofia_transport_t transport = sofia_glue_str2transport(tp);
2236
2237 switch (transport) {
2238 case SOFIA_TRANSPORT_TCP:
2239 contact_str = profile->tcp_public_contact;
2240 break;
2241 case SOFIA_TRANSPORT_TCP_TLS:
2242 contact_str = sofia_test_pflag(profile, PFLAG_TLS) ?
2243 profile->tls_public_contact : profile->tcp_public_contact;
2244 break;
2245 default:
2246 contact_str = profile->public_url;
2247 break;
2248 }
2249 user_via = sofia_glue_create_external_via(NULL, profile, transport);
2250 } else {
2251 sofia_transport_t transport = sofia_glue_str2transport(tp);
2252 switch (transport) {
2253 case SOFIA_TRANSPORT_TCP:
2254 contact_str = profile->tcp_contact;
2255 break;
2256 case SOFIA_TRANSPORT_TCP_TLS:
2257 contact_str = sofia_test_pflag(profile, PFLAG_TLS) ?
2258 profile->tls_contact : profile->tcp_contact;
2259 break;
2260 default:
2261 contact_str = profile->url;
2262 break;
2263 }
2264 }
2265
2266
2267 if ((to_uri = sofia_glue_get_url_from_contact((char *)full_to, 1))) {
2268 char *p;
2269
2270 if ((p = strstr(to_uri, "sip:"))) {
2271 char *q;
2272
2273 p += 4;
2274 if ((q = strchr(p, '@'))) {
2275 *q++ = '\0';
2276
2277 if ((dcs = switch_string_replace(contact_str, "mod_sofia", p))) {
2278 contact_str = dcs;
2279 }
2280
2281 }
2282 }
2283
2284 free(to_uri);
2285 }
2286
2287 if (expires) {
2288 long ltmp = atol(expires);
2289
2290 if (ltmp > 0) {
2291 exptime = (ltmp - now);
2292 } else {
2293 exptime = 0;
2294 }
2295 }
2296
2297 if (exptime <= 0) {
2298 switch_snprintf(sstr, sizeof(sstr), "terminated;reason=noresource");
2299 } else {
2300 switch_snprintf(sstr, sizeof(sstr), "active;expires=%u", (unsigned) exptime);
2301 }
2302
2303 if (mod_sofia_globals.debug_presence > 1 || mod_sofia_globals.debug_sla > 1) {
2304 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SEND PRES NOTIFY:\n"
2305 "file[%s]\nfunc[%s]\nline[%d]\n"
2306 "profile[%s]\nvia[%s]\nip[%s]\nport[%s]\nroute[%s]\ncontact[%s]\nto[%s]\nfrom[%s]\nurl[%s]\ncall_id[%s]\nexpires_str[%s]\n"
2307 "event[%s]\nct[%s]\npl[%s]\ncall_info[%s]\nexptime[%ld]\n",
2308 file, func, line,
2309 profile->name,
2310 switch_str_nil(user_via),
2311 remote_ip,
2312 remote_port,
2313 route_uri,
2314 o_contact,
2315 full_to,
2316 full_from,
2317 contact,
2318 call_id,
2319 expires_str,
2320 event,
2321 switch_str_nil(ct),
2322 switch_str_nil(pl),
2323 switch_str_nil(call_info),
2324 (long)exptime
2325 );
2326 }
2327
2328
2329 callsequence = sofia_presence_get_cseq(profile);
2330
2331 if (cparams) {
2332 send_contact = switch_mprintf("%s;%s", contact_str, cparams);
2333 contact_str = send_contact;
2334 }
2335
2336 nh = nua_handle(profile->nua, NULL, NUTAG_URL(contact), SIPTAG_CONTACT_STR(contact_str), TAG_END());
2337 cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY);
2338 nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
2339
2340
2341 nua_notify(nh,
2342 NUTAG_NEWSUB(1),
2343 TAG_IF(route_uri, NUTAG_PROXY(route_uri)),
2344 TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
2345 TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
2346 TAG_IF(path, SIPTAG_RECORD_ROUTE_STR(path)),
2347
2348 SIPTAG_FROM_STR(full_to),
2349 SIPTAG_TO_STR(full_from),
2350
2351 SIPTAG_CALL_ID_STR(call_id),
2352 TAG_IF(*expires_str, SIPTAG_EXPIRES_STR(expires_str)),
2353 SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
2354 SIPTAG_EVENT_STR(event),
2355 TAG_IF(!zstr(ct), SIPTAG_CONTENT_TYPE_STR(ct)),
2356 TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)),
2357 TAG_IF(!zstr(call_info), SIPTAG_CALL_INFO_STR(call_info)),
2358 TAG_IF(!exptime, SIPTAG_EXPIRES_STR("0")),
2359 SIPTAG_CSEQ(cseq),
2360 TAG_END());
2361
2362
2363 switch_safe_free(route_uri);
2364 switch_safe_free(dcs);
2365 switch_safe_free(contact);
2366
2367 sofia_glue_free_destination(dst);
2368 switch_safe_free(user_via);
2369 switch_safe_free(o_contact_dup);
2370 switch_safe_free(send_contact);
2371 switch_safe_free(path);
2372 }
2373
2374
sofia_dialog_probe_notify_callback(void * pArg,int argc,char ** argv,char ** columnNames)2375 static int sofia_dialog_probe_notify_callback(void *pArg, int argc, char **argv, char **columnNames)
2376 {
2377 struct rfc4235_helper *sh = (struct rfc4235_helper *) pArg;
2378 char key[256] = "";
2379 char *data = NULL;
2380 char *call_id = argv[0];
2381 char *expires = argv[1];
2382 char *user = argv[2];
2383 char *host = argv[3];
2384 char *event = argv[4];
2385 char *version = argv[5];
2386 char *notify_state = argv[6];
2387 char *full_to = argv[7];
2388 char *full_from = argv[8];
2389 char *contact = argv[9];
2390 char *remote_ip = argv[10];
2391 char *remote_port = argv[11];
2392
2393 switch_stream_handle_t stream = { 0 };
2394 char *to;
2395 const char *pl = NULL;
2396 const char *ct = "application/dialog-info+xml";
2397
2398 if (mod_sofia_globals.debug_presence > 0) {
2399 int i;
2400 for(i = 0; i < argc; i++) {
2401 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]);
2402 }
2403 }
2404
2405
2406 if (mod_sofia_globals.debug_presence > 0) {
2407 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
2408 "SEND DIALOG\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\n",
2409 user, host, user, host, call_id);
2410 }
2411
2412 to = switch_mprintf("sip:%s@%s", user, host);
2413
2414 SWITCH_STANDARD_STREAM(stream);
2415
2416 if (zstr(version)) {
2417 version = "0";
2418 }
2419
2420 stream.write_function(&stream,
2421 "<?xml version=\"1.0\"?>\n"
2422 "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" "
2423 "version=\"%s\" state=\"%s\" entity=\"%s\">\n",
2424 version,
2425 notify_state, to);
2426
2427 switch_snprintf(key, sizeof(key), "%s%s", user, host);
2428
2429 data = switch_core_hash_find(sh->hash, key);
2430
2431 if (data) {
2432 stream.write_function(&stream, "%s\n", data);
2433 }
2434
2435 stream.write_function(&stream, "</dialog-info>\n");
2436 pl = stream.data;
2437 ct = "application/dialog-info+xml";
2438
2439 if (mod_sofia_globals.debug_presence > 0 && pl) {
2440 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send payload:\n%s\n", pl);
2441 }
2442
2443
2444 send_presence_notify(sh->profile,
2445 full_to,
2446 full_from,
2447 contact,
2448 expires,
2449 call_id,
2450 event,
2451 remote_ip,
2452 remote_port,
2453 ct,
2454 pl,
2455 NULL
2456 );
2457
2458
2459 switch_safe_free(to);
2460 switch_safe_free(stream.data);
2461
2462 return 0;
2463 }
2464
translate_rpid(char * in)2465 static char *translate_rpid(char *in)
2466 {
2467 char *r = in;
2468
2469 if (in && (strstr(in, "null") || strstr(in, "NULL"))) {
2470 in = NULL;
2471 }
2472
2473 if (zstr(in)) {
2474 return NULL;
2475 }
2476
2477 if (!strcasecmp(in, "unknown")) {
2478 r = NULL;
2479 goto end;
2480 }
2481
2482 if (!strcasecmp(in, "busy")) {
2483 r = in;
2484 goto end;
2485 }
2486
2487 if (!strcasecmp(in, "unavailable")) {
2488 r = "away";
2489 goto end;
2490 }
2491
2492 if (!strcasecmp(in, "idle")) {
2493 r = "busy";
2494 }
2495
2496 end:
2497 return r;
2498 }
2499
2500
gen_pidf(char * user_agent,char * id,char * url,char * open,char * rpid,char * prpid,char * status,const char ** ct)2501 static char *gen_pidf(char *user_agent, char *id, char *url, char *open, char *rpid, char *prpid, char *status, const char **ct)
2502 {
2503 char *ret = NULL;
2504
2505 if (switch_stristr("polycom", user_agent)) {
2506 *ct = "application/xpidf+xml";
2507
2508 /* If unknown/none prpid is provided, just show the user as online. */
2509 if (!prpid || !strcasecmp(prpid, "unknown")) {
2510 prpid = "online";
2511 }
2512
2513 /* of course!, lets make a big deal over dashes. Now the stupidity is complete. */
2514 if (!strcmp(prpid, "on-the-phone")) {
2515 prpid = "onthephone";
2516 }
2517
2518 if (zstr(open)) {
2519 open = "open";
2520 }
2521
2522 ret = switch_mprintf("<?xml version=\"1.0\"?>\n"
2523 "<!DOCTYPE presence PUBLIC \"-//IETF//DTD RFCxxxx XPIDF 1.0//EN\" \"xpidf.dtd\">\n"
2524 "<presence>\n"
2525 " <status>\n"
2526 " <note>%s</note>\n"
2527 " </status>\n"
2528 " <presentity uri=\"%s;method=SUBSCRIBE\" />\n"
2529 " <atom id=\"%s\">\n"
2530 " <address uri=\"%s;user=ip\" priority=\"0.800000\">\n"
2531 " <status status=\"%s\" />\n"
2532 " <msnsubstatus substatus=\"%s\" />\n"
2533 " </address>\n"
2534 " </atom>\n"
2535 "</presence>\n", status, id, id, url, open, prpid);
2536 } else {
2537 char *xml_rpid = NULL;
2538
2539 *ct = "application/pidf+xml";
2540
2541 if (!strcasecmp(open, "closed")) {
2542 status = "Unregistered";
2543 prpid = NULL;
2544 }
2545
2546 if (!strncasecmp(status, "Registered", 10)) {
2547 status = "Available";
2548 }
2549
2550 if (!strcasecmp(status, "Available")) {
2551 prpid = NULL;
2552 }
2553
2554
2555 if (!strcasecmp(status, "Unregistered")) {
2556 prpid = NULL;
2557 open = "closed";
2558 }
2559
2560 if (zstr(rpid)) {
2561 prpid = NULL;
2562 }
2563
2564
2565 if (zstr(status) && !zstr(prpid)) {
2566 status = "Available";
2567 prpid = NULL;
2568 }
2569
2570 if (prpid) {
2571 xml_rpid = switch_mprintf(" <rpid:activities>\r\n"
2572 " <rpid:%s/>\n"
2573 " </rpid:activities>\n", prpid);
2574 }
2575
2576 ret = switch_mprintf("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> \n"
2577 "<presence xmlns='urn:ietf:params:xml:ns:pidf' \n"
2578 "xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model' \n"
2579 "xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid' \n"
2580 "xmlns:c='urn:ietf:params:xml:ns:pidf:cipid' entity='%s'>\n"
2581 " <tuple id='t6a5ed77e'>\n"
2582 " <status>\r\n"
2583 " <basic>%s</basic>\n"
2584 " </status>\n"
2585 " </tuple>\n"
2586 " <dm:person id='p06360c4a'>\n"
2587 "%s"
2588 " <dm:note>%s</dm:note>\n"
2589 " </dm:person>\n"
2590 "</presence>", id, open, switch_str_nil(xml_rpid), status);
2591
2592
2593 switch_safe_free(xml_rpid);
2594 }
2595
2596
2597 return ret;
2598 }
2599
sofia_presence_sub_callback(void * pArg,int argc,char ** argv,char ** columnNames)2600 static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames)
2601 {
2602 struct presence_helper *helper = (struct presence_helper *) pArg;
2603 char *pl = NULL;
2604 char *clean_id = NULL, *id = NULL;
2605 char *proto = argv[0];
2606 char *user = argv[1];
2607 char *host = argv[2];
2608 char *sub_to_user = argv[3];
2609 char *event = argv[5];
2610 char *contact = argv[6];
2611 char *call_id = argv[7];
2612 char *full_from = argv[8];
2613 //char *full_via = argv[9];
2614 char *expires = argv[10];
2615 char *user_agent = argv[11];
2616 char *profile_name = argv[13];
2617 uint32_t in = 0;
2618 char *status = argv[14];
2619 char *rpid = argv[15];
2620 char *sub_to_host = argv[16];
2621 char *open_closed = NULL;
2622 char *dialog_status = NULL;
2623 char *dialog_rpid = NULL;
2624 //char *default_dialog = "partial";
2625 char *default_dialog = "full";
2626 const char *ct = "no/idea";
2627
2628 char *to = NULL;
2629 char *open;
2630 char *prpid;
2631
2632 int is_dialog = 0;
2633 sofia_profile_t *ext_profile = NULL, *profile = helper->profile;
2634
2635 char status_line[256] = "";
2636 char *version = "0";
2637 char *presence_id = NULL;
2638 char *free_me = NULL;
2639 int holding = 0;
2640 char *orig_proto = NULL;
2641 int skip_proto = 0;
2642 char *full_to = NULL;
2643 char *ip = NULL;
2644 char *port = 0;
2645 const char *call_state = NULL;
2646 const char *astate = NULL;
2647 const char *event_status = NULL;
2648 const char *force_event_status = NULL;
2649 char *contact_str, *contact_stripped;
2650
2651 if (mod_sofia_globals.debug_presence > 0) {
2652 int i;
2653 for(i = 0; i < argc; i++) {
2654 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]);
2655 }
2656 DUMP_EVENT(helper->event);
2657 }
2658
2659 if (argc > 18) {
2660 if (!zstr(argv[17])) {
2661 status = argv[17];
2662 }
2663 if (!zstr(argv[18])) {
2664 rpid = argv[18];
2665 }
2666 open_closed = argv[19];
2667 }
2668
2669 if (argc > 20) {
2670 dialog_status = argv[20];
2671 dialog_rpid = argv[21];
2672 version = argv[22];
2673 presence_id = argv[23];
2674 orig_proto = argv[24];
2675 full_to = argv[25];
2676 ip = argv[26];
2677 port = argv[27];
2678 }
2679
2680 if (!zstr(ip) && sofia_glue_check_nat(profile, ip)) {
2681 char *ptr;
2682 if ((ptr = sofia_glue_find_parameter(contact, "transport="))) {
2683 sofia_transport_t transport = sofia_glue_str2transport( ptr + 10 );
2684
2685 switch (transport) {
2686 case SOFIA_TRANSPORT_TCP:
2687 contact_str = profile->tcp_public_contact;
2688 break;
2689 case SOFIA_TRANSPORT_TCP_TLS:
2690 contact_str = sofia_test_pflag(profile, PFLAG_TLS) ?
2691 profile->tls_public_contact : profile->tcp_public_contact;
2692 break;
2693 default:
2694 contact_str = profile->public_url;
2695 break;
2696 }
2697 } else {
2698 contact_str = profile->public_url;
2699 }
2700 } else {
2701 char *ptr;
2702 if ((ptr = sofia_glue_find_parameter(contact, "transport="))) {
2703 sofia_transport_t transport = sofia_glue_str2transport( ptr + 10 );
2704
2705 switch (transport) {
2706 case SOFIA_TRANSPORT_TCP:
2707 contact_str = profile->tcp_contact;
2708 break;
2709 case SOFIA_TRANSPORT_TCP_TLS:
2710 contact_str = sofia_test_pflag(profile, PFLAG_TLS) ?
2711 profile->tls_contact : profile->tcp_contact;
2712 break;
2713 default:
2714 contact_str = profile->url;
2715 break;
2716 }
2717 } else {
2718 contact_str = profile->url;
2719 }
2720 }
2721
2722
2723 if (!zstr(presence_id) && strchr(presence_id, '@')) {
2724 char *p;
2725
2726 free_me = strdup(presence_id);
2727
2728 switch_assert(free_me);
2729
2730 if ((p = strchr(free_me, '@'))) {
2731 *p = '\0';
2732 }
2733
2734 user = free_me;
2735 }
2736
2737
2738 if (!zstr(orig_proto) && !strcmp(orig_proto, SOFIA_CHAT_PROTO)) {
2739 skip_proto = 1;
2740 }
2741
2742 in = helper->event && helper->event->event_id == SWITCH_EVENT_PRESENCE_IN;
2743
2744 if (zstr(rpid)) {
2745 rpid = "unknown";
2746 }
2747
2748 if (zstr(status)) {
2749 if (!strcasecmp(rpid, "busy")) {
2750 status = "Busy";
2751 } else if (!strcasecmp(rpid, "unavailable")) {
2752 status = "Idle";
2753 } else if (!strcasecmp(rpid, "away")) {
2754 status = "Idle";
2755 } else {
2756 status = "Available";
2757 }
2758 }
2759
2760 if (status && !strncasecmp(status, "hold", 4)) {
2761 holding = 1;
2762 }
2763
2764 if (profile_name && strcasecmp(profile_name, helper->profile->name)) {
2765 if ((ext_profile = sofia_glue_find_profile(profile_name))) {
2766 profile = ext_profile;
2767 }
2768 }
2769
2770
2771 if (!strcasecmp(proto, SOFIA_CHAT_PROTO) || skip_proto) {
2772 clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
2773 } else {
2774 clean_id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
2775 }
2776
2777
2778
2779 if (!rpid) {
2780 rpid = "unknown";
2781 }
2782
2783 // if (!strcasecmp(proto, SOFIA_CHAT_PROTO) || skip_proto) {
2784 // clean_id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
2785 //} else {
2786 // clean_id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
2787 //}
2788
2789 if (mod_sofia_globals.debug_presence > 0) {
2790 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
2791 "SEND PRESENCE\nTo: \t%s@%s\nFrom: \t%s@%s\nCall-ID: \t%s\nProfile:\t%s [%s]\n\n",
2792 user, host, sub_to_user, sub_to_host, call_id, profile_name, helper->profile->name);
2793 }
2794
2795 if (!strcasecmp(sub_to_host, host) && !skip_proto) {
2796 /* same host */
2797 id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
2798 } else if (strcasecmp(proto, SOFIA_CHAT_PROTO) && !skip_proto) {
2799 /*encapsulate */
2800 id = switch_mprintf("sip:%s+%s+%s@%s", proto, sub_to_user, sub_to_host, host);
2801 } else {
2802 id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
2803 }
2804
2805 to = switch_mprintf("sip:%s@%s", user, host);
2806
2807 is_dialog = !strcmp(event, "dialog");
2808
2809 if (helper->hup && helper->calls_up > 0) {
2810 call_state = "CS_EXECUTE";
2811 astate = "active";
2812 event_status = "Active";
2813 force_event_status = NULL;
2814 } else {
2815 if (helper->event) {
2816 call_state = switch_event_get_header(helper->event, "channel-state");
2817 astate = switch_str_nil(switch_event_get_header(helper->event, "astate"));
2818 event_status = switch_str_nil(switch_event_get_header(helper->event, "status"));
2819 force_event_status = switch_str_nil(switch_event_get_header(helper->event, "force-status"));
2820 }
2821 }
2822
2823 if (helper->event) {
2824 switch_stream_handle_t stream = { 0 };
2825 const char *direction = switch_str_nil(switch_event_get_header(helper->event, "presence-call-direction"));
2826 //const char *force_direction = switch_str_nil(switch_event_get_header(helper->event, "force-direction"));
2827 const char *uuid = switch_str_nil(switch_event_get_header(helper->event, "unique-id"));
2828 const char *resub = switch_str_nil(switch_event_get_header(helper->event, "resub"));
2829 const char *answer_state = switch_str_nil(switch_event_get_header(helper->event, "answer-state"));
2830 const char *dft_state;
2831 const char *from_id = NULL, *from_name = NULL;
2832 const char *to_user = switch_str_nil(switch_event_get_header(helper->event, "variable_sip_to_user"));
2833 const char *from_user = switch_str_nil(switch_event_get_header(helper->event, "variable_sip_from_user"));
2834 const char *disable_early = switch_str_nil(switch_event_get_header(helper->event, "variable_presence_disable_early"));
2835 const char *answer_epoch = switch_str_nil(switch_event_get_header(helper->event, "variable_answer_epoch"));
2836 int answered = 0;
2837 char *clean_to_user = NULL;
2838 char *clean_from_user = NULL;
2839 int force_status = 0;
2840 int term = 0;
2841
2842 if (answer_epoch) {
2843 answered = atoi(answer_epoch);
2844 }
2845
2846
2847 //if (user_agent && switch_stristr("snom", user_agent) && uuid) {
2848 // default_dialog = "full" ;
2849 //}
2850
2851 if (call_state && !strcasecmp(call_state, "cs_hangup")) {
2852 astate = "hangup";
2853 holding = 0;
2854 term = 1;
2855 } else {
2856
2857 if (event_status && !strncasecmp(event_status, "hold", 4)) {
2858 holding = 1;
2859 }
2860
2861 if (force_event_status && !event_status) {
2862 event_status = force_event_status;
2863 }
2864
2865 if (event_status && !strncasecmp(event_status, "hold", 4)) {
2866 holding = 1;
2867 }
2868 }
2869
2870 if (!strcasecmp(direction, "inbound")) {
2871 from_id = switch_str_nil(switch_event_get_header(helper->event, "Caller-Destination-Number"));
2872
2873 } else {
2874 from_id = switch_str_nil(switch_event_get_header(helper->event, "Caller-Caller-ID-Number"));
2875 from_name = switch_event_get_header(helper->event, "Caller-Caller-ID-Name");
2876
2877 if (zstr(from_id)) {
2878 from_id = switch_str_nil(switch_event_get_header(helper->event, "Other-Leg-Caller-ID-Number"));
2879 }
2880
2881 if (zstr(from_name)) {
2882 from_name = switch_event_get_header(helper->event, "Other-Leg-Caller-ID-Name");
2883 }
2884
2885 }
2886
2887 #if 0
2888 char *buf;
2889 switch_event_serialize(helper->event, &buf, SWITCH_FALSE);
2890 switch_assert(buf);
2891 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf);
2892 free(buf);
2893 #endif
2894
2895 if (is_dialog) {
2896 // Usually we report the dialogs FROM the probed user. The exception is when the monitored endpoint is internal,
2897 // and its presence_id is set in the dialplan. Reverse the direction if this is not a registered entity.
2898 const char *caller = switch_str_nil(switch_event_get_header(helper->event, "caller-username"));
2899 SWITCH_STANDARD_STREAM(stream);
2900 if (!strcmp(direction, "inbound") && strcmp(sub_to_user, caller)) {
2901 // If inbound and the entity is not the caller (i.e. internal to FS), then the direction is reversed
2902 // because it is not going through the B2BUA
2903 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "sofia_presence_sub_callback: endpt is internal\n");
2904 direction = !strcasecmp(direction, "outbound") ? "inbound" : "outbound";
2905 }
2906
2907 }
2908
2909 if (!strcasecmp(direction, "outbound")) {
2910 direction = "recipient";
2911 dft_state = "early";
2912 } else {
2913 direction = "initiator";
2914 dft_state = "confirmed";
2915 }
2916
2917 if (is_dialog) {
2918 if (zstr(version)) {
2919 version = "0";
2920 }
2921
2922 stream.write_function(&stream,
2923 "<?xml version=\"1.0\"?>\n"
2924 "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" "
2925 "version=\"%s\" state=\"%s\" entity=\"%s\">\n", version, default_dialog, clean_id);
2926
2927 }
2928
2929 if (!zstr(uuid)) {
2930 if (!zstr(answer_state)) {
2931 astate = answer_state;
2932 }
2933
2934 if (zstr(astate)) {
2935 if (is_dialog) {
2936 astate = dft_state;
2937 } else {
2938 astate = "terminated";
2939 }
2940 }
2941
2942 if (!strcasecmp(astate, "answered")) {
2943 astate = "confirmed";
2944 }
2945
2946
2947 if (is_dialog) {
2948
2949 if (!strcasecmp(astate, "ringing")) {
2950 if (!strcasecmp(direction, "recipient")) {
2951 astate = "early";
2952 } else {
2953 astate = "confirmed";
2954 }
2955 }
2956
2957 if (holding) {
2958 if (profile->pres_held_type == PRES_HELD_CONFIRMED) {
2959 astate = "confirmed";
2960 } else if (profile->pres_held_type == PRES_HELD_TERMINATED) {
2961 astate = "terminated";
2962 } else {
2963 astate = "early";
2964 }
2965 }
2966
2967
2968 if (!strcasecmp(astate, "hangup")) {
2969 astate = "terminated";
2970 }
2971
2972 stream.write_function(&stream, "<dialog id=\"%s\" direction=\"%s\">\n", uuid, direction);
2973 stream.write_function(&stream, "<state>%s</state>\n", astate);
2974 } else {
2975 if (!strcasecmp(astate, "ringing")) {
2976 astate = "early";
2977 }
2978 }
2979
2980
2981 if ((sofia_test_pflag(profile, PFLAG_PRESENCE_DISABLE_EARLY) || switch_true(disable_early)) &&
2982 ((!zstr(astate) && (!strcasecmp(astate, "early") || !strcasecmp(astate, "ringing") || (!strcasecmp(astate, "terminated") && !answered))))) {
2983 switch_safe_free(stream.data);
2984 goto end;
2985 }
2986
2987 if (!strcasecmp(astate, "early") || !strcasecmp(astate, "confirmed")) {
2988
2989 clean_to_user = switch_mprintf("%s", sub_to_user ? sub_to_user : to_user);
2990 clean_from_user = switch_mprintf("%s", from_id ? from_id : from_user);
2991
2992 if (is_dialog) {
2993 if (!zstr(clean_to_user) && !zstr(clean_from_user)) {
2994 stream.write_function(&stream, "<local>\n<identity display=\"%s\">sip:%s@%s</identity>\n", clean_to_user, clean_to_user, host);
2995 stream.write_function(&stream, "<target uri=\"sip:%s@%s\">\n", clean_to_user, host);
2996 stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"%s\"/>\n", holding ? "no" : "yes");
2997
2998 stream.write_function(&stream, "</target>\n</local>\n");
2999 if (switch_true(switch_event_get_header(helper->event, "Presence-Privacy"))) {
3000 stream.write_function(&stream, "<remote>\n<identity display=\"Anonymous\">sip:anonymous@anonymous.invalid</identity>\n");
3001 } else {
3002 stream.write_function(&stream, "<remote>\n<identity display=\"%s\">sip:%s@%s</identity>\n",
3003 from_name ? from_name : clean_from_user, clean_from_user,
3004 host);
3005 }
3006 stream.write_function(&stream, "<target uri=\"sip:**%s@%s\"/>\n", clean_to_user, host);
3007 stream.write_function(&stream, "</remote>\n");
3008
3009 } else if (!strcasecmp(proto, "queue")) {
3010 stream.write_function(&stream, "<local>\n<identity display=\"queue\">sip:%s@%s;proto=queue</identity>\n",
3011 !zstr(clean_to_user) ? clean_to_user : "unknown", host);
3012 stream.write_function(&stream, "<target uri=\"sip:%s@%s;proto=fifo\">\n", !zstr(clean_to_user) ? clean_to_user : "unknown", host);
3013 stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n</target>\n</local>\n");
3014 stream.write_function(&stream, "<remote>\n<identity display=\"queue\">sip:%s@%s</identity>\n", uuid, host);
3015 if (skip_proto) {
3016 stream.write_function(&stream, "<target uri=\"sip:%s@%s\"/>\n", uuid, host);
3017 } else {
3018 stream.write_function(&stream, "<target uri=\"sip:queue+%s@%s\"/>\n", uuid, host);
3019 }
3020
3021 stream.write_function(&stream, "</remote>\n");
3022 } else if (!strcasecmp(proto, "park")) {
3023 stream.write_function(&stream, "<local>\n<identity display=\"park\">sip:%s@%s;proto=park</identity>\n",
3024 !zstr(clean_to_user) ? clean_to_user : "unknown", host);
3025 stream.write_function(&stream, "<target uri=\"sip:%s@%s;proto=park\">\n", !zstr(clean_to_user) ? clean_to_user : "unknown", host);
3026 stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n</target>\n</local>\n");
3027 stream.write_function(&stream, "<remote>\n<identity display=\"park\">sip:%s</identity>\n", uuid);
3028 if (skip_proto) {
3029 stream.write_function(&stream, "<target uri=\"sip:%s@%s\"/>\n", uuid, host);
3030 } else {
3031 stream.write_function(&stream, "<target uri=\"sip:park+%s@%s\"/>\n", uuid, host);
3032 }
3033 stream.write_function(&stream, "</remote>\n");
3034 } else if (!strcasecmp(proto, "pickup")) {
3035 stream.write_function(&stream, "<local>\n<identity display=\"pickup\">sip:%s@%s;proto=pickup</identity>\n",
3036 !zstr(clean_to_user) ? clean_to_user : "unknown", host);
3037 stream.write_function(&stream, "<target uri=\"sip:%s@%s;proto=pickup\">\n", !zstr(clean_to_user) ? clean_to_user : "unknown", host);
3038 stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n</target>\n</local>\n");
3039 stream.write_function(&stream, "<remote>\n<identity display=\"pickup\">sip:%s@%s</identity>\n", uuid, host);
3040 if (skip_proto) {
3041 stream.write_function(&stream, "<target uri=\"sip:%s@%s\"/>\n", uuid, host);
3042 } else {
3043 stream.write_function(&stream, "<target uri=\"sip:pickup+%s@%s\"/>\n", uuid, host);
3044 }
3045 stream.write_function(&stream, "</remote>\n");
3046 } else if (!strcasecmp(proto, "conf")) {
3047 stream.write_function(&stream, "<local>\n<identity display=\"conference\">sip:%s@%s;proto=conference</identity>\n",
3048 !zstr(clean_to_user) ? clean_to_user : "unknown", host);
3049 stream.write_function(&stream, "<target uri=\"sip:%s@%s;proto=conference\">\n",
3050 !zstr(clean_to_user) ? clean_to_user : "unknown", host);
3051 stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"yes\"/>\n</target>\n</local>\n");
3052 stream.write_function(&stream, "<remote>\n<identity display=\"conference\">sip:%s@%s</identity>\n", uuid, host);
3053 if (skip_proto) {
3054 stream.write_function(&stream, "<target uri=\"sip:%s@%s\"/>\n", uuid, host);
3055 } else {
3056 stream.write_function(&stream, "<target uri=\"sip:conf+%s@%s\"/>\n", uuid, host);
3057 }
3058 stream.write_function(&stream, "</remote>\n");
3059 }
3060 }
3061
3062 switch_safe_free(clean_to_user);
3063 switch_safe_free(clean_from_user);
3064 }
3065 if (is_dialog) {
3066 stream.write_function(&stream, "</dialog>\n");
3067 }
3068 }
3069
3070 if (is_dialog) {
3071 stream.write_function(&stream, "</dialog-info>\n");
3072 pl = stream.data;
3073 ct = "application/dialog-info+xml";
3074 }
3075
3076 if (!zstr(astate) && !zstr(uuid) &&
3077 helper && helper->stream.data && strcmp(helper->last_uuid, uuid) && strcasecmp(astate, "terminated") && strchr(uuid, '-')) {
3078 helper->stream.write_function(&helper->stream, "update sip_dialogs set state='%q' where hostname='%q' and profile_name='%q' and uuid='%q';",
3079 astate, mod_sofia_globals.hostname, profile->name, uuid);
3080 switch_copy_string(helper->last_uuid, uuid, sizeof(helper->last_uuid));
3081 }
3082
3083 if (zstr(astate)) astate = "";
3084
3085 if (!is_dialog) {
3086 switch_set_string(status_line, status);
3087
3088 if (in) {
3089 open = "open";
3090
3091 if (switch_false(resub)) {
3092 const char *direction = switch_event_get_header(helper->event, "Caller-Direction");
3093 const char *op, *what = "Ring";
3094
3095 if (direction && !strcasecmp(direction, "outbound")) {
3096 op = switch_event_get_header(helper->event, "Other-Leg-Caller-ID-Number");
3097 } else {
3098 op = switch_event_get_header(helper->event, "Caller-Callee-ID-Number");
3099 }
3100
3101 if (zstr(op)) {
3102 op = switch_event_get_header(helper->event, "Caller-Destination-Number");
3103 }
3104
3105 if (direction) {
3106 what = strcasecmp(direction, "outbound") ? "Call" : "Ring";
3107 }
3108
3109 if (!strcmp(astate, "early")) {
3110 if (!zstr(op)) {
3111 //switch_snprintf(status_line, sizeof(status_line), "%sing", what);
3112 //} else {
3113 if (sofia_test_pflag(profile, PFLAG_PRESENCE_PRIVACY)) {
3114 switch_snprintf(status_line, sizeof(status_line), "%s", what);
3115 } else {
3116 switch_snprintf(status_line, sizeof(status_line), "%s %s", what, op);
3117 }
3118 }
3119
3120 rpid = "on-the-phone";
3121 force_status = 1;
3122
3123 } else if (!strcmp(astate, "confirmed")) {
3124 if (!zstr(op)) {
3125 if (sofia_test_pflag(profile, PFLAG_PRESENCE_PRIVACY)) {
3126 switch_snprintf(status_line, sizeof(status_line), "On The Phone");
3127 } else {
3128 switch_snprintf(status_line, sizeof(status_line), "Talk %s", op);
3129 }
3130 } else {
3131 switch_snprintf(status_line, sizeof(status_line), "On The Phone");
3132 }
3133
3134 rpid = "on-the-phone";
3135 force_status = 1;
3136 } else if (!strcmp(astate, "terminated") || !strcmp(astate, "hangup")) {
3137 //rpid = "online";
3138 //dialog_rpid = "";
3139 //force_event_status = "Available";
3140 term = 1;
3141 }
3142
3143 if (!term && !strcmp(status, "hold")) {
3144 rpid = "on-the-phone";
3145 if (!zstr(op)) {
3146 if (sofia_test_pflag(profile, PFLAG_PRESENCE_PRIVACY)) {
3147 switch_snprintf(status_line, sizeof(status_line), "Hold");
3148 } else {
3149 switch_snprintf(status_line, sizeof(status_line), "Hold %s", op);
3150 }
3151 force_status = 1;
3152 }
3153 }
3154 }
3155 } else {
3156 open = "closed";
3157 }
3158
3159 if (!zstr(open_closed)) {
3160 open = open_closed;
3161 }
3162
3163 prpid = translate_rpid(rpid);
3164
3165 if (!zstr(dialog_status) && !force_status) {
3166 status = dialog_status;
3167 switch_set_string(status_line, status);
3168 }
3169
3170 if (!zstr(force_event_status)) {
3171 switch_set_string(status_line, force_event_status);
3172 }
3173
3174 if (!zstr(dialog_rpid)) {
3175 prpid = rpid = dialog_rpid;
3176 }
3177
3178 contact_stripped = sofia_glue_strip_uri(contact_str);
3179 pl = gen_pidf(user_agent, clean_id, contact_stripped, open, rpid, prpid, status_line, &ct);
3180 free(contact_stripped);
3181 }
3182
3183 } else {
3184 if (in) {
3185 open = "open";
3186 } else {
3187 open = "closed";
3188 }
3189
3190 if (!zstr(open_closed)) {
3191 open = open_closed;
3192 }
3193
3194 prpid = translate_rpid(rpid);
3195
3196 if (!zstr(dialog_status)) {
3197 status = dialog_status;
3198 }
3199
3200 if (!zstr(dialog_rpid)) {
3201 prpid = rpid = dialog_rpid;
3202 }
3203
3204 contact_stripped = sofia_glue_strip_uri(contact_str);
3205 pl = gen_pidf(user_agent, clean_id, contact_stripped, open, rpid, prpid, status, &ct);
3206 free(contact_stripped);
3207 }
3208
3209
3210 if (!is_dialog && helper->event && !switch_stristr("registered", status_line)){
3211 const char *uuid = switch_event_get_header_nil(helper->event, "unique-id");
3212 const char *register_source = switch_event_get_header_nil(helper->event, "register-source");
3213
3214 if (!zstr(uuid) && strchr(uuid, '-') && !zstr(status_line) && !zstr(rpid) && (zstr(register_source) || strcasecmp(register_source, "register"))) {
3215 char *sql = switch_mprintf("update sip_dialogs set rpid='%q',status='%q' where hostname='%q' and profile_name='%q' and uuid='%q'",
3216 rpid, status_line,
3217 mod_sofia_globals.hostname, profile->name, uuid);
3218 sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE);
3219 }
3220 }
3221
3222 send_presence_notify(profile, full_to, full_from, contact, expires, call_id, event, ip, port, ct, pl, NULL);
3223
3224
3225 end:
3226
3227 switch_safe_free(free_me);
3228
3229 if (ext_profile) {
3230 sofia_glue_release_profile(ext_profile);
3231 }
3232
3233 switch_safe_free(id);
3234 switch_safe_free(clean_id);
3235 switch_safe_free(pl);
3236 switch_safe_free(to);
3237
3238 return 0;
3239 }
3240
sofia_presence_mwi_callback(void * pArg,int argc,char ** argv,char ** columnNames)3241 static int sofia_presence_mwi_callback(void *pArg, int argc, char **argv, char **columnNames)
3242 {
3243 //char *sub_to_user = argv[3];
3244 //char *sub_to_host = argv[4];
3245 char *event = argv[5];
3246 char *contact = argv[6];
3247 char *call_id = argv[7];
3248 char *full_from = argv[8];
3249 char *expires = argv[10];
3250 char *profile_name = argv[13];
3251 char *body = argv[15];
3252 char *full_to = argv[16];
3253 char *remote_ip = argv[17];
3254 char *remote_port = argv[18];
3255
3256 struct mwi_helper *h = (struct mwi_helper *) pArg;
3257 sofia_profile_t *ext_profile = NULL, *profile = h->profile;
3258
3259
3260 if (mod_sofia_globals.debug_presence > 0) {
3261 int i;
3262 for(i = 0; i < argc; i++) {
3263 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]);
3264 }
3265 }
3266
3267 if (profile_name && strcasecmp(profile_name, h->profile->name)) {
3268 if ((ext_profile = sofia_glue_find_profile(profile_name))) {
3269 profile = ext_profile;
3270 }
3271 }
3272
3273 send_presence_notify(profile,
3274 full_to,
3275 full_from,
3276 contact,
3277 expires,
3278 call_id,
3279 event,
3280 remote_ip,
3281 remote_port,
3282 "application/simple-message-summary",
3283 body,
3284 NULL
3285 );
3286
3287
3288 h->total++;
3289
3290 if (ext_profile) {
3291 sofia_glue_release_profile(ext_profile);
3292 }
3293
3294 return 0;
3295 }
3296
sofia_presence_mwi_callback2(void * pArg,int argc,char ** argv,char ** columnNames)3297 static int sofia_presence_mwi_callback2(void *pArg, int argc, char **argv, char **columnNames)
3298 {
3299 const char *user = argv[0];
3300 const char *host = argv[1];
3301 const char *event = "message-summary";
3302 const char *contenttype = "application/simple-message-summary";
3303 const char *body = argv[5];
3304 const char *o_contact = argv[2];
3305 const char *network_ip = argv[4];
3306 const char *call_id = argv[6];
3307
3308 char *profile_name = argv[3];
3309 struct mwi_helper *h = (struct mwi_helper *) pArg;
3310 sofia_profile_t *ext_profile = NULL, *profile = h->profile;
3311
3312 if (profile_name && strcasecmp(profile_name, h->profile->name)) {
3313 if ((ext_profile = sofia_glue_find_profile(profile_name))) {
3314 profile = ext_profile;
3315 }
3316 }
3317
3318 if (!sofia_test_pflag(profile, PFLAG_MWI_USE_REG_CALLID)) {
3319 call_id = NULL;
3320 }
3321
3322 sofia_glue_send_notify(profile, user, host, event, contenttype, body, o_contact, network_ip, call_id);
3323
3324 if (ext_profile) {
3325 sofia_glue_release_profile(ext_profile);
3326 }
3327
3328 return 0;
3329 }
3330
broadsoft_sla_notify_callback(void * pArg,int argc,char ** argv,char ** columnNames)3331 static int broadsoft_sla_notify_callback(void *pArg, int argc, char **argv, char **columnNames)
3332 {
3333 struct state_helper *sh = (struct state_helper *) pArg;
3334 char key[256] = "";
3335 char *data = NULL, *tmp;
3336 char *call_id = argv[0];
3337 //char *expires = argv[1];
3338 char *user = argv[2];
3339 char *host = argv[3];
3340 char *event = argv[4];
3341 int i;
3342
3343
3344 if (mod_sofia_globals.debug_sla > 1) {
3345 for (i = 0; i < argc; i++) {
3346 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SLA3: %d [%s]=[%s]\n", i, columnNames[i], argv[i]);
3347 }
3348 }
3349
3350 switch_snprintf(key, sizeof(key), "%s%s", user, host);
3351 data = switch_core_hash_find(sh->hash, key);
3352
3353 if (data) {
3354 tmp = switch_core_sprintf(sh->pool, "%s,<sip:%s>;appearance-index=*;appearance-state=idle", data, host);
3355 } else {
3356 tmp = switch_core_sprintf(sh->pool, "<sip:%s>;appearance-index=*;appearance-state=idle", host);
3357 }
3358
3359
3360 if (!strcasecmp(event, "line-seize")) {
3361 char *hack;
3362
3363 if ((hack = (char *) switch_stristr("=seized", tmp))) {
3364 switch_snprintf(hack, 7, "=idle ");
3365 }
3366 }
3367
3368 if (mod_sofia_globals.debug_sla > 1) {
3369 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DB PRES NOTIFY: [%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n[%s]\n",
3370 argv[5], argv[6], argv[7], argv[8], call_id, event, argv[9], argv[10], tmp);
3371
3372 }
3373
3374 send_presence_notify(sh->profile, argv[5], argv[6], argv[7], argv[8], call_id, event, argv[9], argv[10], NULL, NULL, tmp);
3375
3376 sh->total++;
3377
3378 return 0;
3379 }
3380
broadsoft_sla_gather_state_callback(void * pArg,int argc,char ** argv,char ** columnNames)3381 static int broadsoft_sla_gather_state_callback(void *pArg, int argc, char **argv, char **columnNames)
3382 {
3383 struct state_helper *sh = (struct state_helper *) pArg;
3384 char key[256] = "";
3385 switch_core_session_t *session;
3386 const char *callee_name = NULL, *callee_number = NULL;
3387 char *data = NULL, *tmp;
3388 char *user = argv[0];
3389 char *host = argv[1];
3390 char *info = argv[2];
3391 char *state = argv[3];
3392 char *uuid = argv[4];
3393 int i;
3394
3395 if (mod_sofia_globals.debug_sla > 1) {
3396 for (i = 0; i < argc; i++) {
3397 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SLA2: %d [%s]=[%s]\n", i, columnNames[i], argv[i]);
3398 }
3399 }
3400
3401 if (zstr(info)) {
3402 return 0;
3403 }
3404
3405 if (zstr(state)) {
3406 state = "idle";
3407 }
3408
3409 switch_snprintf(key, sizeof(key), "%s%s", user, host);
3410
3411 data = switch_core_hash_find(sh->hash, key);
3412
3413 if (strcasecmp(state, "idle") && uuid && (session = switch_core_session_locate(uuid))) {
3414 switch_channel_t *channel = switch_core_session_get_channel(session);
3415
3416 if (switch_channel_test_flag(channel, CF_ORIGINATOR) || switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR) ||
3417 switch_channel_inbound_display(channel) || switch_channel_test_flag(channel, CF_SLA_BARGING)) {
3418 if (!switch_channel_test_flag(channel, CF_ANSWERED)) state = "progressing";
3419 callee_name = switch_channel_get_variable(channel, "callee_id_name");
3420 callee_number = switch_channel_get_variable(channel, "callee_id_number");
3421
3422 if (zstr(callee_number)) {
3423 callee_number = switch_channel_get_variable(channel, "destination_number");
3424 }
3425
3426 } else {
3427 callee_name = switch_channel_get_variable(channel, "caller_id_name");
3428 callee_number = switch_channel_get_variable(channel, "caller_id_number");
3429 }
3430
3431 if (zstr(callee_name) && !zstr(callee_number)) {
3432 callee_name = callee_number;
3433 }
3434
3435 if (!zstr(callee_number)) {
3436 callee_number = switch_sanitize_number(switch_core_session_strdup(session, callee_number));
3437 }
3438
3439 if (!zstr(callee_name)) {
3440 char *tmp = switch_core_session_strdup(session, callee_name);
3441 switch_url_decode(tmp);
3442 callee_name = switch_sanitize_number(tmp);
3443 }
3444
3445
3446 //if (switch_channel_get_state(channel) != CS_EXECUTE) {
3447 //callee_number = NULL;
3448 //}
3449
3450 switch_core_session_rwunlock(session);
3451 }
3452
3453 if (data && strstr(data, info)) {
3454 return 0;
3455 }
3456
3457
3458 if (!zstr(callee_number)) {
3459 if (zstr(callee_name)) {
3460 callee_name = "unknown";
3461 }
3462
3463 if (data) {
3464 tmp = switch_core_sprintf(sh->pool,
3465 "%s,<sip:%s>;%s;appearance-state=%s;appearance-uri=\"\\\"%s\\\" <sip:%s@%s>\"",
3466 data, host, info, state, callee_name, callee_number, host);
3467 } else {
3468 tmp = switch_core_sprintf(sh->pool,
3469 "<sip:%s>;%s;appearance-state=%s;appearance-uri=\"\\\"%s\\\" <sip:%s@%s>\"",
3470 host, info, state, callee_name, callee_number, host);
3471 }
3472 } else {
3473 if (data) {
3474 tmp = switch_core_sprintf(sh->pool, "%s,<sip:%s>;%s;appearance-state=%s", data, host, info, state);
3475 } else {
3476 tmp = switch_core_sprintf(sh->pool, "<sip:%s>;%s;appearance-state=%s", host, info, state);
3477 }
3478 }
3479
3480 switch_core_hash_insert(sh->hash, key, tmp);
3481
3482 return 0;
3483 }
3484
sync_sla(sofia_profile_t * profile,const char * to_user,const char * to_host,switch_bool_t clear,switch_bool_t unseize,const char * call_id)3485 static int sync_sla(sofia_profile_t *profile, const char *to_user, const char *to_host, switch_bool_t clear, switch_bool_t unseize, const char *call_id)
3486 {
3487 struct state_helper *sh;
3488 switch_memory_pool_t *pool;
3489 char *sql;
3490 int total = 0;
3491
3492
3493 if (clear) {
3494 struct pres_sql_cb cb = {profile, 0};
3495
3496
3497 if (call_id) {
3498
3499 sql = switch_mprintf("update sip_subscriptions set version=version+1,expires=%ld where "
3500 "call_id='%q' "
3501 "and event='line-seize'", (long) switch_epoch_time_now(NULL),
3502 call_id);
3503
3504 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
3505
3506 if (mod_sofia_globals.debug_sla > 1) {
3507 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
3508 }
3509 switch_safe_free(sql);
3510
3511 sql = switch_mprintf("select full_to, full_from, contact, -1, call_id, event, network_ip, network_port, "
3512 "NULL as ct, NULL as pt "
3513 " from sip_subscriptions where call_id='%q' "
3514
3515 "and event='line-seize'", call_id);
3516
3517 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_send_sql, &cb);
3518 if (mod_sofia_globals.debug_sla > 1) {
3519 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
3520 }
3521 switch_safe_free(sql);
3522 } else {
3523
3524 sql = switch_mprintf("update sip_subscriptions set version=version+1,expires=%ld where "
3525 "hostname='%q' and profile_name='%q' "
3526 "and sub_to_user='%q' and sub_to_host='%q' "
3527
3528 "and event='line-seize'", (long) switch_epoch_time_now(NULL),
3529 mod_sofia_globals.hostname, profile->name, to_user, to_host
3530 );
3531
3532 if (mod_sofia_globals.debug_sla > 1) {
3533 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
3534 }
3535
3536 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
3537
3538
3539 sql = switch_mprintf("select full_to, full_from, contact, -1, call_id, event, network_ip, network_port, "
3540 "NULL as ct, NULL as pt "
3541 " from sip_subscriptions where "
3542 "hostname='%q' and profile_name='%q' "
3543 "and sub_to_user='%q' and sub_to_host='%q' "
3544 "and event='line-seized'",
3545 mod_sofia_globals.hostname, profile->name, to_user, to_host
3546 );
3547
3548 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_send_sql, &cb);
3549
3550 if (mod_sofia_globals.debug_sla > 1) {
3551 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
3552 }
3553
3554 switch_safe_free(sql);
3555 }
3556
3557
3558 sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and profile_name='%q' and "
3559 "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
3560 "and call_info_state='seized'", mod_sofia_globals.hostname, profile->name, to_user, to_host, to_user, to_host);
3561
3562
3563 if (mod_sofia_globals.debug_sla > 1) {
3564 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
3565 }
3566 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
3567 switch_safe_free(sql);
3568 }
3569
3570
3571 switch_core_new_memory_pool(&pool);
3572 sh = switch_core_alloc(pool, sizeof(*sh));
3573 sh->pool = pool;
3574 switch_core_hash_init(&sh->hash);
3575
3576 sql = switch_mprintf("select sip_from_user,sip_from_host,call_info,call_info_state,uuid from sip_dialogs "
3577 "where call_info_state is not null and call_info_state != '' and call_info_state != 'idle' and hostname='%q' and profile_name='%q' "
3578 "and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
3579 "and profile_name='%q'",
3580 mod_sofia_globals.hostname, profile->name, to_user, to_host, to_user, to_host, profile->name);
3581
3582
3583 if (mod_sofia_globals.debug_sla > 1) {
3584 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql);
3585 }
3586 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, broadsoft_sla_gather_state_callback, sh);
3587 switch_safe_free(sql);
3588
3589
3590 if (!zstr(call_id)) {
3591
3592 if (unseize) {
3593 sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port "
3594 "from sip_subscriptions where call_id='%q' and hostname='%q' and profile_name='%q' "
3595 "and (event='call-info' or event='line-seize')",
3596 call_id, mod_sofia_globals.hostname, profile->name);
3597
3598 } else {
3599 sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port "
3600 "from sip_subscriptions where call_id='%q' and hostname='%q' and profile_name='%q' and event='call-info'",
3601 call_id, mod_sofia_globals.hostname, profile->name);
3602 }
3603
3604 } else {
3605
3606 if (unseize) {
3607 sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port "
3608 "from sip_subscriptions "
3609 "where hostname='%q' and profile_name='%q' "
3610 "and sub_to_user='%q' and sub_to_host='%q' "
3611 "and (event='call-info' or event='line-seize') and (profile_name='%q' or presence_hosts like '%%%q%%')",
3612 mod_sofia_globals.hostname, profile->name, to_user, to_host, profile->name, to_host);
3613 } else {
3614 sql = switch_mprintf("select call_id,expires,sub_to_user,sub_to_host,event,full_to,full_from,contact,expires,network_ip,network_port "
3615 "from sip_subscriptions "
3616 "where hostname='%q' and profile_name='%q' "
3617 "and sub_to_user='%q' and sub_to_host='%q' " "and (event='call-info') and "
3618 "(profile_name='%q' or presence_hosts like '%%%q%%')",
3619 mod_sofia_globals.hostname, profile->name, to_user, to_host, profile->name, to_host);
3620 }
3621 }
3622
3623 if (mod_sofia_globals.debug_sla > 1) {
3624 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "PRES SQL %s\n", sql);
3625 }
3626
3627 sh->profile = profile;
3628 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, broadsoft_sla_notify_callback, sh);
3629 switch_safe_free(sql);
3630 total = sh->total;
3631 switch_core_hash_destroy(&sh->hash);
3632
3633 sh = NULL;
3634 switch_core_destroy_memory_pool(&pool);
3635
3636
3637
3638
3639
3640 return total;
3641
3642 }
3643
sofia_presence_handle_sip_i_subscribe(int status,char const * phrase,nua_t * nua,sofia_profile_t * profile,nua_handle_t * nh,sofia_private_t * sofia_private,sip_t const * sip,sofia_dispatch_event_t * de,tagi_t tags[])3644 void sofia_presence_handle_sip_i_subscribe(int status,
3645 char const *phrase,
3646 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
3647 sofia_dispatch_event_t *de,
3648 tagi_t tags[])
3649 {
3650
3651 long exp_delta = 0;
3652 char exp_delta_str[30] = "";
3653 uint32_t sub_max_deviation_var = 0;
3654 sip_to_t const *to;
3655 const char *from_user = NULL, *from_host = NULL;
3656 const char *to_user = NULL, *to_host = NULL;
3657 char *my_to_user = NULL;
3658 char *sql, *event = NULL;
3659 char *proto = "sip";
3660 char *orig_proto = "";
3661 char *alt_proto = NULL;
3662 char *d_user = NULL;
3663 char *contact_str = "";
3664 const char *call_id = NULL;
3665 char *to_str = NULL;
3666 char *full_from = NULL;
3667 char *full_to = NULL;
3668 char *full_via = NULL;
3669 char *full_agent = NULL;
3670 char *sstr;
3671 switch_event_t *sevent;
3672 int sub_state = nua_substate_pending;
3673 int sent_reply = 0;
3674 sip_contact_t const *contact;
3675 const char *ipv6;
3676 const char *contact_user = NULL;
3677 const char *contact_host = NULL;
3678 const char *contact_port = NULL;
3679 sofia_nat_parse_t np = { { 0 } };
3680 int found_proto = 0;
3681 const char *use_to_tag;
3682 char to_tag[13] = "";
3683 char buf[1025] = "";
3684 char *orig_to_user = NULL;
3685 char *p;
3686 uint32_t callsequence;
3687 sip_cseq_t * cseq;
3688
3689 if (!sip) {
3690 return;
3691 }
3692
3693 to = sip->sip_to;
3694 contact = sip->sip_contact;
3695
3696 np.fs_path = 1;
3697 if (!(contact_str = sofia_glue_gen_contact_str(profile, sip, nh, de, &np))) {
3698 nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
3699 return;
3700 }
3701
3702 if (sip->sip_to && sip->sip_to->a_tag) {
3703 use_to_tag = sip->sip_to->a_tag;
3704 } else {
3705 switch_stun_random_string(to_tag, 12, NULL);
3706 use_to_tag = to_tag;
3707 }
3708
3709 if (sip->sip_contact) {
3710 contact_host = sip->sip_contact->m_url->url_host;
3711 contact_port = sip->sip_contact->m_url->url_port;
3712 contact_user = sip->sip_contact->m_url->url_user;
3713 }
3714
3715 full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent);
3716
3717 //tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END());
3718
3719 //sip->sip_subscription_state->ss_substate
3720
3721 if (sip->sip_subscription_state && sip->sip_subscription_state->ss_substate) {
3722 if (switch_stristr("terminated", sip->sip_subscription_state->ss_substate)) {
3723 sub_state = nua_substate_terminated;
3724 } else if (switch_stristr("active", sip->sip_subscription_state->ss_substate)) {
3725 sub_state = nua_substate_active;
3726 }
3727 }
3728
3729 event = sip_header_as_string(nh->nh_home, (void *) sip->sip_event);
3730
3731 if (to) {
3732 to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host);
3733 to_user = to->a_url->url_user;
3734 to_host = to->a_url->url_host;
3735 }
3736
3737 if (profile->sub_domain) {
3738 to_host = profile->sub_domain;
3739 }
3740
3741 if (sip->sip_from) {
3742 from_user = sip->sip_from->a_url->url_user;
3743 from_host = sip->sip_from->a_url->url_host;
3744 } else {
3745 from_user = "n/a";
3746 from_host = "n/a";
3747 }
3748
3749 if ((exp_delta = sip->sip_expires ? sip->sip_expires->ex_delta : 3600)) {
3750 if ((profile->force_subscription_expires > 0) && (profile->force_subscription_expires < (uint32_t)exp_delta)) {
3751 exp_delta = profile->force_subscription_expires;
3752 }
3753 }
3754
3755 if ((sub_max_deviation_var = profile->sip_subscription_max_deviation)) {
3756 int sub_deviation;
3757 srand( (unsigned) ( (unsigned)(intptr_t)switch_thread_self() + switch_micro_time_now() ) );
3758 /* random negative number between 0 and negative sub_max_deviation_var: */
3759 sub_deviation = ( rand() % sub_max_deviation_var ) - sub_max_deviation_var;
3760 if ( (exp_delta + sub_deviation) > 45 ) {
3761 exp_delta += sub_deviation;
3762 }
3763 }
3764
3765 if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
3766 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DELTA %ld\n", exp_delta);
3767 }
3768
3769 if (!exp_delta) {
3770 sub_state = nua_substate_terminated;
3771 }
3772
3773 switch_snprintf(exp_delta_str, sizeof(exp_delta_str), "%ld", exp_delta);
3774
3775 if (!strcmp("as-feature-event", event)) {
3776 sip_authorization_t const *authorization = NULL;
3777 auth_res_t auth_res = AUTH_FORBIDDEN;
3778 char key[128] = "";
3779 switch_event_t *v_event = NULL;
3780
3781
3782 if (sip->sip_authorization) {
3783 authorization = sip->sip_authorization;
3784 } else if (sip->sip_proxy_authorization) {
3785 authorization = sip->sip_proxy_authorization;
3786 }
3787
3788 if (authorization) {
3789 char network_ip[80];
3790 int network_port;
3791 sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
3792 auth_res = sofia_reg_parse_auth(profile, authorization, sip, de,
3793 (char *) sip->sip_request->rq_method_name, key, sizeof(key), network_ip, network_port, &v_event, 0,
3794 REG_REGISTER, to_user, NULL, NULL, NULL);
3795 if (v_event) switch_event_destroy(&v_event);
3796 } else if (sofia_reg_handle_register(nua, profile, nh, sip, de, REG_REGISTER, key, sizeof(key), &v_event, NULL, NULL, NULL)) {
3797 if (v_event) switch_event_destroy(&v_event);
3798 goto end;
3799 }
3800
3801 if ((auth_res != AUTH_OK && auth_res != AUTH_RENEWED)) {
3802 nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
3803 goto end;
3804 }
3805 } else if (sofia_test_pflag(profile, PFLAG_AUTH_SUBSCRIPTIONS)) {
3806 sip_authorization_t const *authorization = NULL;
3807 auth_res_t auth_res = AUTH_FORBIDDEN;
3808 char keybuf[128] = "";
3809 char *key;
3810 size_t keylen;
3811 switch_event_t *v_event = NULL;
3812
3813 key = keybuf;
3814 keylen = sizeof(keybuf);
3815
3816 if (sip->sip_authorization) {
3817 authorization = sip->sip_authorization;
3818 } else if (sip->sip_proxy_authorization) {
3819 authorization = sip->sip_proxy_authorization;
3820 }
3821
3822 if (authorization) {
3823 char network_ip[80];
3824 int network_port;
3825 sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
3826 auth_res = sofia_reg_parse_auth(profile, authorization, sip, de,
3827 (char *) sip->sip_request->rq_method_name, key, keylen, network_ip, network_port, NULL, 0,
3828 REG_INVITE, NULL, NULL, NULL, NULL);
3829 } else if ( sofia_reg_handle_register(nua, profile, nh, sip, de, REG_INVITE, key, (uint32_t)keylen, &v_event, NULL, NULL, NULL)) {
3830 if (v_event) {
3831 switch_event_destroy(&v_event);
3832 }
3833
3834 goto end;
3835 }
3836
3837 if ((auth_res != AUTH_OK && auth_res != AUTH_RENEWED)) {
3838 nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
3839 goto end;
3840 }
3841 }
3842
3843 orig_to_user = su_strdup(nua_handle_home(nh), to_user);
3844
3845 if (to_user && (p = strchr(to_user, '+')) && p != to_user) {
3846 char *h;
3847 if ((proto = (d_user = strdup(to_user)))) {
3848 if ((my_to_user = strchr(d_user, '+'))) {
3849 *my_to_user++ = '\0';
3850 to_user = my_to_user;
3851 if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) {
3852 *h++ = '\0';
3853 to_host = h;
3854 }
3855 }
3856 }
3857
3858 if (!(proto && to_host)) {
3859 nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
3860 goto end;
3861 }
3862
3863 found_proto++;
3864 }
3865
3866 call_id = sip->sip_call_id->i_id;
3867 full_from = sip_header_as_string(nh->nh_home, (void *) sip->sip_from);
3868 full_to = sip_header_as_string(nh->nh_home, (void *) sip->sip_to);
3869 full_via = sip_header_as_string(nh->nh_home, (void *) sip->sip_via);
3870
3871
3872 if (sip->sip_expires && sip->sip_expires->ex_delta > 31536000) {
3873 sip->sip_expires->ex_delta = 31536000;
3874 }
3875
3876 if (sofia_test_pflag(profile, PFLAG_PRESENCE_MAP) && !found_proto && (alt_proto = switch_ivr_check_presence_mapping(to_user, to_host))) {
3877 orig_proto = proto;
3878 proto = alt_proto;
3879 }
3880
3881 if ((sub_state != nua_substate_terminated)) {
3882 sql = switch_mprintf("select contact from sip_subscriptions where call_id='%q' and profile_name='%q' and hostname='%q'",
3883 call_id, profile->name, mod_sofia_globals.hostname);
3884 sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, buf, sizeof(buf));
3885
3886
3887 if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
3888 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
3889 "check subs sql: %s [%s]\n", sql, buf);
3890 }
3891
3892 switch_safe_free(sql);
3893
3894 if (!zstr(buf)) {
3895 sub_state = nua_substate_active;
3896 }
3897 }
3898
3899 if (sub_state == nua_substate_active) {
3900 char *contact = contact_str;
3901
3902 sstr = switch_mprintf("active;expires=%ld", exp_delta);
3903
3904 if (strstr(buf, "fs_path=") && !strstr(contact_str, "fs_path=")) {
3905 char *e = strchr(buf,';');
3906 size_t l = e ? e-buf : strlen(buf);
3907 if (!strncmp(contact_str,buf,l)) {
3908 contact = buf;
3909 }
3910 }
3911
3912 sql = switch_mprintf("update sip_subscriptions "
3913 "set expires=%ld, "
3914 "network_ip='%q',network_port='%d',sip_user='%q',sip_host='%q',full_via='%q',full_to='%q',full_from='%q',contact='%q' "
3915 "where call_id='%q' and profile_name='%q' and hostname='%q'",
3916 (long) switch_epoch_time_now(NULL) + exp_delta,
3917 np.network_ip, np.network_port, from_user, from_host, full_via, full_to, full_from, contact,
3918
3919 call_id, profile->name, mod_sofia_globals.hostname);
3920
3921 if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
3922 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
3923 "re-subscribe event %s, sql: %s\n", event, sql);
3924 }
3925
3926 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
3927 } else {
3928
3929 if (sub_state == nua_substate_terminated) {
3930 sql = switch_mprintf("delete from sip_subscriptions where call_id='%q' and profile_name='%q' and hostname='%q'",
3931 call_id, profile->name, mod_sofia_globals.hostname);
3932
3933 if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
3934 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
3935 "sub del sql: %s\n", sql);
3936 }
3937
3938 switch_assert(sql != NULL);
3939 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
3940 sstr = switch_mprintf("terminated;reason=noresource");
3941
3942 } else {
3943 sip_accept_t *ap = sip->sip_accept;
3944 char accept_header[256] = "";
3945
3946 sub_state = nua_substate_active;
3947
3948 while (ap) {
3949 switch_snprintf(accept_header + strlen(accept_header), sizeof(accept_header) - strlen(accept_header),
3950 "%s%s ", ap->ac_type, ap->ac_next ? "," : "");
3951 ap = ap->ac_next;
3952 }
3953
3954 sql = switch_mprintf("insert into sip_subscriptions "
3955 "(proto,sip_user,sip_host,sub_to_user,sub_to_host,presence_hosts,event,contact,call_id,full_from,"
3956 "full_via,expires,user_agent,accept,profile_name,hostname,network_port,network_ip,version,orig_proto, full_to) "
3957 "values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%d','%q',-1,'%q','%q;tag=%q')",
3958 proto, from_user, from_host, to_user, to_host, profile->presence_hosts ? profile->presence_hosts : "",
3959 event, contact_str, call_id, full_from, full_via,
3960 (long) switch_epoch_time_now(NULL) + exp_delta,
3961 full_agent, accept_header, profile->name, mod_sofia_globals.hostname,
3962 np.network_port, np.network_ip, orig_proto, full_to, use_to_tag);
3963
3964 switch_assert(sql != NULL);
3965
3966
3967 if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
3968 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s SUBSCRIBE %s@%s %s@%s\n%s\n",
3969 profile->name, from_user, from_host, to_user, to_host, sql);
3970 }
3971
3972
3973 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
3974 sstr = switch_mprintf("active;expires=%ld", exp_delta);
3975 }
3976
3977 }
3978
3979 if ( sip->sip_event && sip->sip_event->o_type && !strcasecmp(sip->sip_event->o_type, "ua-profile") && contact_host ) {
3980 char *uri = NULL;
3981 char *ct = "application/url";
3982 char *extra_headers = NULL;
3983
3984 if ( contact_port ) {
3985 uri = switch_mprintf("sip:%s:%s", contact_host, contact_port);
3986 } else {
3987 uri = switch_mprintf("sip:%s", contact_host);
3988 }
3989
3990 if ( uri ) {
3991 switch_event_t *params = NULL;
3992 /* Grandstream REALLY uses a header called Message Body */
3993 extra_headers = switch_mprintf("MessageBody: %s\r\n", profile->pnp_prov_url);
3994 if (sofia_test_pflag(profile, PFLAG_SUBSCRIBE_RESPOND_200_OK)) {
3995 nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
3996 } else {
3997 nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
3998 }
3999
4000 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "sending pnp NOTIFY for %s to provision to %s\n", uri, profile->pnp_prov_url);
4001
4002 switch_event_create(¶ms, SWITCH_EVENT_NOTIFY);
4003 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", profile->name);
4004 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "event-string", sip->sip_event->o_type);
4005 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "to-uri", uri);
4006 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "from-uri", uri);
4007 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "extra-headers", extra_headers);
4008 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "content-type", ct);
4009 switch_event_add_body(params, "%s", profile->pnp_prov_url);
4010 switch_event_fire(¶ms);
4011
4012 switch_safe_free(uri);
4013 switch_safe_free(extra_headers);
4014
4015 goto end;
4016 }
4017 }
4018
4019 if (status < 200) {
4020 char *sticky = NULL;
4021 char *contactstr, *cs = NULL;
4022 char *p = NULL, *new_contactstr = NULL;
4023 sofia_transport_t transport;
4024
4025 if (np.is_nat) {
4026 char params[128] = "";
4027 if (contact->m_url->url_params) {
4028 switch_snprintf(params, sizeof(params), ";%s", contact->m_url->url_params);
4029 }
4030 ipv6 = strchr(np.network_ip, ':');
4031 sticky = switch_mprintf("sip:%s@%s%s%s:%d%s", contact_user, ipv6 ? "[" : "", np.network_ip, ipv6 ? "]" : "", np.network_port, params);
4032 }
4033
4034 if (np.is_auto_nat) {
4035 contactstr = profile->public_url;
4036 } else {
4037 contactstr = profile->url;
4038 }
4039
4040 if (sip->sip_via) {
4041 transport = sofia_glue_via2transport(sip->sip_via);
4042 } else {
4043 transport = sofia_glue_url2transport(contact->m_url);
4044 }
4045
4046 if (transport == SOFIA_TRANSPORT_TCP) {
4047 if (np.is_auto_nat) {
4048 cs = profile->tcp_public_contact;
4049 } else {
4050 cs = profile->tcp_contact;
4051 }
4052 } else if (transport == SOFIA_TRANSPORT_TCP_TLS) {
4053 if (np.is_auto_nat) {
4054 cs = sofia_test_pflag(profile, PFLAG_TLS) ? profile->tls_public_contact : profile->tcp_public_contact;
4055 } else {
4056 cs = sofia_test_pflag(profile, PFLAG_TLS) ? profile->tls_contact : profile->tcp_contact;
4057 }
4058 }
4059
4060 if (cs) {
4061 contactstr = cs;
4062 }
4063
4064
4065 if (nh && nh->nh_ds->ds_usage) {
4066 /* nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta + SUB_OVERLAP, exp_delta + SUB_OVERLAP); */
4067 nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, exp_delta, exp_delta);
4068 }
4069
4070 if (contactstr && (p = strchr(contactstr, '@'))) {
4071 if (strrchr(p, '>')) {
4072 new_contactstr = switch_mprintf("<sip:%s%s", orig_to_user, p);
4073 } else {
4074 new_contactstr = switch_mprintf("<sip:%s%s>", orig_to_user, p);
4075 }
4076 }
4077
4078 if (nh) {
4079 sip_to_tag(nh->nh_home, sip->sip_to, use_to_tag);
4080 }
4081
4082 if (mod_sofia_globals.debug_presence > 0) {
4083 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to SUBSCRIBE with 202 Accepted\n");
4084 }
4085 if (sofia_test_pflag(profile, PFLAG_SUBSCRIBE_RESPOND_200_OK)) {
4086 nua_respond(nh, SIP_200_OK,
4087 SIPTAG_TO(sip->sip_to),
4088 TAG_IF(new_contactstr, SIPTAG_CONTACT_STR(new_contactstr)),
4089 NUTAG_WITH_THIS_MSG(de->data->e_msg),
4090 SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END());
4091 } else {
4092 nua_respond(nh, SIP_202_ACCEPTED,
4093 SIPTAG_TO(sip->sip_to),
4094 TAG_IF(new_contactstr, SIPTAG_CONTACT_STR(new_contactstr)),
4095 NUTAG_WITH_THIS_MSG(de->data->e_msg),
4096 SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_EXPIRES_STR(exp_delta_str), TAG_IF(sticky, NUTAG_PROXY(sticky)), TAG_END());
4097 }
4098
4099 switch_safe_free(new_contactstr);
4100 switch_safe_free(sticky);
4101
4102 if (sub_state == nua_substate_terminated) {
4103 if (mod_sofia_globals.debug_presence > 0) {
4104 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending NOTIFY with Expires [0] and State [%s]\n", sstr);
4105 }
4106
4107 if (zstr(full_agent) || (*full_agent != 'z' && *full_agent != 'Z')) {
4108 /* supress endless loop bug with zoiper */
4109 callsequence = sofia_presence_get_cseq(profile);
4110 cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY);
4111 nua_notify(nh,
4112 SIPTAG_EXPIRES_STR("0"),
4113 SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
4114 SIPTAG_CSEQ(cseq),
4115 TAG_END());
4116 }
4117
4118
4119 }
4120 }
4121
4122 if (sub_state == nua_substate_terminated) {
4123 char *full_call_info = NULL;
4124 char *p = NULL;
4125
4126 if (sip->sip_call_info) {
4127 full_call_info = sip_header_as_string(nh->nh_home, (void *) sip->sip_call_info);
4128 if ((p = strchr(full_call_info, ';'))) {
4129 p++;
4130 }
4131
4132 #if 0
4133 nua_notify(nh,
4134 SIPTAG_EXPIRES_STR("0"),
4135 SIPTAG_SUBSCRIPTION_STATE_STR(sstr), TAG_IF(full_call_info, SIPTAG_CALL_INFO_STR(full_call_info)), TAG_END());
4136 #endif
4137
4138 if (!strcasecmp(event, "line-seize")) {
4139 if (mod_sofia_globals.debug_sla > 1) {
4140 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CANCEL LINE SEIZE\n");
4141 }
4142
4143 sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and profile_name='%q' and "
4144 "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
4145 "and call_info_state='seized'",
4146 mod_sofia_globals.hostname, profile->name, to_user, to_host, to_user, to_host);
4147
4148
4149 if (mod_sofia_globals.debug_sla > 1) {
4150 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
4151 }
4152 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
4153
4154 sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE, NULL);
4155 }
4156
4157 su_free(nh->nh_home, full_call_info);
4158
4159 }
4160
4161 } else {
4162 if (!strcasecmp(event, "line-seize")) {
4163 char *full_call_info = NULL;
4164 char *p;
4165 switch_time_t now;
4166
4167 if (sip->sip_call_info) {
4168 full_call_info = sip_header_as_string(nh->nh_home, (void *) sip->sip_call_info);
4169 if ((p = strchr(full_call_info, ';'))) {
4170 p++;
4171 }
4172 callsequence = sofia_presence_get_cseq(profile);
4173 cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY);
4174 nua_notify(nh,
4175 SIPTAG_FROM(sip->sip_to),
4176 SIPTAG_TO(sip->sip_from),
4177 SIPTAG_EXPIRES_STR(exp_delta_str),
4178 SIPTAG_CSEQ(cseq),
4179 SIPTAG_SUBSCRIPTION_STATE_STR(sstr),
4180 SIPTAG_EVENT_STR("line-seize"), TAG_IF(full_call_info, SIPTAG_CALL_INFO_STR(full_call_info)), TAG_END());
4181
4182
4183
4184
4185 sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and profile_name='%q' and "
4186 "((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') "
4187 "and call_info_state='seized' and profile_name='%q'",
4188 mod_sofia_globals.hostname, profile->name, to_user, to_host, to_user, to_host, profile->name);
4189
4190
4191 if (mod_sofia_globals.debug_sla > 1) {
4192 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CLEAR SQL %s\n", sql);
4193 }
4194 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
4195
4196 now = switch_epoch_time_now(NULL);
4197 sql = switch_mprintf("insert into sip_dialogs (sip_from_user,sip_from_host,call_info,call_info_state,hostname,expires,rcd,profile_name) "
4198 "values ('%q','%q','%q','seized','%q',%"TIME_T_FMT",%ld,'%q')",
4199 to_user, to_host, switch_str_nil(p), mod_sofia_globals.hostname,
4200 switch_epoch_time_now(NULL) + exp_delta, (long)now, profile->name);
4201
4202 if (mod_sofia_globals.debug_sla > 1) {
4203 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SEIZE SQL %s\n", sql);
4204 }
4205 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
4206 sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE, NULL);
4207
4208 su_free(nh->nh_home, full_call_info);
4209 }
4210 } else if (!strcasecmp(event, "call-info")) {
4211 sync_sla(profile, to_user, to_host, SWITCH_FALSE, SWITCH_FALSE, call_id);
4212 }
4213 }
4214
4215 sent_reply++;
4216
4217 switch_safe_free(sstr);
4218
4219 if (!strcasecmp(event, "as-feature-event")) {
4220 switch_event_t *event;
4221 char sip_cseq[40] = "";
4222
4223 switch_snprintf(sip_cseq, sizeof(sip_cseq), "%d", sip->sip_cseq->cs_seq);
4224 switch_event_create(&event, SWITCH_EVENT_PHONE_FEATURE_SUBSCRIBE);
4225 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user", from_user);
4226 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "host", from_host);
4227 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "contact", contact_str);
4228 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-id", call_id);
4229 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
4230 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "cseq", sip_cseq);
4231 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "profile_name", profile->name);
4232 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "hostname", mod_sofia_globals.hostname);
4233
4234 if (sip->sip_payload) {
4235 switch_xml_t xml = NULL;
4236 char *pd_dup = NULL;
4237
4238 pd_dup = strdup(sip->sip_payload->pl_data);
4239
4240 switch_assert(pd_dup);
4241
4242 if ((xml = switch_xml_parse_str(pd_dup, strlen(pd_dup)))) {
4243 switch_xml_t device = NULL;
4244
4245 if ((device = switch_xml_child(xml, "device"))) {
4246 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "device", device->txt);
4247 }
4248
4249 if (xml->name && !strcmp(xml->name, "SetDoNotDisturb")) {
4250 switch_xml_t action = NULL;
4251
4252 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Action", "SetDoNotDisturb");
4253 if ((action = switch_xml_child(xml, "doNotDisturbOn"))) {
4254 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Enabled", action->txt);
4255 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Name", action->name);
4256 }
4257 }
4258
4259 if (xml->name && !strcmp(xml->name, "SetForwarding")) {
4260 switch_xml_t cfwd_type, cfwd_enable, cfwd_target;
4261
4262 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Action", "SetCallForward");
4263 if ((cfwd_type = switch_xml_child(xml, "forwardingType"))
4264 && (cfwd_enable = switch_xml_child(xml, "activateForward"))
4265 && (cfwd_target = switch_xml_child(xml, "forwardDN"))) {
4266
4267 if (!strcmp(cfwd_type->txt, "forwardImmediate")) {
4268 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Enabled", cfwd_enable->txt);
4269 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Name", "forward_immediate");
4270 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Value", cfwd_target->txt);
4271 } else if (!strcmp(cfwd_type->txt, "forwardBusy")) {
4272 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Enabled", cfwd_enable->txt);
4273 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Name", "forward_busy");
4274 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Value", cfwd_target->txt);
4275 } else if (!strcmp(cfwd_type->txt, "forwardNoAns")) {
4276 switch_xml_t rc;
4277
4278 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Feature-Enabled", cfwd_enable->txt);
4279 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Name", "forward_no_answer");
4280 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action-Value", cfwd_target->txt);
4281 if ((rc = switch_xml_child(xml, "ringCount"))) {
4282 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "ringCount", rc->txt);
4283 }
4284 }
4285 }
4286 }
4287 }
4288 }
4289 switch_event_fire(&event);
4290 } else if (!strcasecmp(event, "message-summary")) {
4291 if ((sql = switch_mprintf("select proto,sip_user,'%q',sub_to_user,sub_to_host,event,contact,call_id,full_from,"
4292 "full_via,expires,user_agent,accept,profile_name,network_ip"
4293 " from sip_subscriptions where hostname='%q' and profile_name='%q' and "
4294 "event='message-summary' and sub_to_user='%q' "
4295 "and (sip_host='%q' or presence_hosts like '%%%q%%') and call_id='%q'",
4296 to_host, mod_sofia_globals.hostname, profile->name,
4297 to_user, to_host, to_host, call_id))) {
4298
4299 if (mod_sofia_globals.debug_presence > 0) {
4300 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
4301 "SUBSCRIBE MWI SQL: %s\n", sql);
4302 }
4303
4304
4305 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_sub_reg_callback, profile);
4306
4307 switch_safe_free(sql);
4308 }
4309 } else if (!strcasecmp(event, "conference")) {
4310 switch_event_t *event;
4311 switch_event_create(&event, SWITCH_EVENT_CONFERENCE_DATA_QUERY);
4312 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Name", to_user);
4313 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Domain", to_host);
4314 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Query-From", from_user);
4315 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Query-From-Domain", from_host);
4316 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Call-Id", call_id);
4317 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sofia-Profile", profile->name);
4318 switch_event_fire(&event);
4319 }
4320
4321 end:
4322
4323 if (strcasecmp(event, "call-info") && strcasecmp(event, "line-seize")) {
4324
4325 if (to_user && (strstr(to_user, "ext+") || strstr(to_user, "user+"))) {
4326 char protocol[80];
4327 char *p;
4328
4329 switch_copy_string(protocol, to_user, sizeof(protocol));
4330 if ((p = strchr(protocol, '+'))) {
4331 *p = '\0';
4332 }
4333
4334 if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
4335 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", protocol);
4336 if (!zstr(orig_proto)) {
4337 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "orig_proto", orig_proto);
4338 }
4339 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
4340 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
4341 switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, to_host);
4342 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "rpid", "active");
4343 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call");
4344 switch_event_fire(&sevent);
4345 }
4346
4347 } else if (to_user && (strcasecmp(proto, SOFIA_CHAT_PROTO) != 0)) {
4348 if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
4349 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", proto);
4350 if (!zstr(orig_proto)) {
4351 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "orig_proto", orig_proto);
4352 }
4353 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
4354 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
4355 switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
4356 switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s%s%s@%s", proto, "+", to_user, to_host);
4357 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event);
4358 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
4359 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "event_type", "presence");
4360 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
4361 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
4362 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sub-call-id", call_id);
4363 switch_event_fire(&sevent);
4364
4365 }
4366 } else {
4367
4368 if (!strcasecmp(event, "dialog")) {
4369 if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
4370 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "probe-type", "dialog");
4371 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
4372 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
4373 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
4374 switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
4375 switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, to_host);
4376 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto-specific-event-name", event);
4377 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
4378 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "event_type", "presence");
4379 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
4380 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
4381 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sub-call-id", call_id);
4382 switch_event_fire(&sevent);
4383 }
4384 } else if (!strcasecmp(event, "presence")) {
4385 if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) {
4386 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
4387 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "login", profile->name);
4388 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
4389 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "presence-source", "subscribe");
4390 switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
4391 switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, to_host);
4392 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "expires", exp_delta_str);
4393 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
4394 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "rpid", "unknown");
4395 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "status", "Registered");
4396 switch_event_add_header_string(sevent, SWITCH_STACK_BOTTOM, "sub-call-id", call_id);
4397 switch_event_fire(&sevent);
4398 }
4399 }
4400 }
4401 }
4402
4403 if (event) {
4404 su_free(nh->nh_home, event);
4405 }
4406
4407 if (full_from) {
4408 su_free(nh->nh_home, full_from);
4409 }
4410 if (full_to) {
4411 su_free(nh->nh_home, full_to);
4412 }
4413
4414 if (full_via) {
4415 su_free(nh->nh_home, full_via);
4416 }
4417 if (full_agent) {
4418 su_free(nh->nh_home, full_agent);
4419 }
4420
4421 switch_safe_free(d_user);
4422 switch_safe_free(to_str);
4423 switch_safe_free(contact_str);
4424 switch_safe_free(alt_proto);
4425
4426 if (!sent_reply) {
4427 nua_respond(nh, 481, "INVALID SUBSCRIPTION", TAG_END());
4428 }
4429
4430 if (!sofia_private || !sofia_private->is_call) {
4431 nua_handle_destroy(nh);
4432 }
4433
4434 }
4435
4436
sofia_find_gateway_subscription(sofia_gateway_t * gateway_ptr,const char * event)4437 sofia_gateway_subscription_t *sofia_find_gateway_subscription(sofia_gateway_t *gateway_ptr, const char *event)
4438 {
4439 sofia_gateway_subscription_t *gw_sub_ptr;
4440 for (gw_sub_ptr = gateway_ptr->subscriptions; gw_sub_ptr; gw_sub_ptr = gw_sub_ptr->next) {
4441 if (!strcasecmp(gw_sub_ptr->event, event)) {
4442 /* this is the gateway subscription we are interested in */
4443 return gw_sub_ptr;
4444 }
4445 }
4446 return NULL;
4447 }
4448
sofia_presence_handle_sip_r_subscribe(int status,char const * phrase,nua_t * nua,sofia_profile_t * profile,nua_handle_t * nh,sofia_private_t * sofia_private,sip_t const * sip,sofia_dispatch_event_t * de,tagi_t tags[])4449 void sofia_presence_handle_sip_r_subscribe(int status,
4450 char const *phrase,
4451 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
4452 sofia_dispatch_event_t *de,
4453 tagi_t tags[])
4454 {
4455 sip_event_t const *o = NULL;
4456 sofia_gateway_subscription_t *gw_sub_ptr;
4457 sofia_gateway_t *gateway = NULL;
4458
4459 if (!sip) {
4460 return;
4461 }
4462
4463 tl_gets(tags, SIPTAG_EVENT_REF(o), TAG_END());
4464 /* o->o_type: message-summary (for example) */
4465 if (!o) {
4466 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event information not given\n");
4467 return;
4468 }
4469
4470 if (!sofia_private || zstr(sofia_private->gateway_name)) {
4471 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
4472 return;
4473 }
4474
4475
4476 if (!(gateway = sofia_reg_find_gateway(sofia_private->gateway_name))) {
4477 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Gateway information missing\n");
4478 return;
4479 }
4480
4481
4482 /* Find the subscription if one exists */
4483 if (!(gw_sub_ptr = sofia_find_gateway_subscription(gateway, o->o_type))) {
4484 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Could not find gateway subscription. Gateway: %s. Subscription Event: %s\n",
4485 gateway->name, o->o_type);
4486 goto end;
4487 }
4488
4489 /* Update the subscription status for the subscription */
4490 switch (status) {
4491 case 200:
4492 case 202:
4493 /* TODO: in the spec it is possible for the other side to change the original expiry time,
4494 * this needs to be researched (eg, what sip header this information will be in) and implemented.
4495 * Although, since it seems the sofia stack is pretty much handling the subscription expiration
4496 * anyway, then maybe its not even worth bothering.
4497 */
4498 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got 200 OK response, updated state to SUB_STATE_SUBSCRIBE.\n");
4499 gw_sub_ptr->state = SUB_STATE_SUBSCRIBE;
4500 break;
4501 case 100:
4502 break;
4503 default:
4504 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "status (%d) != 200, updated state to SUB_STATE_FAILED.\n", status);
4505 gw_sub_ptr->state = SUB_STATE_FAILED;
4506
4507 break;
4508 }
4509
4510 end:
4511 sofia_reg_release_gateway(gateway);
4512
4513 }
4514
4515
sofia_presence_send_sql(void * pArg,int argc,char ** argv,char ** columnNames)4516 static int sofia_presence_send_sql(void *pArg, int argc, char **argv, char **columnNames)
4517 {
4518 struct pres_sql_cb *cb = (struct pres_sql_cb *) pArg;
4519
4520
4521 if (mod_sofia_globals.debug_presence > 0) {
4522 int i;
4523 for(i = 0; i < argc; i++) {
4524 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "arg %d[%s] = [%s]\n", i, columnNames[i], argv[i]);
4525 }
4526 }
4527
4528 send_presence_notify(cb->profile, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], NULL);
4529 cb->ttl++;
4530
4531 return 0;
4532 }
4533
4534
sofia_presence_contact_count(sofia_profile_t * profile,const char * contact_str)4535 uint32_t sofia_presence_contact_count(sofia_profile_t *profile, const char *contact_str)
4536 {
4537 char buf[32] = "";
4538 char *sql;
4539
4540 sql = switch_mprintf("select count(*) from sip_subscriptions where hostname='%q' and profile_name='%q' and contact='%q'",
4541 mod_sofia_globals.hostname, profile->name, contact_str);
4542
4543 sofia_glue_execute_sql2str(profile, profile->dbh_mutex, sql, buf, sizeof(buf));
4544 switch_safe_free(sql);
4545 return atoi(buf);
4546 }
4547
sofia_presence_handle_sip_i_publish(nua_t * nua,sofia_profile_t * profile,nua_handle_t * nh,sofia_private_t * sofia_private,sip_t const * sip,sofia_dispatch_event_t * de,tagi_t tags[])4548 void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
4549 sofia_dispatch_event_t *de,
4550 tagi_t tags[])
4551 {
4552
4553 sip_from_t const *from;
4554 char *from_user = NULL;
4555 char *from_host = NULL;
4556 char *rpid = "";
4557 sip_payload_t *payload;
4558 char *event_type = NULL;
4559 char etag[9] = "";
4560 char expstr[30] = "";
4561 long exp = 0, exp_delta = 3600;
4562 char *pd_dup = NULL;
4563 int count = 1, sub_count = 1;
4564 char *contact_str;
4565 sofia_nat_parse_t np = { { 0 } };
4566
4567 if (!sip) {
4568 return;
4569 }
4570
4571 from = sip->sip_from;
4572 payload = sip->sip_payload;
4573
4574 np.fs_path = 1;
4575 contact_str = sofia_glue_gen_contact_str(profile, sip, nh, de, &np);
4576
4577 if (from) {
4578 from_user = (char *) from->a_url->url_user;
4579 from_host = (char *) from->a_url->url_host;
4580 }
4581
4582 exp_delta = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
4583 if ((profile->force_publish_expires > 0) && (profile->force_publish_expires < (uint32_t)exp_delta)) {
4584 exp_delta = profile->force_publish_expires;
4585 }
4586
4587 if (exp_delta < 0) {
4588 exp = exp_delta;
4589 } else {
4590 exp = (long) switch_epoch_time_now(NULL) + exp_delta;
4591 }
4592
4593 if (payload) {
4594 switch_xml_t xml, note, person, tuple, status, basic, act;
4595 switch_event_t *event;
4596 char *sql;
4597 char *full_agent = NULL;
4598 char network_ip[80];
4599 int network_port = 0;
4600
4601 sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
4602
4603 pd_dup = strdup(payload->pl_data);
4604
4605 switch_assert(pd_dup);
4606
4607 if ((xml = switch_xml_parse_str(pd_dup, strlen(pd_dup)))) {
4608 char *open_closed = "", *note_txt = "";
4609
4610 if (sip->sip_user_agent) {
4611 full_agent = sip_header_as_string(nh->nh_home, (void *) sip->sip_user_agent);
4612 }
4613
4614 if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status"))
4615 && (basic = switch_xml_child(status, "basic"))) {
4616 open_closed = basic->txt;
4617
4618 if ((note = switch_xml_child(tuple, "note"))) {
4619 rpid = note_txt = note->txt;
4620 } else if ((note = switch_xml_child(tuple, "dm:note"))) {
4621 rpid = note_txt = note->txt;
4622 }
4623 }
4624
4625 if ((person = switch_xml_child(xml, "dm:person"))) {
4626 if ((note = switch_xml_child(person, "dm:note"))) {
4627 note_txt = note->txt;
4628 } else if ((note = switch_xml_child(person, "rpid:note"))) {
4629 note_txt = note->txt;
4630 }
4631 if ((act = switch_xml_child(person, "rpid:activities")) && act->child && act->child->name) {
4632 if ((rpid = strchr(act->child->name, ':'))) {
4633 rpid++;
4634 } else {
4635 rpid = act->child->name;
4636 }
4637 }
4638 if (zstr(note_txt)) note_txt = "Available";
4639 }
4640
4641 if (!strcasecmp(open_closed, "closed")) {
4642 rpid = note_txt = "Unregistered";
4643 if (sofia_test_pflag(profile, PFLAG_MULTIREG)) {
4644 count = sofia_reg_reg_count(profile, from_user, from_host);
4645
4646 if (count != 1) {
4647 /* Don't broadcast offline when there is more than one client or one signing off makes them all appear to sign off on some clients */
4648 count = 0;
4649 } else {
4650 sub_count = sofia_presence_contact_count(profile, contact_str);
4651 }
4652 }
4653 }
4654
4655 event_type = sip_header_as_string(nh->nh_home, (void *) sip->sip_event);
4656
4657 if (count) {
4658 if ((sql = switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' "
4659 " and profile_name='%q' and hostname='%q'",
4660 from_user, from_host, profile->name, mod_sofia_globals.hostname))) {
4661 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
4662 }
4663
4664 if (sub_count > 0 && (sql = switch_mprintf("insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent,"
4665 " profile_name, hostname, open_closed, network_ip, network_port) "
4666 "values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q','%q','%d')",
4667 from_user, from_host, note_txt, rpid, exp, full_agent, profile->name,
4668 mod_sofia_globals.hostname, open_closed, network_ip, network_port))) {
4669
4670 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
4671 }
4672
4673 } else if (contact_str) {
4674 struct pres_sql_cb cb = {profile, 0};
4675
4676 sql = switch_mprintf("select full_to, full_from, contact, expires, call_id, event, network_ip, network_port, "
4677 "'application/pidf+xml' as ct,'%q' as pt "
4678 " from sip_subscriptions where "
4679 "hostname='%q' and profile_name='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q'"
4680 "and contact = '%q' ",
4681
4682 switch_str_nil(payload->pl_data),
4683 mod_sofia_globals.hostname, profile->name,
4684 from_user, from_host, event_type, contact_str);
4685
4686 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_send_sql, &cb);
4687 switch_safe_free(sql);
4688 }
4689
4690 if (sub_count > 0) {
4691 if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
4692 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
4693 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
4694 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
4695 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
4696 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent", full_agent);
4697 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
4698 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", note_txt);
4699 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", event_type);
4700 switch_event_fire(&event);
4701 }
4702 }
4703
4704 if (event_type) {
4705 su_free(nh->nh_home, event_type);
4706 }
4707
4708 if (full_agent) {
4709 su_free(nh->nh_home, full_agent);
4710 }
4711
4712 switch_xml_free(xml);
4713 }
4714 } else {
4715 char *sql = switch_mprintf("update sip_presence set expires=%ld where sip_user='%q' and sip_host='%q' and profile_name='%q' and hostname='%q'",
4716 exp, from_user, from_host, profile->name, mod_sofia_globals.hostname);
4717 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
4718 }
4719
4720 switch_safe_free(pd_dup);
4721
4722 switch_snprintf(expstr, sizeof(expstr), "%d", exp_delta);
4723 switch_stun_random_string(etag, 8, NULL);
4724
4725 if (sub_count > 0) {
4726 nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_ETAG_STR(etag), SIPTAG_EXPIRES_STR(expstr), TAG_END());
4727 } else {
4728 nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
4729 }
4730
4731 switch_safe_free(contact_str);
4732 }
4733
sofia_presence_set_hash_key(char * hash_key,int32_t len,sip_t const * sip)4734 void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip)
4735 {
4736 url_t *to = sip->sip_to->a_url;
4737 url_t *from = sip->sip_from->a_url;
4738 switch_snprintf(hash_key, len, "%s%s%s", from->url_user, from->url_host, to->url_user);
4739 }
4740
sofia_presence_handle_sip_i_message(int status,char const * phrase,nua_t * nua,sofia_profile_t * profile,nua_handle_t * nh,switch_core_session_t * session,sofia_private_t * sofia_private,sip_t const * sip,sofia_dispatch_event_t * de,tagi_t tags[])4741 void sofia_presence_handle_sip_i_message(int status,
4742 char const *phrase,
4743 nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh,
4744 switch_core_session_t *session,
4745 sofia_private_t *sofia_private, sip_t const *sip,
4746 sofia_dispatch_event_t *de,
4747 tagi_t tags[])
4748 {
4749
4750 if (sip) {
4751 sip_from_t const *from = sip->sip_from;
4752 const char *from_user = NULL;
4753 const char *from_host = NULL;
4754 sip_to_t const *to = sip->sip_to;
4755 const char *to_user = NULL;
4756 const char *to_host = NULL;
4757 sip_payload_t *payload = sip->sip_payload;
4758 char *msg = NULL;
4759 const char *us;
4760 char network_ip[80];
4761 int network_port = 0;
4762 switch_channel_t *channel = NULL;
4763
4764
4765 if (!sofia_test_pflag(profile, PFLAG_ENABLE_CHAT)) {
4766 goto end;
4767 }
4768
4769
4770 if (session) {
4771 channel = switch_core_session_get_channel(session);
4772 }
4773
4774 if (sofia_test_pflag(profile, PFLAG_AUTH_MESSAGES)) {
4775 sip_authorization_t const *authorization = NULL;
4776 auth_res_t auth_res = AUTH_FORBIDDEN;
4777 char keybuf[128] = "";
4778 char *key;
4779 size_t keylen;
4780 switch_event_t *v_event = NULL;
4781
4782 key = keybuf;
4783 keylen = sizeof(keybuf);
4784
4785 if (sip->sip_authorization) {
4786 authorization = sip->sip_authorization;
4787 } else if (sip->sip_proxy_authorization) {
4788 authorization = sip->sip_proxy_authorization;
4789 }
4790
4791 if (authorization) {
4792 char network_ip[80];
4793 int network_port;
4794 sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
4795 auth_res = sofia_reg_parse_auth(profile, authorization, sip, de,
4796 (char *) sip->sip_request->rq_method_name, key, keylen, network_ip, network_port, NULL, 0,
4797 REG_INVITE, NULL, NULL, NULL, NULL);
4798 } else if ( sofia_reg_handle_register(nua, profile, nh, sip, de, REG_INVITE, key, (uint32_t)keylen, &v_event, NULL, NULL, NULL)) {
4799 if (v_event) {
4800 switch_event_destroy(&v_event);
4801 }
4802
4803 goto end;
4804 }
4805
4806 if ((auth_res != AUTH_OK && auth_res != AUTH_RENEWED)) {
4807 nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
4808 goto end;
4809 }
4810
4811 if (channel) {
4812 switch_channel_set_variable(channel, "sip_authorized", "true");
4813 }
4814 }
4815
4816 if ((us = sofia_glue_get_unknown_header(sip, "X-FS-Sending-Message")) && !strcmp(us, switch_core_get_uuid())) {
4817 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not sending message to ourselves!\n");
4818 nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
4819 return;
4820 }
4821
4822 if (sip->sip_content_type && sip->sip_content_type->c_subtype) {
4823 if (strstr(sip->sip_content_type->c_subtype, "composing")) {
4824 goto end;
4825 }
4826 }
4827
4828
4829 sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
4830
4831
4832 if (from) {
4833 from_user = from->a_url->url_user;
4834 from_host = from->a_url->url_host;
4835 }
4836
4837 if (to) {
4838 to_user = to->a_url->url_user;
4839 to_host = to->a_url->url_host;
4840 }
4841
4842 if (!to_user) {
4843 goto end;
4844 }
4845
4846 if (payload) {
4847 msg = payload->pl_data;
4848 }
4849
4850 if (nh) {
4851 char hash_key[512];
4852 private_object_t *tech_pvt;
4853 switch_event_t *event, *event_dup;
4854 char *to_addr;
4855 char *from_addr;
4856 char *p;
4857 char *full_from;
4858 char proto[512] = SOFIA_CHAT_PROTO;
4859 sip_unknown_t *un;
4860 int first_history_info = 1;
4861
4862 full_from = sip_header_as_string(nh->nh_home, (void *) sip->sip_from);
4863
4864 if ((p = strchr(to_user, '+')) && p != to_user) {
4865 switch_copy_string(proto, to_user, sizeof(proto));
4866 p = strchr(proto, '+');
4867 *p++ = '\0';
4868
4869 if ((to_addr = strdup(p))) {
4870 if ((p = strchr(to_addr, '+'))) {
4871 *p = '@';
4872 }
4873 }
4874 } else {
4875 to_addr = switch_mprintf("%s@%s", to_user, to_host);
4876 }
4877
4878 from_addr = switch_mprintf("%s@%s", from_user, from_host);
4879
4880 if (sofia_test_pflag(profile, PFLAG_IN_DIALOG_CHAT)) {
4881 sofia_presence_set_hash_key(hash_key, sizeof(hash_key), sip);
4882 }
4883
4884 if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
4885 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
4886 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
4887
4888 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to_proto", proto);
4889
4890 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", from_addr);
4891 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_user", from_user);
4892 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_host", from_host);
4893 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to_user", to_user);
4894 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to_host", to_host);
4895 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_sip_ip", network_ip);
4896 switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from_sip_port", "%d", network_port);
4897 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to", to_addr);
4898 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "subject", "SIMPLE MESSAGE");
4899 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "context", profile->context);
4900
4901 if (sip->sip_content_type && sip->sip_content_type->c_subtype) {
4902 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", sip->sip_content_type->c_type);
4903 } else {
4904 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "text/plain");
4905 }
4906
4907 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_full", full_from);
4908 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_profile", profile->name);
4909
4910
4911 if (sip->sip_call_info) {
4912 sip_call_info_t *call_info = sip->sip_call_info;
4913 char *ci = sip_header_as_string(nua_handle_home(nh), (void *) call_info);
4914 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_call_info", ci);
4915 }
4916
4917 /* Loop thru unknown Headers Here so we can do something with them */
4918 for (un = sip->sip_unknown; un; un = un->un_next) {
4919 if (!strncasecmp(un->un_name, "Diversion", 9)) {
4920 /* Basic Diversion Support for Diversion Indication in SIP */
4921 /* draft-levy-sip-diversion-08 */
4922 if (!zstr(un->un_value)) {
4923 char *tmp_name;
4924 if ((tmp_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) {
4925 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, tmp_name, un->un_value);
4926 free(tmp_name);
4927 }
4928 }
4929 } else if (!strncasecmp(un->un_name, "History-Info", 12)) {
4930 if (first_history_info) {
4931 /* If the header exists first time, make sure to remove old info and re-set the variable */
4932 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_history_info", un->un_value);
4933 first_history_info = 0;
4934 } else {
4935 /* Append the History-Info into one long string */
4936 const char *history_var = switch_event_get_header(event, "sip_history_info");
4937 if (!zstr(history_var)) {
4938 char *tmp_str;
4939 if ((tmp_str = switch_mprintf("%s, %s", history_var, un->un_value))) {
4940 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_history_info", tmp_str);
4941 free(tmp_str);
4942 } else {
4943 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_history_info", un->un_value);
4944 }
4945 } else {
4946 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_history_info", un->un_value);
4947 }
4948 }
4949 } else if (!strcasecmp(un->un_name, "Geolocation")) {
4950 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_geolocation", un->un_value);
4951 } else if (!strcasecmp(un->un_name, "Geolocation-Error")) {
4952 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sip_geolocation_error", un->un_value);
4953 } else if (!strncasecmp(un->un_name, "X-", 2) || !strncasecmp(un->un_name, "P-", 2) || !strcasecmp(un->un_name, "User-to-User")) {
4954 if (!zstr(un->un_value)) {
4955 char new_name[512] = "";
4956 int reps = 0;
4957 for (;;) {
4958 char postfix[25] = "";
4959 if (reps > 0) {
4960 switch_snprintf(postfix, sizeof(postfix), "-%d", reps);
4961 }
4962 reps++;
4963 switch_snprintf(new_name, sizeof(new_name), "%s%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name, postfix);
4964
4965 if (switch_event_get_header(event, new_name)) {
4966 continue;
4967 }
4968
4969 switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, new_name, un->un_value);
4970 break;
4971 }
4972 }
4973 }
4974 }
4975
4976 if (msg) {
4977 switch_event_add_body(event, "%s", msg);
4978 }
4979
4980 if (channel) {
4981 switch_channel_event_set_data(channel, event);
4982 }
4983
4984
4985 if (sofia_test_pflag(profile, PFLAG_FIRE_MESSAGE_EVENTS)) {
4986 if (switch_event_dup(&event_dup, event) == SWITCH_STATUS_SUCCESS) {
4987 event_dup->event_id = SWITCH_EVENT_RECV_MESSAGE;
4988 event_dup->flags |= EF_UNIQ_HEADERS;
4989 switch_event_add_header_string(event_dup, SWITCH_STACK_BOTTOM, "Event-Name", switch_event_name(event_dup->event_id));
4990 switch_event_fire(&event_dup);
4991 }
4992 }
4993
4994 if (session) {
4995 if (switch_event_dup(&event_dup, event) == SWITCH_STATUS_SUCCESS) {
4996 switch_core_session_queue_event(session, &event_dup);
4997 }
4998 }
4999
5000
5001 } else {
5002 abort();
5003 }
5004
5005 if (sofia_test_pflag(profile, PFLAG_IN_DIALOG_CHAT) && (tech_pvt = (private_object_t *) switch_core_hash_find_locked(profile->chat_hash, hash_key, profile->flag_mutex))) {
5006 switch_core_session_queue_event(tech_pvt->session, &event);
5007 } else {
5008 switch_core_chat_send(proto, event);
5009 switch_event_destroy(&event);
5010 }
5011
5012 switch_safe_free(to_addr);
5013 switch_safe_free(from_addr);
5014
5015 if (full_from) {
5016 su_free(nh->nh_home, full_from);
5017 }
5018 }
5019 }
5020
5021 end:
5022
5023 if (sofia_test_pflag(profile, PFLAG_MESSAGES_RESPOND_200_OK)) {
5024 nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
5025 } else {
5026 nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
5027 }
5028
5029 }
5030
sofia_presence_set_chat_hash(private_object_t * tech_pvt,sip_t const * sip)5031 void sofia_presence_set_chat_hash(private_object_t *tech_pvt, sip_t const *sip)
5032 {
5033 char hash_key[256] = "";
5034 char buf[512];
5035 su_home_t *home = NULL;
5036
5037 if (!tech_pvt || tech_pvt->hash_key || !sip || !sip->sip_from || !sip->sip_from->a_url->url_user || !sip->sip_from->a_url->url_host) {
5038 return;
5039 }
5040
5041 if (sofia_reg_find_reg_url(tech_pvt->profile, sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host, buf, sizeof(buf))) {
5042 home = su_home_new(sizeof(*home));
5043 switch_assert(home != NULL);
5044 tech_pvt->chat_from = sip_header_as_string(home, (const sip_header_t *) sip->sip_to);
5045 tech_pvt->chat_to = switch_core_session_strdup(tech_pvt->session, buf);
5046 sofia_presence_set_hash_key(hash_key, sizeof(hash_key), sip);
5047 su_home_unref(home);
5048 home = NULL;
5049 } else {
5050 return;
5051 }
5052
5053 switch_mutex_lock(tech_pvt->profile->flag_mutex);
5054 tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
5055 switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
5056 switch_mutex_unlock(tech_pvt->profile->flag_mutex);
5057 }
5058
5059
sofia_presence_check_subscriptions(sofia_profile_t * profile,time_t now)5060 void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now)
5061 {
5062 char *sql;
5063
5064 if (now) {
5065 struct pres_sql_cb cb = {profile, 0};
5066
5067 if (profile->pres_type != PRES_TYPE_FULL) {
5068 if (mod_sofia_globals.debug_presence > 0) {
5069 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "check_subs: %s is passive, skipping\n", (char *) profile->name);
5070 }
5071 return;
5072 }
5073
5074 sql = switch_mprintf("update sip_subscriptions set version=version+1 where "
5075 "((expires > 0 and expires <= %ld)) and profile_name='%q' and hostname='%q'",
5076 (long) now, profile->name, mod_sofia_globals.hostname);
5077
5078 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
5079 switch_safe_free(sql);
5080
5081 sql = switch_mprintf("select full_to, full_from, contact, -1, call_id, event, network_ip, network_port, "
5082 "NULL as ct, NULL as pt "
5083 " from sip_subscriptions where ((expires > 0 and expires <= %ld)) and profile_name='%q' and hostname='%q'",
5084 (long) now, profile->name, mod_sofia_globals.hostname);
5085
5086 sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sofia_presence_send_sql, &cb);
5087 switch_safe_free(sql);
5088
5089 if (cb.ttl) {
5090 sql = switch_mprintf("delete from sip_subscriptions where ((expires > 0 and expires <= %ld)) "
5091 "and profile_name='%q' and hostname='%q'",
5092 (long) now, profile->name, mod_sofia_globals.hostname);
5093
5094 if (mod_sofia_globals.debug_presence > 0 || mod_sofia_globals.debug_sla > 0) {
5095 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
5096 "sub del sql: %s\n", sql);
5097 }
5098
5099 sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
5100 }
5101 }
5102
5103
5104
5105 }
5106
5107
5108 /* For Emacs:
5109 * Local Variables:
5110 * mode:c
5111 * indent-tabs-mode:t
5112 * tab-width:4
5113 * c-basic-offset:4
5114 * End:
5115 * For VIM:
5116 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
5117 */
5118