1 /*
2  * libDingaLing XMPP Jingle Library
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 libDingaLing XMPP Jingle Library
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  *
28  * libdingaling.c -- Main Library Code
29  *
30  * QMOD: XMPP Video Signaling + Presentation (video-v1 & camera-v1)
31  *
32  */
33 
34 
35 #ifndef  _MSC_VER
36 #include <config.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <time.h>
42 #endif
43 
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <assert.h>
48 #include <ctype.h>
49 #include <fcntl.h>
50 #include <iksemel.h>
51 #include <apr.h>
52 #include <apr_network_io.h>
53 #include <apr_errno.h>
54 #include <apr_general.h>
55 #include <apr_thread_proc.h>
56 #include <apr_thread_mutex.h>
57 #include <apr_thread_cond.h>
58 #include <apr_thread_rwlock.h>
59 #include <apr_file_io.h>
60 #include <apr_poll.h>
61 #include <apr_dso.h>
62 #include <apr_hash.h>
63 #include <apr_strings.h>
64 #include <apr_network_io.h>
65 #include <apr_poll.h>
66 #include <apr_queue.h>
67 #include <apr_uuid.h>
68 #include <apr_strmatch.h>
69 #define APR_WANT_STDIO
70 #define APR_WANT_STRFUNC
71 #include <apr_want.h>
72 #include <apr_env.h>
73 
74 #include "ldl_compat.h"
75 #include "libdingaling.h"
76 #include "sha1.h"
77 
78 #ifdef _MSC_VER
79 #include <io.h>
80 #pragma warning(disable:4127 4706)
81 #endif
82 
83 #define microsleep(x) apr_sleep(x * 1000)
84 #define LDL_CAPS_VER "1.0.0.1"
85 
86 static int opt_timeout = 30;
87 
88 static void sha1_hash(char *out, unsigned char *in, unsigned int len);
89 static int b64encode(unsigned char *in, size_t ilen, unsigned char *out, size_t olen);
90 static void ldl_random_string(char *buf, uint16_t len, char *set);
91 
92 static struct {
93 	unsigned int flags;
94 	FILE *log_stream;
95 	int debug;
96 	apr_pool_t *memory_pool;
97 	unsigned int id;
98 	ldl_logger_t logger;
99 	apr_hash_t *avatar_hash;
100 	apr_thread_mutex_t *flag_mutex;
101 } globals;
102 
103 struct packet_node {
104 	char id[80];
105 	iks *xml;
106 	unsigned int retries;
107 	apr_time_t next;
108 };
109 
110 struct ldl_buffer {
111 	char *buf;
112 	unsigned int len;
113 	int hit;
114 };
115 
116 typedef enum {
117 	CS_NEW,
118 	CS_START,
119 	CS_CONNECTED
120 } ldl_handle_state_t;
121 
122 struct ldl_handle {
123 	iksparser *parser;
124 	iksid *acc;
125 	iksfilter *filter;
126 	char *login;
127 	char *password;
128 	char *server;
129 	char *status_msg;
130 	char *priority;
131 	uint16_t port;
132 	int features;
133 	int counter;
134 	int job_done;
135 	unsigned int flags;
136 	apr_queue_t *queue;
137 	apr_queue_t *retry_queue;
138 	apr_hash_t *sessions;
139 	apr_hash_t *retry_hash;
140 	apr_hash_t *probe_hash;
141 	apr_hash_t *sub_hash;
142 	apr_thread_mutex_t *lock;
143 	apr_thread_mutex_t *flag_mutex;
144 	ldl_loop_callback_t loop_callback;
145 	ldl_session_callback_t session_callback;
146 	ldl_response_callback_t response_callback;
147 	apr_pool_t *pool;
148 	void *private_info;
149 	FILE *log_stream;
150 	ldl_handle_state_t state;
151 	int fail_count;
152 };
153 
154 struct ldl_session {
155 	ldl_state_t state;
156 	ldl_handle_t *handle;
157 	char *id;
158 	char *initiator;
159 	char *them;
160 	char *ip;
161 	char *login;
162 	ldl_payload_t payloads[LDL_MAX_PAYLOADS];
163 	unsigned int payload_len;
164 	/*! \brief Transport candidates, organized per type */
165 	ldl_candidate_t candidates[LDL_TPORT_MAX][LDL_MAX_CANDIDATES];
166 	/*! \brief Length of the candidate list, per transport type */
167 	unsigned int candidate_len[LDL_TPORT_MAX];
168 	apr_pool_t *pool;
169 	apr_hash_t *variables;
170 	apr_time_t created;
171 	void *private_data;
172 	ldl_user_flag_t flags;
173 };
174 
175 static int on_disco_default(void *user_data, ikspak *pak);
176 static int on_vcard(void *user_data, ikspak *pak);
177 typedef int (*iks_filter_callback_t)(void *user_data, ikspak *pak);
178 
179 struct ldl_feature {
180 	const char *name;
181 	iks_filter_callback_t callback;
182 };
183 typedef struct ldl_feature ldl_feature_t;
184 
185 #define FEATURE_DISCO "http://jabber.org/protocol/disco"
186 #define FEATURE_DISCO_INFO "http://jabber.org/protocol/disco#info"
187 #define FEATURE_VERSION "jabber:iq:version"
188 #define FEATURE_VCARD "vcard-temp"
189 #define FEATURE_VOICE "http://www.google.com/xmpp/protocol/voice/v1"
190 #define FEATURE_VIDEO "http://www.google.com/xmpp/protocol/video/v1"
191 #define FEATURE_CAMERA "http://www.google.com/xmpp/protocol/camera/v1"
192 #define FEATURE_LAST "jabber:iq:last"
193 
194 static ldl_feature_t FEATURES[] = {
195 	{ FEATURE_DISCO, on_disco_default },
196 	{ FEATURE_DISCO_INFO, on_disco_default },
197 	{ FEATURE_VERSION, on_disco_default },
198 	{ FEATURE_VCARD, on_vcard},
199 	{ FEATURE_VOICE, on_disco_default },
200 	{ FEATURE_VIDEO, on_disco_default },
201 	{ FEATURE_CAMERA, on_disco_default },
202 	{ FEATURE_LAST, on_disco_default },
203 	{ NULL, NULL}
204 };
205 
206 
207 struct ldl_avatar {
208 	char *path;
209 	char *base64;
210 	char hash[256];
211 };
212 
213 typedef struct ldl_avatar ldl_avatar_t;
214 
215 
lowercase(char * str)216 static void lowercase(char *str)
217 {
218 	size_t x = 0;
219 
220 	if (str) {
221 		for (x = 0; x < strlen(str); x++) {
222 			str[x] = (char)tolower((int)str[x]);
223 		}
224 	}
225 }
226 
cut_path(char * in)227 static char *cut_path(char *in)
228 {
229 	char *p, *ret = in;
230 	char delims[] = "/\\";
231 	char *i;
232 
233 	for (i = delims; *i; i++) {
234 		p = in;
235 		while ((p = strchr(p, *i)) != 0) {
236 			ret = ++p;
237 		}
238 	}
239 	return ret;
240 }
241 
default_logger(char * file,const char * func,int line,int level,char * fmt,...)242 static void default_logger(char *file, const char *func, int line, int level, char *fmt, ...)
243 {
244 	char *fp;
245 	char data[1024];
246 
247 	va_list ap;
248 
249 	fp = cut_path(file);
250 
251 	va_start(ap, fmt);
252 
253 	vsnprintf(data, sizeof(data), fmt, ap);
254 
255 	fprintf(globals.log_stream, "%s:%d %s() %s", fp, line, func, data);
256 
257 	va_end(ap);
258 
259 }
260 
next_id(void)261 static unsigned int next_id(void)
262 {
263 	return globals.id++;
264 }
265 
iks_name_nons(iks * x)266 static char *iks_name_nons(iks *x)
267 {
268 	char *r = iks_name(x);
269 	char *p;
270 
271 	if (r && (p = strchr(r, ':'))) {
272 		r = p + 1;
273 	}
274 
275 	return r;
276 }
277 
278 
ldl_session_get_value(ldl_session_t * session,char * key)279 char *ldl_session_get_value(ldl_session_t *session, char *key)
280 {
281 	return apr_hash_get(session->variables, key, APR_HASH_KEY_STRING);
282 }
283 
ldl_session_set_value(ldl_session_t * session,const char * key,const char * val)284 void ldl_session_set_value(ldl_session_t *session, const char *key, const char *val)
285 {
286 	apr_hash_set(session->variables, apr_pstrdup(session->pool, key), APR_HASH_KEY_STRING, apr_pstrdup(session->pool, val));
287 }
288 
ldl_session_get_id(ldl_session_t * session)289 char *ldl_session_get_id(ldl_session_t *session)
290 {
291 	return session->id;
292 }
293 
ldl_session_send_msg(ldl_session_t * session,char * subject,char * body)294 void ldl_session_send_msg(ldl_session_t *session, char *subject, char *body)
295 {
296 	ldl_handle_send_msg(session->handle, session->login, session->them, subject, body);
297 }
298 
ldl_session_destroy(ldl_session_t ** session_p)299 ldl_status ldl_session_destroy(ldl_session_t **session_p)
300 {
301 	ldl_session_t *session = *session_p;
302 
303 	if (session) {
304 		apr_pool_t *pool = session->pool;
305 		apr_hash_t *hash = session->handle->sessions;
306 
307 		if (globals.debug) {
308 			globals.logger(DL_LOG_CRIT, "Destroyed Session %s\n", session->id);
309 		}
310 
311 		if (session->id) {
312 			apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL);
313 		}
314 
315 		if (session->them) {
316 			apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL);
317 		}
318 
319 		apr_pool_destroy(pool);
320 		pool = NULL;
321 		*session_p = NULL;
322 		return LDL_STATUS_SUCCESS;
323 	}
324 
325 	return LDL_STATUS_FALSE;
326 }
327 
328 
ldl_session_create(ldl_session_t ** session_p,ldl_handle_t * handle,char * id,char * them,char * me,ldl_user_flag_t flags)329 ldl_status ldl_session_create(ldl_session_t **session_p, ldl_handle_t *handle, char *id, char *them, char *me, ldl_user_flag_t flags)
330 {
331 	ldl_session_t *session = NULL;
332 
333 	if (!(session = apr_palloc(handle->pool, sizeof(ldl_session_t)))) {
334 		globals.logger(DL_LOG_CRIT, "Memory ERROR!\n");
335 		*session_p = NULL;
336 		return LDL_STATUS_MEMERR;
337 	}
338 	memset(session, 0, sizeof(ldl_session_t));
339 	apr_pool_create(&session->pool, globals.memory_pool);
340 	session->id = apr_pstrdup(session->pool, id);
341 	session->them = apr_pstrdup(session->pool, them);
342 
343 	if (flags & LDL_FLAG_OUTBOUND) {
344 		session->initiator = apr_pstrdup(session->pool, me);
345 	}
346 
347 	if (ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
348 		session->login = apr_pstrdup(session->pool, me);
349 	} else {
350 		session->login = apr_pstrdup(session->pool, handle->login);
351 	}
352 
353 	apr_hash_set(handle->sessions, session->id, APR_HASH_KEY_STRING, session);
354 	apr_hash_set(handle->sessions, session->them, APR_HASH_KEY_STRING, session);
355 	session->handle = handle;
356 	session->created = apr_time_now();
357 	session->state = LDL_STATE_NEW;
358 	session->variables = apr_hash_make(session->pool);
359 	session->flags = flags;
360 	*session_p = session;
361 
362 
363 	if (globals.debug) {
364 		globals.logger(DL_LOG_CRIT, "Created Session %s\n", id);
365 	}
366 
367 	return LDL_STATUS_SUCCESS;
368 }
369 
parse_session_code(ldl_handle_t * handle,char * id,char * from,char * to,iks * xml,char * xtype)370 static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, char *to, iks *xml, char *xtype)
371 {
372 	ldl_session_t *session = NULL;
373 	ldl_signal_t dl_signal = LDL_SIGNAL_NONE;
374 	char *initiator = iks_find_attrib(xml, "initiator");
375 	char *msg = NULL;
376 
377 	if (!(session = apr_hash_get(handle->sessions, id, APR_HASH_KEY_STRING))) {
378 		ldl_session_create(&session, handle, id, from, to, LDL_FLAG_NONE);
379 		if (!session) {
380 			return LDL_STATUS_MEMERR;
381 		}
382 	}
383 
384 	if (!session) {
385 		if (globals.debug) {
386 			globals.logger(DL_LOG_CRIT, "Non-Existent Session %s!\n", id);
387 		}
388 		return LDL_STATUS_MEMERR;
389 	}
390 
391 	if (globals.debug) {
392 		globals.logger(DL_LOG_CRIT, "Message for Session %s\n", id);
393 	}
394 
395 	while(xml) {
396 		char *type = NULL;
397 		iks *tag;
398 
399 		if (iks_type(xml) != IKS_CDATA) {
400 			type = xtype ? xtype : iks_find_attrib(xml, "type");
401 		}
402 
403 		if (type) {
404 
405 			if (!strcasecmp(type, "redirect")) {
406 				apr_hash_t *hash = session->handle->sessions;
407 				char *p = to;
408 				if ((p = strchr(to, ':'))) {
409 					p++;
410 				} else {
411 					p = to;
412 				}
413 
414 
415 				apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL);
416 				apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL);
417 				session->them = apr_pstrdup(session->pool, p);
418 				apr_hash_set(handle->sessions, session->them, APR_HASH_KEY_STRING, session);
419 				apr_hash_set(handle->sessions, session->id, APR_HASH_KEY_STRING, session);
420 
421 				dl_signal = LDL_SIGNAL_REDIRECT;
422 			} else if (!strcasecmp(type, "initiate") || !strcasecmp(type, "accept")) {
423 
424 				dl_signal = LDL_SIGNAL_INITIATE;
425 
426 				if (!strcasecmp(type, "accept")) {
427 					msg = "accept";
428 				}
429 				if (!session->initiator && initiator) {
430 					session->initiator = apr_pstrdup(session->pool, initiator);
431 				}
432 				tag = iks_child (xml);
433 
434 				while(tag) {
435 					if (!strcasecmp(iks_name_nons(tag), "description")) {
436 						iks * itag = iks_child (tag);
437 						while(itag) {
438 							if (!strcasecmp(iks_name_nons(itag), "payload-type") && session->payload_len < LDL_MAX_PAYLOADS) {
439 								char *name = iks_find_attrib(itag, "name");
440 								char *id = iks_find_attrib(itag, "id");
441 								char *rate = iks_find_attrib(itag, "clockrate");
442 								char *ptime = iks_find_attrib(itag, "ptime");
443 								if (name && id) {
444 									session->payloads[session->payload_len].name = apr_pstrdup(session->pool, name);
445 									session->payloads[session->payload_len].id = atoi(id);
446 									if (ptime) {
447 										session->payloads[session->payload_len].ptime = atoi(ptime);
448 									} else {
449 										session->payloads[session->payload_len].ptime = 20;
450 									}
451 									if (rate) {
452 										session->payloads[session->payload_len].rate = atoi(rate);
453 									} else {
454 										if (!strncasecmp(iks_name(itag), "vid", 3)) {
455 											session->payloads[session->payload_len].rate = 90000;
456 										} else {
457 											session->payloads[session->payload_len].rate = 8000;
458 										}
459                                     }
460 									session->payload_len++;
461 
462 									if (globals.debug) {
463 										globals.logger(DL_LOG_CRIT, "Add Payload [%s] id='%s'\n", name, id);
464 									}
465 								}
466 							}
467 							itag = iks_next_tag(itag);
468 						}
469 					}
470 					tag = iks_next_tag(tag);
471 				}
472 			} else if (!strcasecmp(type, "transport-accept")) {
473 				dl_signal = LDL_SIGNAL_TRANSPORT_ACCEPT;
474 			} else if (!strcasecmp(type, "reject")) {
475 				dl_signal = LDL_SIGNAL_REJECT;
476 			} else if (!strcasecmp(type, "transport-info") || !strcasecmp(type, "candidates")) {
477 				char *tid = iks_find_attrib(xml, "id");
478 				dl_signal = LDL_SIGNAL_CANDIDATES;
479 				tag = iks_child (xml);
480 				id = type;
481 				if (tag && !strcasecmp(iks_name_nons(tag), "transport")) {
482 					tag = iks_child(tag);
483 				}
484 
485 				for (;tag;tag = iks_next_tag(tag)) {
486 					if (!strcasecmp(iks_name_nons(tag), "info_element")) {
487 						char *name = iks_find_attrib(tag, "name");
488 						char *value = iks_find_attrib(tag, "value");
489 						if (globals.debug) {
490 							globals.logger(DL_LOG_CRIT, "Info Element [%s]=[%s]\n", name, value);
491 						}
492 						ldl_session_set_value(session, name, value);
493 
494 					} else if (!strcasecmp(iks_name_nons(tag), "candidate") /*&& session->candidate_len < LDL_MAX_CANDIDATES*/) {
495 						char *key;
496 						double pref = 0.0;
497 						int index = -1;
498 						ldl_transport_type_t tport;
499 						unsigned int *candidate_len = NULL;
500 						ldl_candidate_t (*candidates)[LDL_MAX_CANDIDATES] = NULL;
501 
502 						if (!(key = iks_find_attrib(tag, "preference"))) {
503 							globals.logger(DL_LOG_WARNING, "Field preference was not set\n");
504 							continue;
505 						} else {
506 							unsigned int x;
507 
508 							pref = strtod(key, NULL);
509 
510 							/* Check what kind of candidate this is */
511 							if ((key = iks_find_attrib(tag, "name")) && ((tport = ldl_transport_type_parse(key)) != LDL_TPORT_MAX)) {
512 								candidates = &(session->candidates[tport]);
513 								candidate_len = &(session->candidate_len[tport]);
514 							} else {
515 								globals.logger(DL_LOG_WARNING, "No such transport type: %s\n", key);
516 								continue;
517 							}
518 
519 							if (*candidate_len >= LDL_MAX_CANDIDATES) {
520 								globals.logger(DL_LOG_WARNING, "Too many %s candidates\n", key);
521 								continue;
522 							}
523 
524 							for (x = 0; x < *candidate_len; x++) {
525 								if ((*candidates)[x].pref == pref) {
526 									if (globals.debug) {
527 										globals.logger(DL_LOG_CRIT, "Duplicate Pref! Updating...\n");
528 									}
529 									index = x;
530 									break;
531 								}
532 							}
533 						}
534 
535 						if (index < 0) {
536 							index = (*candidate_len)++;
537 						}
538 
539 						(*candidates)[index].pref = pref;
540 
541 						if (tid) {
542 							(*candidates)[index].tid = apr_pstrdup(session->pool, tid);
543 						}
544 
545 						if ((key = iks_find_attrib(tag, "name"))) {
546 							(*candidates)[index].name = apr_pstrdup(session->pool, key);
547 						}
548 						if ((key = iks_find_attrib(tag, "type"))) {
549 							(*candidates)[index].type = apr_pstrdup(session->pool, key);
550 						}
551 						if ((key = iks_find_attrib(tag, "protocol"))) {
552 							(*candidates)[index].protocol = apr_pstrdup(session->pool, key);
553 						}
554 						if ((key = iks_find_attrib(tag, "username"))) {
555 							(*candidates)[index].username = apr_pstrdup(session->pool, key);
556 						}
557 						if ((key = iks_find_attrib(tag, "password"))) {
558 							(*candidates)[index].password = apr_pstrdup(session->pool, key);
559 						}
560 						if ((key = iks_find_attrib(tag, "address"))) {
561 							(*candidates)[index].address = apr_pstrdup(session->pool, key);
562 						}
563 						if ((key = iks_find_attrib(tag, "port"))) {
564 							(*candidates)[index].port = (uint16_t)atoi(key);
565 						}
566 
567 						if (!(*candidates)[index].type) {
568 							(*candidates)[index].type = apr_pstrdup(session->pool, "stun");
569 						}
570 
571 
572 						if (globals.debug) {
573 							globals.logger(DL_LOG_CRIT,
574 									"New Candidate %d\n"
575 									"name=%s\n"
576 									"type=%s\n"
577 									"protocol=%s\n"
578 									"username=%s\n"
579 									"password=%s\n"
580 									"address=%s\n"
581 									"port=%d\n"
582 									"pref=%0.2f\n",
583 									*candidate_len,
584 									(*candidates)[index].name,
585 									(*candidates)[index].type,
586 									(*candidates)[index].protocol,
587 									(*candidates)[index].username,
588 									(*candidates)[index].password,
589 									(*candidates)[index].address,
590 									(*candidates)[index].port,
591 									(*candidates)[index].pref
592 									);
593 						}
594 					}
595 				}
596 			} else if (!strcasecmp(type, "terminate")) {
597 				dl_signal = LDL_SIGNAL_TERMINATE;
598 			} else if (!strcasecmp(type, "error")) {
599 				dl_signal = LDL_SIGNAL_ERROR;
600 			}
601 		}
602 
603 		xml = iks_child(xml);
604 	}
605 
606 	if (handle->session_callback && dl_signal) {
607 		handle->session_callback(handle, session, dl_signal, to, from, id, msg);
608 	}
609 
610 	return LDL_STATUS_SUCCESS;
611 }
612 
613 
parse_jingle_code(ldl_handle_t * handle,iks * xml,char * to,char * from,char * type)614 static ldl_status parse_jingle_code(ldl_handle_t *handle, iks *xml, char *to, char *from, char *type)
615 {
616 	ldl_session_t *session = NULL;
617 	ldl_signal_t dl_signal = LDL_SIGNAL_NONE;
618 	char *initiator = iks_find_attrib(xml, "initiator");
619 	char *msg = NULL;
620 	char *id = iks_find_attrib(xml, "sid");
621 	char *action = iks_find_attrib(xml, "action");
622 	iks *tag;
623 
624 
625 	if (!strcasecmp(type, "error")) {
626 		action = type;
627 	}
628 
629 
630 	if (!(id && action && from)) {
631 		globals.logger(DL_LOG_CRIT, "missing required params\n");
632 		return LDL_STATUS_FALSE;
633 	}
634 
635 	if (!(session = apr_hash_get(handle->sessions, id, APR_HASH_KEY_STRING))) {
636 		ldl_session_create(&session, handle, id, from, to, LDL_FLAG_NONE);
637 		if (!session) {
638 			return LDL_STATUS_MEMERR;
639 		}
640 	}
641 
642 	if (!session) {
643 		if (globals.debug) {
644 			globals.logger(DL_LOG_CRIT, "Non-Existent Session %s!\n", id);
645 		}
646 		return LDL_STATUS_MEMERR;
647 	}
648 
649 	if (globals.debug) {
650 		globals.logger(DL_LOG_CRIT, "Message for Session %s\n", id);
651 	}
652 
653 
654 	if (action) {
655 
656 		if (!strcasecmp(action, "redirect")) {
657 			apr_hash_t *hash = session->handle->sessions;
658 			char *p = to;
659 			if ((p = strchr(to, ':'))) {
660 				p++;
661 			} else {
662 				p = to;
663 			}
664 
665 
666 			apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL);
667 			apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL);
668 			session->them = apr_pstrdup(session->pool, p);
669 			apr_hash_set(handle->sessions, session->them, APR_HASH_KEY_STRING, session);
670 			apr_hash_set(handle->sessions, session->id, APR_HASH_KEY_STRING, session);
671 
672 			dl_signal = LDL_SIGNAL_REDIRECT;
673 		} else if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "session-accept")) {
674 
675 			dl_signal = LDL_SIGNAL_INITIATE;
676 
677 			if (!strcasecmp(action, "session-accept")) {
678 				msg = "accept";
679 			}
680 
681 			if (!session->initiator && initiator) {
682 				session->initiator = apr_pstrdup(session->pool, initiator);
683 			}
684 			tag = iks_child (xml);
685 
686 			while(tag) {
687 
688 				if (!strcasecmp(iks_name_nons(tag), "content")) {
689 					iks *dtag = iks_child (tag);
690 					char key[512];
691 
692 					if (!strcasecmp(iks_name_nons(dtag), "description")) {
693 						iks *itag = iks_child (dtag);
694 						char *name = iks_find_attrib(tag, "name");
695 						char *media = iks_find_attrib(dtag, "media");
696 
697 						if (globals.debug) {
698 							globals.logger(DL_LOG_CRIT, "Found description of type '%s' media type '%s'\n", name, media);
699 
700 						}
701 
702 						while(itag) {
703 							if (!strcasecmp(iks_name_nons(itag), "rtcp-mux")) {
704 								snprintf(key, sizeof(key), "%s:rtcp-mux", media);
705 								ldl_session_set_value(session, key, "true");
706 							}
707 
708 							if (!strcasecmp(iks_name_nons(itag), "encryption")) {
709 								iks *etag = iks_child (itag);
710 
711 								while(etag) {
712 									char *suite = iks_find_attrib(etag, "crypto-suite");
713 									char *params = iks_find_attrib(etag, "key-params");
714 									char *tag = iks_find_attrib(etag, "tag");
715 									char val[512];
716 
717 									if (suite && params && tag) {
718 										snprintf(key, sizeof(key), "%s:crypto:%s", media, tag);
719 										snprintf(val, sizeof(val), "%s %s %s", tag, suite, params);
720 
721 										ldl_session_set_value(session, key, val);
722 									}
723 
724 									etag = iks_next_tag(etag);
725 								}
726 							}
727 
728 
729 							if (!strcasecmp(iks_name_nons(itag), "payload-type") && session->payload_len < LDL_MAX_PAYLOADS) {
730 								char *name = iks_find_attrib(itag, "name");
731 								char *id = iks_find_attrib(itag, "id");
732 								char *rate = iks_find_attrib(itag, "clockrate");
733 
734 								if (name && id) {
735 									session->payloads[session->payload_len].name = apr_pstrdup(session->pool, name);
736 									session->payloads[session->payload_len].id = atoi(id);
737 									if (rate) {
738 										session->payloads[session->payload_len].rate = atoi(rate);
739 									} else {
740 										if (!strcasecmp(media, "video")) {
741 											session->payloads[session->payload_len].rate = 90000;
742 										} else {
743 											session->payloads[session->payload_len].rate = 8000;
744 										}
745 									}
746 									session->payload_len++;
747 
748 									if (globals.debug) {
749 										globals.logger(DL_LOG_CRIT, "Add Payload [%s] id='%s'\n", name, id);
750 									}
751 								}
752 							}
753 							itag = iks_next_tag(itag);
754 						}
755 
756 					}
757 				}
758 
759 				tag = iks_next_tag(tag);
760 			}
761 		} else if (!strcasecmp(action, "transport-accept")) {
762 			dl_signal = LDL_SIGNAL_TRANSPORT_ACCEPT;
763 		} else if (!strcasecmp(action, "reject")) {
764 			dl_signal = LDL_SIGNAL_REJECT;
765 		} else if (!strcasecmp(action, "transport-info")) {
766 
767 			tag = iks_child (xml);
768 
769 			while(tag) {
770 
771 				if (!strcasecmp(iks_name_nons(tag), "content")) {
772 					iks *ttag = iks_child (tag);
773 
774 					dl_signal = LDL_SIGNAL_CANDIDATES;
775 
776 					id = action;
777 
778 					if (ttag && !strcasecmp(iks_name_nons(ttag), "transport")) {
779 						ttag = iks_child(ttag);
780 					}
781 
782 					for (;ttag;ttag = iks_next_tag(ttag)) {
783 						if (!strcasecmp(iks_name_nons(ttag), "info_element")) {
784 							char *name = iks_find_attrib(ttag, "name");
785 							char *value = iks_find_attrib(ttag, "value");
786 							if (globals.debug) {
787 								globals.logger(DL_LOG_CRIT, "Info Element [%s]=[%s]\n", name, value);
788 							}
789 							ldl_session_set_value(session, name, value);
790 
791 						} else if (!strcasecmp(iks_name_nons(ttag), "candidate")) {
792 							char *key;
793 							double pref = 0.0;
794 							int index = -1;
795 							ldl_transport_type_t tport;
796 							unsigned int *candidate_len = NULL;
797 							ldl_candidate_t (*candidates)[LDL_MAX_CANDIDATES] = NULL;
798 
799 							if ((key = iks_find_attrib(ttag, "preference"))) {
800 								unsigned int x;
801 
802 								pref = strtod(key, NULL);
803 
804 								/* Check what kind of candidate this is */
805 								if ((key = iks_find_attrib(ttag, "name")) && ((tport = ldl_transport_type_parse(key)) != LDL_TPORT_MAX)) {
806 									candidates = &(session->candidates[tport]);
807 									candidate_len = &(session->candidate_len[tport]);
808 								} else {
809 									globals.logger(DL_LOG_WARNING, "No such transport type: %s\n", key);
810 									continue;
811 								}
812 
813 								if (*candidate_len >= LDL_MAX_CANDIDATES) {
814 									globals.logger(DL_LOG_WARNING, "Too many %s candidates\n", key);
815 									continue;
816 								}
817 
818 								for (x = 0; x < *candidate_len; x++) {
819 									if ((*candidates)[x].pref == pref) {
820 										if (globals.debug) {
821 											globals.logger(DL_LOG_CRIT, "Duplicate Pref!\n");
822 										}
823 										index = x;
824 										break;
825 									}
826 								}
827 							} else {
828 								globals.logger(DL_LOG_WARNING, "No preference specified");
829 								continue;
830 							}
831 
832 							if (index < 0) {
833 								index = (*candidate_len)++;
834 							}
835 
836 							(*candidates)[index].pref = pref;
837 
838 							if ((key = iks_find_attrib(ttag, "name"))) {
839 								(*candidates)[index].name = apr_pstrdup(session->pool, key);
840 							}
841 							if ((key = iks_find_attrib(ttag, "type"))) {
842 								(*candidates)[index].type = apr_pstrdup(session->pool, key);
843 							}
844 							if ((key = iks_find_attrib(ttag, "protocol"))) {
845 								(*candidates)[index].protocol = apr_pstrdup(session->pool, key);
846 							}
847 							if ((key = iks_find_attrib(ttag, "username"))) {
848 								(*candidates)[index].username = apr_pstrdup(session->pool, key);
849 							}
850 							if ((key = iks_find_attrib(ttag, "password"))) {
851 								(*candidates)[index].password = apr_pstrdup(session->pool, key);
852 							}
853 							if ((key = iks_find_attrib(ttag, "address"))) {
854 								(*candidates)[index].address = apr_pstrdup(session->pool, key);
855 							}
856 							if ((key = iks_find_attrib(ttag, "port"))) {
857 								(*candidates)[index].port = (uint16_t)atoi(key);
858 							}
859 
860 							if (!(*candidates)[index].type) {
861 								(*candidates)[index].type = apr_pstrdup(session->pool, "stun");
862 							}
863 
864 
865 							if (globals.debug) {
866 								globals.logger(DL_LOG_CRIT,
867 											   "New Candidate %d\n"
868 											   "name=%s\n"
869 											   "type=%s\n"
870 											   "protocol=%s\n"
871 											   "username=%s\n"
872 											   "password=%s\n"
873 											   "address=%s\n"
874 											   "port=%d\n"
875 											   "pref=%0.2f\n",
876 											   *candidate_len,
877 											   (*candidates)[index].name,
878 											   (*candidates)[index].type,
879 											   (*candidates)[index].protocol,
880 											   (*candidates)[index].username,
881 											   (*candidates)[index].password,
882 											   (*candidates)[index].address,
883 											   (*candidates)[index].port,
884 											   (*candidates)[index].pref
885 											   );
886 							}
887 						}
888 					}
889 				}
890 
891 				tag = iks_next_tag(tag);
892 			}
893 		} else if (!strcasecmp(action, "session-terminate")) {
894 			dl_signal = LDL_SIGNAL_TERMINATE;
895 		} else if (!strcasecmp(action, "error")) {
896 			dl_signal = LDL_SIGNAL_ERROR;
897 		}
898 	}
899 
900 
901 
902 	if (handle->session_callback && dl_signal) {
903 		handle->session_callback(handle, session, dl_signal, to, from, id, msg);
904 	}
905 
906 	return LDL_STATUS_SUCCESS;
907 }
908 
909 
910 
911 const char *marker = "TRUE";
912 
913 
on_vcard(void * user_data,ikspak * pak)914 static int on_vcard(void *user_data, ikspak *pak)
915 {
916 	ldl_handle_t *handle = user_data;
917 	char *from = iks_find_attrib(pak->x, "from");
918 	char *to = iks_find_attrib(pak->x, "to");
919 
920 	if (handle->session_callback) {
921 		handle->session_callback(handle, NULL, LDL_SIGNAL_VCARD, to, from, pak->id, NULL);
922 	}
923 
924 	return IKS_FILTER_EAT;
925 }
926 
927 
on_disco_default(void * user_data,ikspak * pak)928 static int on_disco_default(void *user_data, ikspak *pak)
929 {
930 	char *node = NULL;
931 	char *ns = NULL;
932 	ldl_handle_t *handle = user_data;
933 	iks *iq = NULL, *query, *tag;
934 	uint8_t send = 0;
935 	int x;
936 
937 	if (pak && pak->query) {
938 		ns = iks_find_attrib(pak->query, "xmlns");
939 		node = iks_find_attrib(pak->query, "node");
940 	}
941 
942 	if (pak && pak->subtype == IKS_TYPE_RESULT) {
943 		globals.logger(DL_LOG_CRIT, "FixME!!! node=[%s]\n", node?node:"");
944 	} else if (pak && pak->subtype == IKS_TYPE_GET) {
945 		if (ns && (iq = iks_new("iq"))) {
946 			int all = 0;
947 
948 			iks_insert_attrib(iq, "from", handle->login);
949 			if (pak->from) {
950 				iks_insert_attrib(iq, "to", pak->from->full);
951 			}
952 			iks_insert_attrib(iq, "id", pak->id);
953 			iks_insert_attrib(iq, "type", "result");
954 
955 			if (!(query = iks_insert (iq, "query"))) {
956 				goto fail;
957 			}
958 			iks_insert_attrib(query, "xmlns", ns);
959 
960 			if (!strcasecmp(ns, FEATURE_LAST)) {
961 				iks_insert_attrib(query, "seconds", "1");
962 			}
963 
964 			if (!(tag = iks_insert (query, "identity"))) {
965 				goto fail;
966 			}
967 
968 			iks_insert_attrib(tag, "category", "gateway");
969 			//iks_insert_attrib(tag, "type", "voice");
970 			iks_insert_attrib(tag, "name", "LibDingaLing");
971 
972 			if (!strcasecmp(ns, FEATURE_DISCO_INFO)) {
973 				if (!node) {
974 					all++;
975 				} else {
976 					char *p;
977 
978 					if ((p = strstr(node, "caps#"))) {
979 						char *what = p + 5;
980 
981 						if (!strcasecmp(what, "voice-v1")) {
982 							if (!(tag = iks_insert (query, "feature"))) {
983 								goto fail;
984 							}
985 							iks_insert_attrib(tag, "var", FEATURE_VOICE);
986 							goto done;
987 						}
988 
989 					}
990 				}
991 			}
992 
993 			for (x = 0; FEATURES[x].name; x++) {
994 				if (all || !ns || !strcasecmp(ns, FEATURES[x].name)) {
995 					if (!(tag = iks_insert (query, "feature"))) {
996 						goto fail;
997 					}
998 					iks_insert_attrib(tag, "var", FEATURES[x].name);
999 				}
1000 			}
1001 
1002 		done:
1003 
1004 			apr_queue_push(handle->queue, iq);
1005 			iq = NULL;
1006 			send = 1;
1007 		}
1008 	fail:
1009 
1010 		if (iq) {
1011 			iks_delete(iq);
1012 		}
1013 
1014 		if (!send) {
1015 			globals.logger(DL_LOG_CRIT, "Memory Error!\n");
1016 		}
1017 	}
1018 
1019 	return IKS_FILTER_EAT;
1020 }
1021 
on_presence(void * user_data,ikspak * pak)1022 static int on_presence(void *user_data, ikspak *pak)
1023 {
1024 	ldl_handle_t *handle = user_data;
1025 	char *from = iks_find_attrib(pak->x, "from");
1026 	char *to = iks_find_attrib(pak->x, "to");
1027 	char *type = iks_find_attrib(pak->x, "type");
1028 	char *show = iks_find_cdata(pak->x, "show");
1029 	char *status = iks_find_cdata(pak->x, "status");
1030 	char id[1024];
1031 	char *resource;
1032 	struct ldl_buffer *buffer;
1033 	ldl_signal_t dl_signal = LDL_SIGNAL_PRESENCE_IN;
1034 	int done = 0;
1035 
1036 
1037     if (type && *type) {
1038         if (!strcasecmp(type, "unavailable")) {
1039             dl_signal = LDL_SIGNAL_PRESENCE_OUT;
1040         } else if (!strcasecmp(type, "probe")) {
1041             dl_signal = LDL_SIGNAL_PRESENCE_PROBE;
1042         }
1043         if (!status) {
1044             status = type;
1045         }
1046     } else {
1047         if (!status) {
1048             status = "Available";
1049         }
1050     }
1051 
1052 
1053 	apr_cpystrn(id, from, sizeof(id));
1054 	lowercase(id);
1055 
1056 	if ((resource = strchr(id, '/'))) {
1057 		*resource++ = '\0';
1058 	}
1059 
1060 
1061 	if (!apr_hash_get(handle->sub_hash, from, APR_HASH_KEY_STRING)) {
1062 		iks *msg;
1063 		apr_hash_set(handle->sub_hash, 	apr_pstrdup(handle->pool, from), APR_HASH_KEY_STRING, &marker);
1064 		if ((msg = iks_make_s10n (IKS_TYPE_SUBSCRIBED, id, "Ding A Ling...."))) {
1065 			apr_queue_push(handle->queue, msg);
1066 			msg = NULL;
1067 		}
1068 	}
1069 
1070 	if (resource && (strstr(resource, "talk") || strstr(resource, "telepathy")) && (buffer = apr_hash_get(handle->probe_hash, id, APR_HASH_KEY_STRING))) {
1071 		apr_cpystrn(buffer->buf, from, buffer->len);
1072 		buffer->hit = 1;
1073 		done = 1;
1074 	}
1075 
1076 	if (!done) {
1077 		iks *xml = iks_find(pak->x, "c");
1078 		if (!xml) {
1079 			xml = iks_find(pak->x, "caps:c");
1080 		}
1081 
1082 		if (xml) {
1083 			char *ext = iks_find_attrib(xml, "ext");;
1084 			if (ext && strstr(ext, "voice-v1") && (buffer = apr_hash_get(handle->probe_hash, id, APR_HASH_KEY_STRING))) {
1085 				apr_cpystrn(buffer->buf, from, buffer->len);
1086 				buffer->hit = 1;
1087 			}
1088 		}
1089 	}
1090 
1091 
1092     if (handle->session_callback) {
1093         handle->session_callback(handle, NULL, dl_signal, to, id, status ? status : "n/a", show ? show : "n/a");
1094     }
1095 
1096 	return IKS_FILTER_EAT;
1097 }
1098 
ldl_handle_strdup(ldl_handle_t * handle,char * str)1099 static char *ldl_handle_strdup(ldl_handle_t *handle, char *str)
1100 {
1101 	char *dup;
1102 	apr_size_t len;
1103 
1104 	len = strlen(str) + 1;
1105 	dup = apr_palloc(handle->pool, len);
1106 	assert(dup != NULL);
1107 	strncpy(dup, str, len);
1108 	return dup;
1109 }
1110 
ldl_strip_resource(char * in)1111 static void ldl_strip_resource(char *in)
1112 {
1113 	char *p;
1114 
1115 	if ((p = strchr(in, '/'))) {
1116 		*p = '\0';
1117 	}
1118 }
1119 
ldl_get_avatar(ldl_handle_t * handle,char * path,char * from)1120 static ldl_avatar_t *ldl_get_avatar(ldl_handle_t *handle, char *path, char *from)
1121 {
1122 	ldl_avatar_t *ap;
1123 	uint8_t image[8192];
1124 	unsigned char base64[9216] = "";
1125 	int fd = -1;
1126 	size_t bytes;
1127 	char *key;
1128 	//char hash[128] = "";
1129 
1130 	if (from && (ap = (ldl_avatar_t *) apr_hash_get(globals.avatar_hash, from, APR_HASH_KEY_STRING))) {
1131 		return ap;
1132 	}
1133 
1134 	if (path && from) {
1135 		if ((ap = (ldl_avatar_t *) apr_hash_get(globals.avatar_hash, path, APR_HASH_KEY_STRING))) {
1136 			key = ldl_handle_strdup(handle, from);
1137 			ldl_strip_resource(key);
1138 			apr_hash_set(globals.avatar_hash, key, APR_HASH_KEY_STRING, ap);
1139 			return ap;
1140 		}
1141 	}
1142 
1143 	if (!(path && from)) {
1144 		return NULL;
1145 	}
1146 
1147 	if ((fd = open(path, O_RDONLY, 0)) < 0) {
1148 		globals.logger(DL_LOG_ERR, "File %s does not exist!\n", path);
1149 		return NULL;
1150 	}
1151 
1152 	bytes = read(fd, image, sizeof(image));
1153 	close(fd);
1154 
1155 	ap = malloc(sizeof(*ap));
1156 	assert(ap != NULL);
1157 	memset(ap, 0, sizeof(*ap));
1158 	sha1_hash(ap->hash, (unsigned char *) image, (unsigned int)bytes);
1159 	ap->path = strdup(path);
1160 
1161 	key = ldl_handle_strdup(handle, from);
1162 	ldl_strip_resource(key);
1163 
1164 	b64encode((unsigned char *)image, bytes, base64, sizeof(base64));
1165 	ap->base64 = strdup((const char *)base64);
1166 	apr_hash_set(globals.avatar_hash, ap->path, APR_HASH_KEY_STRING, ap);
1167 	apr_hash_set(globals.avatar_hash, key, APR_HASH_KEY_STRING, ap);
1168 	return ap;
1169 }
1170 
1171 
do_presence(ldl_handle_t * handle,char * from,char * to,char * type,char * rpid,char * message,char * avatar)1172 static void do_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *rpid, char *message, char *avatar)
1173 {
1174 	iks *pres;
1175 	char buf[512];
1176 	iks *tag;
1177 
1178 	if (from && !strchr(from, '/')) {
1179 		snprintf(buf, sizeof(buf), "%s/talk", from);
1180 		from = buf;
1181 	}
1182 
1183 	if (ldl_test_flag(handle, LDL_FLAG_COMPONENT) && from && to && ldl_jid_domcmp(from, to)) {
1184 		globals.logger(DL_LOG_ERR, "Refusal to send presence from and to the same domain in component mode [%s][%s]\n", from, to);
1185 		return;
1186 	}
1187 
1188 	if ((pres = iks_new("presence"))) {
1189 		iks_insert_attrib(pres, "xmlns", "jabber:client");
1190 		if (from) {
1191 			iks_insert_attrib(pres, "from", from);
1192 		}
1193 		if (to) {
1194 			iks_insert_attrib(pres, "to", to);
1195 		}
1196 		if (type) {
1197 			iks_insert_attrib(pres, "type", type);
1198 		}
1199 
1200 		if (rpid) {
1201 			if ((tag = iks_insert (pres, "show"))) {
1202 				iks_insert_cdata(tag, rpid, 0);
1203 			}
1204 		}
1205 
1206 		if (message) {
1207 			if ((tag = iks_insert (pres, "status"))) {
1208 				iks_insert_cdata(tag, message, 0);
1209 			}
1210 		}
1211 
1212 		if (message || rpid) {
1213 			ldl_avatar_t *ap;
1214 
1215 			if (avatar) {
1216 				if ((ap = ldl_get_avatar(handle, avatar, from))) {
1217 					if ((tag = iks_insert(pres, "x"))) {
1218 						iks *hash;
1219 						iks_insert_attrib(tag, "xmlns", "vcard-temp:x:update");
1220 						if ((hash = iks_insert(tag, "photo"))) {
1221 							iks_insert_cdata(hash, ap->hash, 0);
1222 						}
1223 					}
1224 				}
1225 			}
1226 
1227 			if ((tag = iks_insert(pres, "c"))) {
1228 				iks_insert_attrib(tag, "node", "http://www.freeswitch.org/xmpp/client/caps");
1229 				iks_insert_attrib(tag, "ver", LDL_CAPS_VER);
1230 				iks_insert_attrib(tag, "ext", "sidebar voice-v1 video-v1 camera-v1");
1231 				iks_insert_attrib(tag, "client", "libdingaling");
1232 				iks_insert_attrib(tag, "xmlns", "http://jabber.org/protocol/caps");
1233 			}
1234 		}
1235 
1236 		apr_queue_push(handle->queue, pres);
1237 		pres = NULL;
1238 	}
1239 }
1240 
do_roster(ldl_handle_t * handle)1241 static void do_roster(ldl_handle_t *handle)
1242 {
1243 	if (handle->session_callback) {
1244         handle->session_callback(handle, NULL, LDL_SIGNAL_ROSTER, NULL, handle->login, NULL, NULL);
1245     }
1246 }
1247 
on_unsubscribe(void * user_data,ikspak * pak)1248 static int on_unsubscribe(void *user_data, ikspak *pak)
1249 {
1250 	ldl_handle_t *handle = user_data;
1251 	char *from = iks_find_attrib(pak->x, "from");
1252 	char *to = iks_find_attrib(pak->x, "to");
1253 
1254 	if (handle->session_callback) {
1255 		handle->session_callback(handle, NULL, LDL_SIGNAL_UNSUBSCRIBE, to, from, NULL, NULL);
1256 	}
1257 
1258 	return IKS_FILTER_EAT;
1259 }
1260 
on_subscribe(void * user_data,ikspak * pak)1261 static int on_subscribe(void *user_data, ikspak *pak)
1262 {
1263 	ldl_handle_t *handle = user_data;
1264 	char *from = iks_find_attrib(pak->x, "from");
1265 	char *to = iks_find_attrib(pak->x, "to");
1266 	iks *msg = NULL;
1267 	char *id = strdup(from);
1268 	char *r;
1269 
1270 	if (!id) {
1271 		return -1;
1272 	}
1273 	if ((r = strchr(from, '/'))) {
1274 		*r++ = '\0';
1275 	}
1276 
1277 	if ((msg = iks_make_s10n (IKS_TYPE_SUBSCRIBED, id, "Ding A Ling...."))) {
1278 		if (to && ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
1279 			iks_insert_attrib(msg, "from", to);
1280 		}
1281 
1282 		apr_queue_push(handle->queue, msg);
1283 		msg = NULL;
1284 	}
1285 
1286 	if ((msg = iks_make_s10n (IKS_TYPE_SUBSCRIBE, id, "Ding A Ling...."))) {
1287 
1288 		if (to && ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
1289 			iks_insert_attrib(msg, "from", to);
1290 		}
1291 
1292 		apr_queue_push(handle->queue, msg);
1293 		msg = NULL;
1294 	}
1295 
1296 	if (handle->session_callback) {
1297 		handle->session_callback(handle, NULL, LDL_SIGNAL_SUBSCRIBE, to, from, NULL, NULL);
1298 	}
1299 
1300 	return IKS_FILTER_EAT;
1301 }
1302 
cancel_retry(ldl_handle_t * handle,char * id)1303 static void cancel_retry(ldl_handle_t *handle, char *id)
1304 {
1305 	struct packet_node *packet_node;
1306 
1307 	apr_thread_mutex_lock(handle->lock);
1308 	if ((packet_node = apr_hash_get(handle->retry_hash, id, APR_HASH_KEY_STRING))) {
1309 		if (globals.debug) {
1310 			globals.logger(DL_LOG_CRIT, "Cancel packet %s\n", packet_node->id);
1311 		}
1312 		packet_node->retries = 0;
1313 	}
1314 	apr_thread_mutex_unlock(handle->lock);
1315 }
1316 
working_find(iks * tag,const char * name)1317 static iks* working_find(iks *tag, const char *name)
1318 {
1319 	while(tag) {
1320 		if (!strcasecmp(iks_name(tag), name)) {
1321 			return tag;
1322 		}
1323 		tag = iks_next_tag(tag);
1324 	}
1325 
1326 	return NULL;
1327 }
1328 
working_find_nons(iks * tag,const char * name)1329 static iks* working_find_nons(iks *tag, const char *name)
1330 {
1331 	while(tag) {
1332 		char *a = iks_name(tag);
1333 		char *b = (char *)name;
1334 		char *p;
1335 
1336 		if ((p = strchr(a, ':'))) {
1337 			a = p+1;
1338 		}
1339 
1340 		if ((p = strchr(b, ':'))) {
1341 			b = p+1;
1342 		}
1343 
1344 		if (!strcasecmp(a,b)) {
1345 			return tag;
1346 		}
1347 		tag = iks_next_tag(tag);
1348 	}
1349 
1350 	return NULL;
1351 }
1352 
on_commands(void * user_data,ikspak * pak)1353 static int on_commands(void *user_data, ikspak *pak)
1354 {
1355 	ldl_handle_t *handle = user_data;
1356 	char *from = iks_find_attrib(pak->x, "from");
1357 	char *to = iks_find_attrib(pak->x, "to");
1358 	char *iqid = iks_find_attrib(pak->x, "id");
1359 	char *type = iks_find_attrib(pak->x, "type");
1360 	uint8_t is_result = strcasecmp(type, "result") ? 0 : 1;
1361 	uint8_t is_error = strcasecmp(type, "error") ? 0 : 1;
1362 	iks *xml, *xsession, *xerror = NULL, *xredir = NULL;
1363 	iks *xjingle;
1364 
1365 
1366 	xml = iks_child (pak->x);
1367 
1368 	if (is_error) {
1369 		if ((xerror = working_find(xml, "error"))) {
1370 			char *code = iks_find_attrib(xerror, "code");
1371 			if (code && !strcmp(code, "302") &&
1372 				((xredir = iks_find(xerror, "ses:redirect")) || (xredir = iks_find(xerror, "redirect")))) {
1373 				is_result = 0;
1374 				is_error = 0;
1375 				cancel_retry(handle, iqid);
1376 			}
1377 		}
1378 	}
1379 
1380 
1381 	if (is_result) {
1382 		iks *tag = iks_child (pak->x);
1383 		while(tag) {
1384 			if (!strcasecmp(iks_name_nons(tag), "bind")) {
1385 				char *jid = iks_find_cdata(tag, "jid");
1386 				char *resource = strchr(jid, '/');
1387 				if (resource) {
1388 					resource++;
1389 					handle->acc->resource = apr_pstrdup(handle->pool, resource);
1390 				}
1391 				handle->login = apr_pstrdup(handle->pool, jid);
1392 #if 0
1393 				if ((iq = iks_new("iq"))) {
1394 					iks_insert_attrib(iq, "type", "get");
1395 					iks_insert_attrib(iq, "id", "roster");
1396 					x = iks_insert(iq,  "query");
1397 					iks_insert_attrib(x, "xmlns", "jabber:iq:roster");
1398 					iks_insert_attrib(x, "xmlns:gr", "google:roster");
1399 					iks_insert_attrib(x, "gr:ext", "2");
1400 					iks_insert_attrib(x, "gr:include", "all");
1401 					apr_queue_push(handle->queue, iq);
1402 					iq = NULL;
1403 					break;
1404 				}
1405 #endif
1406 			}
1407 			tag = iks_next_tag(tag);
1408 		}
1409 	}
1410 
1411 
1412 
1413 	if ((is_result || is_error) && iqid && from) {
1414 
1415 		cancel_retry(handle, iqid);
1416 
1417 		if (is_result) {
1418 			if (handle->response_callback) {
1419 				handle->response_callback(handle, iqid);
1420 			}
1421 			return IKS_FILTER_EAT;
1422 		} else if (is_error) {
1423 			return IKS_FILTER_EAT;
1424 
1425 		}
1426 	}
1427 
1428 
1429 
1430 	if ((handle->flags & LDL_FLAG_JINGLE) && (xjingle = working_find_nons(xml, "jin:jingle"))) {
1431 		if (parse_jingle_code(handle, xjingle, to, from, type) == LDL_STATUS_SUCCESS) {
1432 			iks *reply;
1433 			if ((reply = iks_make_iq(IKS_TYPE_RESULT, NULL))) {
1434 				iks_insert_attrib(reply, "to", from);
1435 				iks_insert_attrib(reply, "from", to);
1436 				iks_insert_attrib(reply, "id", iqid);
1437 				apr_queue_push(handle->queue, reply);
1438 				reply = NULL;
1439 			}
1440 		}
1441 
1442 	} else if ((xsession = working_find_nons(xml, "ses:session"))) {
1443 		char *id;
1444 
1445 		id = iks_find_attrib(xsession, "id");
1446 
1447 		if (xredir) {
1448 			to = iks_cdata(iks_child(xredir));
1449 			type = "redirect";
1450 		}
1451 
1452 		if (strcasecmp(type, "error") && strcasecmp(type, "redirect")) {
1453 			type = NULL;
1454 		}
1455 
1456 		if (parse_session_code(handle, id, from, to, xsession, type) == LDL_STATUS_SUCCESS) {
1457 			iks *reply;
1458 			if ((reply = iks_make_iq(IKS_TYPE_RESULT, NULL))) {
1459 				iks_insert_attrib(reply, "to", from);
1460 				iks_insert_attrib(reply, "from", to);
1461 				iks_insert_attrib(reply, "id", iqid);
1462 				apr_queue_push(handle->queue, reply);
1463 				reply = NULL;
1464 			}
1465 		}
1466 	}
1467 
1468 	return IKS_FILTER_EAT;
1469 }
1470 
1471 
on_result(void * user_data,ikspak * pak)1472 static int on_result(void *user_data, ikspak *pak)
1473 {
1474 	ldl_handle_t *handle = user_data;
1475 	iks *msg, *ctag, *tag;
1476 
1477 	if ((msg = iks_make_pres (IKS_SHOW_AVAILABLE, handle->status_msg))) {
1478 		ctag = iks_insert(msg, "c");
1479 		iks_insert_attrib(ctag, "node", "http://www.freeswitch.org/xmpp/client/caps");
1480 		iks_insert_attrib(ctag, "ver", "1.0.0.1");
1481 		iks_insert_attrib(ctag, "ext", "sidebar voice-v1 video-v1");
1482 		iks_insert_attrib(ctag, "client", "libdingaling");
1483 		iks_insert_attrib(ctag, "xmlns", "http://jabber.org/protocol/caps");
1484 
1485 		if (handle->priority && strlen(handle->priority)) {
1486 			tag = iks_insert (msg, "priority");
1487 			iks_insert_cdata(tag, handle->priority, 0);
1488 		}
1489 
1490 		apr_queue_push(handle->queue, msg);
1491 		msg = NULL;
1492 	}
1493 	return IKS_FILTER_EAT;
1494 }
1495 
1496 static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1497 #define B64BUFFLEN 1024
1498 
b64encode(unsigned char * in,size_t ilen,unsigned char * out,size_t olen)1499 static int b64encode(unsigned char *in, size_t ilen, unsigned char *out, size_t olen)
1500 {
1501 	int y=0,bytes=0;
1502 	size_t x=0;
1503 	unsigned int b=0,l=0;
1504 
1505 	for(x=0;x<ilen;x++) {
1506 		b = (b<<8) + in[x];
1507 		l += 8;
1508 		while (l >= 6) {
1509 			out[bytes++] = c64[(b>>(l-=6))%64];
1510 			if(++y!=72) {
1511 				continue;
1512 			}
1513 			//out[bytes++] = '\n';
1514 			y=0;
1515 		}
1516 	}
1517 
1518 	if (l > 0) {
1519 		out[bytes++] = c64[((b%16)<<(6-l))%64];
1520 	}
1521 	if (l != 0) while (l < 6) {
1522 		out[bytes++] = '=', l += 2;
1523 	}
1524 
1525 	return 0;
1526 }
1527 
sha1_hash(char * out,unsigned char * in,unsigned int len)1528 static void sha1_hash(char *out, unsigned char *in, unsigned int len)
1529 {
1530 	SHA1Context sha;
1531 	char *p;
1532 	int x;
1533 	unsigned char digest[SHA1_HASH_SIZE] = "";
1534 
1535 	SHA1Init(&sha);
1536 
1537 	SHA1Update(&sha, in, len);
1538 
1539 	SHA1Final(&sha, digest);
1540 
1541 	p = out;
1542 	for (x = 0; x < SHA1_HASH_SIZE; x++) {
1543 		p += sprintf(p, "%2.2x", digest[x]);
1544 	}
1545 }
1546 
1547 
on_stream_component(ldl_handle_t * handle,int type,iks * node)1548 static int on_stream_component(ldl_handle_t *handle, int type, iks *node)
1549 {
1550 	ikspak *pak = NULL;
1551 
1552     if (node) {
1553         pak = iks_packet(node);
1554     }
1555 
1556 	switch (type) {
1557 	case IKS_NODE_START:
1558 		if (pak && handle->state == CS_NEW) {
1559 			char secret[256] = "";
1560 			char hash[256] = "";
1561 			char handshake[512] = "";
1562 
1563 			snprintf(secret, sizeof(secret), "%s%s", pak->id, handle->password);
1564 			sha1_hash(hash, (unsigned char *) secret, (unsigned int)strlen(secret));
1565 			snprintf(handshake, sizeof(handshake), "<handshake>%s</handshake>", hash);
1566 			iks_send_raw(handle->parser, handshake);
1567 			handle->state = CS_START;
1568 			if (iks_recv(handle->parser, 1) == 2) {
1569 				handle->state = CS_CONNECTED;
1570 				if (!ldl_test_flag(handle, LDL_FLAG_AUTHORIZED)) {
1571 					do_roster(handle);
1572 					if (handle->session_callback) {
1573 						handle->session_callback(handle, NULL, LDL_SIGNAL_LOGIN_SUCCESS, "user", "core", "Login Success", handle->login);
1574 					}
1575 					globals.logger(DL_LOG_DEBUG, "XMPP authenticated\n");
1576 					ldl_set_flag_locked(handle, LDL_FLAG_AUTHORIZED);
1577 					ldl_set_flag_locked(handle, LDL_FLAG_CONNECTED);
1578 					handle->fail_count = 0;
1579 				}
1580 			} else {
1581 				globals.logger(DL_LOG_ERR, "LOGIN ERROR!\n");
1582 				handle->state = CS_NEW;
1583 			}
1584 			break;
1585 		}
1586 		break;
1587 
1588 	case IKS_NODE_NORMAL:
1589 		break;
1590 
1591 	case IKS_NODE_ERROR:
1592 		globals.logger(DL_LOG_ERR, "NODE ERROR!\n");
1593 		return IKS_HOOK;
1594 
1595 	case IKS_NODE_STOP:
1596 		globals.logger(DL_LOG_ERR, "DISCONNECTED!\n");
1597 		return IKS_HOOK;
1598 	}
1599 
1600     iks_filter_packet(handle->filter, pak);
1601 
1602 	if (handle->job_done == 1) {
1603 		return IKS_HOOK;
1604 	}
1605 
1606 	if (node) {
1607         iks_delete(node);
1608 	}
1609 
1610 	return IKS_OK;
1611 }
1612 
on_stream(ldl_handle_t * handle,int type,iks * node)1613 static int on_stream(ldl_handle_t *handle, int type, iks *node)
1614 {
1615 	handle->counter = opt_timeout;
1616 
1617 
1618     switch (type) {
1619 	case IKS_NODE_START:
1620 		if (ldl_test_flag(handle, LDL_FLAG_TLS) && !iks_is_secure(handle->parser)) {
1621 			if (iks_has_tls()) {
1622 				iks_start_tls(handle->parser);
1623 			} else {
1624 				globals.logger(DL_LOG_WARNING, "TLS NOT SUPPORTED IN THIS BUILD!\n");
1625 			}
1626 		}
1627 		break;
1628 	case IKS_NODE_NORMAL:
1629         if (node && strcmp("stream:features", iks_name(node)) == 0) {
1630 			handle->features = iks_stream_features(node);
1631 			if (ldl_test_flag(handle, LDL_FLAG_TLS) && !iks_is_secure(handle->parser))
1632 				break;
1633 			if (ldl_test_flag(handle, LDL_FLAG_CONNECTED)) {
1634 				iks *t;
1635 				if (handle->features & IKS_STREAM_BIND) {
1636 					if ((t = iks_make_resource_bind(handle->acc))) {
1637 						apr_queue_push(handle->queue, t);
1638 						t = NULL;
1639 					}
1640 				}
1641 				if (handle->features & IKS_STREAM_SESSION) {
1642 					if ((t = iks_make_session())) {
1643 						iks_insert_attrib(t, "id", "auth");
1644 						apr_queue_push(handle->queue, t);
1645 						t = NULL;
1646 					}
1647 				}
1648 			} else {
1649 				if (handle->features & IKS_STREAM_SASL_MD5) {
1650 					iks_start_sasl(handle->parser, IKS_SASL_DIGEST_MD5, handle->acc->user, handle->password);
1651 				} else if (handle->features & IKS_STREAM_SASL_PLAIN) {
1652 					iks *x = NULL;
1653 
1654 					if ((x = iks_new("auth"))) {
1655 						char s[512] = "";
1656 						char base64[1024] = "";
1657 						uint32_t slen;
1658 
1659 						iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_SASL);
1660 						iks_insert_attrib(x, "mechanism", "PLAIN");
1661 						iks_insert_attrib(x, "encoding", "UTF-8");
1662 						snprintf(s, sizeof(s), "%c%s%c%s", 0, handle->acc->user, 0, handle->password);
1663 						slen = (uint32_t)(strlen(handle->acc->user) + strlen(handle->password) + 2);
1664 						b64encode((unsigned char *)s, slen, (unsigned char *) base64, sizeof(base64));
1665 						iks_insert_cdata(x, base64, 0);
1666 						apr_queue_push(handle->queue, x);
1667 						x = NULL;
1668 					} else {
1669 						globals.logger(DL_LOG_CRIT, "Memory ERROR!\n");
1670 						break;
1671 					}
1672 
1673 				}
1674 			}
1675 		} else if (node && strcmp("failure", iks_name_nons(node)) == 0) {
1676 			globals.logger(DL_LOG_CRIT, "sasl authentication failed\n");
1677 			if (handle->session_callback) {
1678 				handle->session_callback(handle, NULL, LDL_SIGNAL_LOGIN_FAILURE, "user", "core", "Login Failure", handle->login);
1679 			}
1680 		} else if (node && strcmp("success", iks_name_nons(node)) == 0) {
1681 			globals.logger(DL_LOG_NOTICE, "XMPP server connected\n");
1682 			iks_send_header(handle->parser, handle->acc->server);
1683 			ldl_set_flag_locked(handle, LDL_FLAG_CONNECTED);
1684 			if (handle->session_callback) {
1685 				handle->session_callback(handle, NULL, LDL_SIGNAL_CONNECTED, "user", "core", "Server Connected", handle->login);
1686 			}
1687 		} else {
1688 			ikspak *pak;
1689 			if (!ldl_test_flag(handle, LDL_FLAG_AUTHORIZED)) {
1690 				if (handle->session_callback) {
1691 					handle->session_callback(handle, NULL, LDL_SIGNAL_LOGIN_SUCCESS, "user", "core", "Login Success", handle->login);
1692 				}
1693 				globals.logger(DL_LOG_NOTICE, "XMPP authenticated\n");
1694 				ldl_set_flag_locked(handle, LDL_FLAG_AUTHORIZED);
1695 			}
1696             if (node) {
1697                 pak = iks_packet(node);
1698                 iks_filter_packet(handle->filter, pak);
1699             }
1700 			if (handle->job_done == 1) {
1701 				return IKS_HOOK;
1702 			}
1703 		}
1704 		break;
1705 #if 0
1706 	case IKS_NODE_STOP:
1707 		globals.logger(DL_LOG_DEBUG, "server disconnected\n");
1708 		break;
1709 
1710 	case IKS_NODE_ERROR:
1711 		globals.logger(DL_LOG_DEBUG, "stream error\n");
1712 		break;
1713 #endif
1714 
1715 	}
1716 
1717 	if (node) {
1718 		iks_delete(node);
1719     }
1720 	return IKS_OK;
1721 }
1722 
on_msg(void * user_data,ikspak * pak)1723 static int on_msg(void *user_data, ikspak *pak)
1724 {
1725 	char *cmd = iks_find_cdata(pak->x, "body");
1726 	char *to = iks_find_attrib(pak->x, "to");
1727 	char *from = iks_find_attrib(pak->x, "from");
1728 	char *subject = iks_find_attrib(pak->x, "subject");
1729 	ldl_handle_t *handle = user_data;
1730 	ldl_session_t *session = NULL;
1731 
1732 	if (from) {
1733 		session = apr_hash_get(handle->sessions, from, APR_HASH_KEY_STRING);
1734 	}
1735 
1736 	if (handle->session_callback) {
1737 		handle->session_callback(handle, session, LDL_SIGNAL_MSG, to, from, subject ? subject : "N/A", cmd);
1738 	}
1739 
1740 	return 0;
1741 }
1742 
on_error(void * user_data,ikspak * pak)1743 static int on_error(void *user_data, ikspak * pak)
1744 {
1745 	globals.logger(DL_LOG_ERR, "authorization failed\n");
1746 	return IKS_FILTER_EAT;
1747 }
1748 
on_log(ldl_handle_t * handle,const char * data,size_t size,int is_incoming)1749 static void on_log(ldl_handle_t *handle, const char *data, size_t size, int is_incoming)
1750 {
1751 
1752 	if (globals.debug) {
1753 		if (is_incoming) {
1754 			globals.logger(DL_LOG_INFO, "+xml:%s%s:%s", iks_is_secure(handle->parser) ? "Sec" : "", is_incoming ? "RECV" : "SEND", data);
1755 		} else {
1756 			globals.logger(DL_LOG_NOTICE, "+xml:%s%s:%s", iks_is_secure(handle->parser) ? "Sec" : "", is_incoming ? "RECV" : "SEND", data);
1757 		}
1758 	}
1759 }
1760 
j_setup_filter(ldl_handle_t * handle)1761 static void j_setup_filter(ldl_handle_t *handle)
1762 {
1763 	int x = 0;
1764 
1765 	if (handle->filter) {
1766 		iks_filter_delete(handle->filter);
1767 	}
1768 	handle->filter = iks_filter_new();
1769 
1770 	iks_filter_add_rule(handle->filter, on_msg, handle, IKS_RULE_TYPE, IKS_PAK_MESSAGE, IKS_RULE_SUBTYPE, IKS_TYPE_CHAT, IKS_RULE_DONE);
1771 
1772 	iks_filter_add_rule(handle->filter, on_result, handle,
1773 						IKS_RULE_TYPE, IKS_PAK_IQ,
1774 						IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, IKS_RULE_ID, "auth", IKS_RULE_DONE);
1775 
1776 	iks_filter_add_rule(handle->filter, on_presence, handle,
1777 						IKS_RULE_TYPE, IKS_PAK_PRESENCE,
1778 						//IKS_RULE_SUBTYPE, IKS_TYPE_SET,
1779 						IKS_RULE_DONE);
1780 
1781 	iks_filter_add_rule(handle->filter, on_commands, handle,
1782 						IKS_RULE_TYPE, IKS_PAK_IQ,
1783 						IKS_RULE_SUBTYPE, IKS_TYPE_SET,
1784 						IKS_RULE_DONE);
1785 
1786 	iks_filter_add_rule(handle->filter, on_commands, handle,
1787 						IKS_RULE_TYPE, IKS_PAK_IQ,
1788 						IKS_RULE_SUBTYPE, IKS_TYPE_RESULT,
1789 						IKS_RULE_DONE);
1790 
1791 	iks_filter_add_rule(handle->filter, on_commands, handle,
1792 						IKS_RULE_TYPE, IKS_PAK_IQ,
1793 						IKS_RULE_SUBTYPE, IKS_TYPE_ERROR,
1794 						IKS_RULE_DONE);
1795 
1796 	iks_filter_add_rule(handle->filter, on_subscribe, handle,
1797 						IKS_RULE_TYPE, IKS_PAK_S10N,
1798 						IKS_RULE_SUBTYPE, IKS_TYPE_SUBSCRIBE,
1799 						IKS_RULE_DONE);
1800 
1801 	iks_filter_add_rule(handle->filter, on_unsubscribe, handle,
1802 						IKS_RULE_TYPE, IKS_PAK_S10N,
1803 						IKS_RULE_SUBTYPE, IKS_TYPE_UNSUBSCRIBE,
1804 						IKS_RULE_DONE);
1805 
1806 	iks_filter_add_rule(handle->filter, on_error, handle,
1807 						IKS_RULE_TYPE, IKS_PAK_IQ,
1808 						IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, IKS_RULE_ID, "auth", IKS_RULE_DONE);
1809 
1810 	for (x = 0; FEATURES[x].name; x++) {
1811 		iks_filter_add_rule(handle->filter, FEATURES[x].callback, handle,
1812 							IKS_RULE_NS, FEATURES[x].name, IKS_RULE_DONE);
1813 	}
1814 }
1815 
ldl_flush_queue(ldl_handle_t * handle,int done)1816 static ldl_queue_t ldl_flush_queue(ldl_handle_t *handle, int done)
1817 {
1818 	iks *msg;
1819 	void *pop = NULL;
1820 	unsigned int len = 0, x = 0;
1821 
1822 	ldl_queue_t sent_data = LDL_QUEUE_NONE;
1823 
1824 	apr_thread_mutex_lock(handle->lock);
1825 
1826 	while(apr_queue_trypop(handle->queue, &pop) == APR_SUCCESS) {
1827 		if (pop) {
1828 			msg = (iks *) pop;
1829 			if (!done) {
1830 				if (iks_send(handle->parser, msg) != IKS_OK) {
1831 					globals.logger(DL_LOG_DEBUG, "Failed sending data!\n");
1832 				};
1833 			};
1834 			iks_delete(msg);
1835 			pop = NULL;
1836 			sent_data = LDL_QUEUE_SENT;
1837 		} else {
1838 			break;
1839 		}
1840 	}
1841 
1842 	len = apr_queue_size(handle->retry_queue);
1843 	if (globals.debug && len) {
1844 		globals.logger(DL_LOG_CRIT, "Processing %u packets in retry queue\n", len);
1845 	}
1846 
1847 	pop = NULL;
1848 
1849 	while(x < len && apr_queue_trypop(handle->retry_queue, &pop) == APR_SUCCESS) {
1850 		if (!pop) {
1851 			break;
1852 		} else {
1853 			struct packet_node *packet_node = (struct packet_node *) pop;
1854 			apr_time_t now = apr_time_now();
1855 			x++;
1856 
1857 			if (packet_node->next <= now) {
1858 				if (packet_node->retries > 0) {
1859 					packet_node->retries--;
1860 					if (globals.debug) {
1861 						globals.logger(DL_LOG_CRIT, "Sending packet %s (%d left)\n", packet_node->id, packet_node->retries);
1862 					}
1863 					if (iks_send(handle->parser, packet_node->xml) != IKS_OK) {
1864 						globals.logger(DL_LOG_DEBUG, "Failed trying re-sending data!\n");
1865 					};
1866 					packet_node->next = now + 5000000;
1867 					sent_data = LDL_QUEUE_SENT;
1868 				}
1869 			}
1870 			if (packet_node->retries == 0 || done) {
1871 				if (globals.debug) {
1872 					globals.logger(DL_LOG_CRIT, "Discarding packet %s\n", packet_node->id);
1873 				}
1874 				apr_hash_set(handle->retry_hash, packet_node->id, APR_HASH_KEY_STRING, NULL);
1875 				iks_delete(packet_node->xml);
1876 				free(packet_node);
1877 			} else {
1878 				apr_queue_push(handle->retry_queue, packet_node);
1879 				packet_node = NULL;
1880 			}
1881 			pop = NULL;
1882 		}
1883 	}
1884 	apr_thread_mutex_unlock(handle->lock);
1885 	return sent_data;
1886 }
1887 
1888 
xmpp_connect(ldl_handle_t * handle,char * jabber_id,char * pass)1889 static void xmpp_connect(ldl_handle_t *handle, char *jabber_id, char *pass)
1890 {
1891 	int count_ka = LDL_KEEPALIVE_TIMEOUT;
1892 	time_t tstart, tnow;
1893 
1894 	while (ldl_test_flag((&globals), LDL_FLAG_READY) && ldl_test_flag(handle, LDL_FLAG_RUNNING)) {
1895 		int e;
1896 		char tmp[512], *sl;
1897 		int fd;
1898 
1899 		handle->parser = iks_stream_new(ldl_test_flag(handle, LDL_FLAG_COMPONENT) ? IKS_NS_COMPONENT : IKS_NS_CLIENT,
1900 										handle,
1901 										(iksStreamHook *) (ldl_test_flag(handle, LDL_FLAG_COMPONENT) ? on_stream_component : on_stream));
1902 
1903 
1904 		iks_set_log_hook(handle->parser, (iksLogHook *) on_log);
1905 
1906 
1907 		strncpy(tmp, jabber_id, sizeof(tmp)-1);
1908 		sl = strchr(tmp, '/');
1909 
1910 		if (!sl && !ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
1911 			/* user gave no resource name, use the default */
1912 			snprintf(tmp + strlen(tmp), sizeof(tmp) - strlen(tmp), "/%s", "talk");
1913 		} else if (sl && ldl_test_flag(handle, LDL_FLAG_COMPONENT)) {
1914 			*sl = '\0';
1915 		}
1916 
1917 		handle->acc = iks_id_new(iks_parser_stack(handle->parser), tmp);
1918 
1919 		handle->password = pass;
1920 
1921 		j_setup_filter(handle);
1922 
1923 		globals.logger(DL_LOG_DEBUG, "xmpp connecting\n");
1924 
1925 		e = iks_connect_via(handle->parser,
1926 							handle->server ? handle->server : handle->acc->server,
1927 							handle->port ? handle->port : IKS_JABBER_PORT,
1928 							handle->acc->server);
1929 
1930 		switch (e) {
1931 		case IKS_OK:
1932 			break;
1933 		case IKS_NET_NODNS:
1934 			globals.logger(DL_LOG_CRIT, "hostname lookup failed\n");
1935 			microsleep(1000);
1936 			goto fail;
1937 		case IKS_NET_NOCONN:
1938 			globals.logger(DL_LOG_CRIT, "connection failed\n");
1939 			microsleep(1000);
1940 			goto fail;
1941 		default:
1942 			globals.logger(DL_LOG_CRIT, "io error 1 %d\n", e);
1943 			microsleep(1000);
1944 			goto fail;
1945 		}
1946 
1947 		handle->counter = opt_timeout;
1948 		if ((tstart = time(NULL)) == -1) {
1949 			globals.logger(DL_LOG_DEBUG, "error determining connection time");
1950 		}
1951 
1952 		while (ldl_test_flag((&globals), LDL_FLAG_READY) && ldl_test_flag(handle, LDL_FLAG_RUNNING)) {
1953 			e = iks_recv(handle->parser, 1);
1954 
1955 			if (handle->loop_callback) {
1956 				if (handle->loop_callback(handle) != LDL_STATUS_SUCCESS) {
1957 					ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING);
1958 					break;
1959 				}
1960 			}
1961 
1962 			if (handle->job_done) {
1963 				break;
1964 			}
1965 
1966 			if (IKS_HOOK == e) {
1967 				break;
1968 			}
1969 
1970 			if (IKS_OK != e || ldl_test_flag(handle, LDL_FLAG_BREAK)) {
1971 				globals.logger(DL_LOG_DEBUG, "io error 2 %d retry in %d second(s)", e, ++handle->fail_count);
1972 				if ((tnow = time(NULL)) == -1) {
1973 					globals.logger(DL_LOG_DEBUG, "error deterniming io error time");
1974 				}
1975 				if (difftime(tnow, tstart) > 30) {
1976 					/* this is a new error situation: reset counter */
1977 					globals.logger(DL_LOG_DEBUG, "resetting fail count");
1978 					handle->fail_count = 1;
1979 				}
1980 				microsleep(1000 * handle->fail_count);
1981 				goto fail;
1982 			}
1983 
1984 			if (ldl_test_flag(handle, LDL_FLAG_RUNNING)) {
1985 				if (ldl_flush_queue(handle, 0) == LDL_QUEUE_SENT) {
1986 					count_ka = LDL_KEEPALIVE_TIMEOUT;
1987 				}
1988 			}
1989 
1990 			if (!ldl_test_flag(handle, LDL_FLAG_CONNECTED)) {
1991 				handle->counter--;
1992 
1993 				if (IKS_NET_TLSFAIL == e) {
1994 					globals.logger(DL_LOG_CRIT, "tls handshake failed\n");
1995 					microsleep(500);
1996 					break;
1997 				}
1998 
1999 				if (handle->counter == 0) {
2000 					globals.logger(DL_LOG_CRIT, "network timeout\n");
2001 					microsleep(500);
2002 					break;
2003 				}
2004 			}
2005 
2006 			if (count_ka-- <= 0) {
2007 				if( iks_send_raw(handle->parser, " ") == IKS_OK) {
2008 					globals.logger(DL_LOG_DEBUG, "Sent keep alive signal");
2009 					count_ka = LDL_KEEPALIVE_TIMEOUT;
2010 				} else {
2011 					globals.logger(DL_LOG_DEBUG, "Failed sending keep alive signal");
2012 					microsleep(500);
2013 					break;
2014 				}
2015 			}
2016 
2017 		}
2018 
2019 	fail:
2020 
2021 		ldl_clear_flag_locked(handle, LDL_FLAG_CONNECTED);
2022 		ldl_clear_flag_locked(handle, LDL_FLAG_AUTHORIZED);
2023 		ldl_clear_flag_locked(handle, LDL_FLAG_BREAK);
2024 		handle->state = CS_NEW;
2025 
2026 		if ((fd = iks_fd(handle->parser)) > -1) {
2027 			shutdown(fd, 0x02);
2028 		}
2029 
2030 		iks_disconnect(handle->parser);
2031 		iks_parser_delete(handle->parser);
2032 	}
2033 	ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING);
2034 
2035 	ldl_flush_queue(handle, 1);
2036 
2037 	ldl_set_flag_locked(handle, LDL_FLAG_STOPPED);
2038 
2039 }
2040 
add_elements(ldl_session_t * session,iks * tag)2041 static void add_elements(ldl_session_t *session, iks *tag)
2042 {
2043 	apr_hash_index_t *hi;
2044 	return;
2045 	for (hi = apr_hash_first(session->pool, session->variables); hi; hi = apr_hash_next(hi)) {
2046 		void *val = NULL;
2047 		const void *key = NULL;
2048 
2049 		apr_hash_this(hi, &key, NULL, &val);
2050 		if (val) {
2051 			iks *var = iks_insert(tag, "info_element");
2052 			iks_insert_attrib(var, "xmlns", "http://www.freeswitch.org/jie");
2053 			iks_insert_attrib(var, "name", (char *) key);
2054 			iks_insert_attrib(var, "value", (char *) val);
2055 		}
2056 	}
2057 }
2058 
2059 
ldl_set_jingle_tag(ldl_session_t * session,iks * iq,char * action)2060 static iks *ldl_set_jingle_tag(ldl_session_t *session, iks *iq, char *action)
2061 {
2062 	iks *jin = iks_insert (iq, "jin:jingle");
2063 	iks_insert_attrib(jin, "xmlns:jin", "urn:xmpp:jingle:1");
2064 	iks_insert_attrib(jin, "action", action);
2065 	iks_insert_attrib(jin, "sid", session->id);
2066 	//iks_insert_attrib(jin, "initiator", session->initiator ? session->initiator : session->them);
2067 
2068 	return jin;
2069 }
2070 
new_jingle_iq(ldl_session_t * session,iks ** iqp,iks ** jinp,unsigned int * id,char * action)2071 static ldl_status new_jingle_iq(ldl_session_t *session, iks **iqp, iks **jinp, unsigned int *id, char *action)
2072 {
2073 	iks *iq , *jin;
2074 	unsigned int myid;
2075 	char idbuf[80];
2076 
2077 	myid = next_id();
2078 	snprintf(idbuf, sizeof(idbuf), "%u", myid);
2079 	iq = iks_new("iq");
2080 	iks_insert_attrib(iq, "xmlns", "jabber:client");
2081 	iks_insert_attrib(iq, "from", session->login);
2082 	iks_insert_attrib(iq, "to", session->them);
2083 	iks_insert_attrib(iq, "type", "set");
2084 	iks_insert_attrib(iq, "id", idbuf);
2085 
2086 	jin = ldl_set_jingle_tag(session, iq, action);
2087 
2088 	*jinp = jin;
2089 	*iqp = iq;
2090 	*id = myid;
2091 	return LDL_STATUS_SUCCESS;
2092 }
2093 
2094 
new_session_iq(ldl_session_t * session,iks ** iqp,iks ** sessp,unsigned int * id,char * type)2095 static ldl_status new_session_iq(ldl_session_t *session, iks **iqp, iks **sessp, unsigned int *id, char *type)
2096 {
2097 	iks *iq, *sess;
2098 	unsigned int myid;
2099 	char idbuf[80];
2100 
2101 	myid = next_id();
2102 	snprintf(idbuf, sizeof(idbuf), "%u", myid);
2103 	iq = iks_new("iq");
2104 	iks_insert_attrib(iq, "xmlns", "jabber:client");
2105 	iks_insert_attrib(iq, "from", session->login);
2106 	iks_insert_attrib(iq, "to", session->them);
2107 	iks_insert_attrib(iq, "type", "set");
2108 	iks_insert_attrib(iq, "id", idbuf);
2109 	sess = iks_insert (iq, "ses:session");
2110 	iks_insert_attrib(sess, "xmlns:ses", "http://www.google.com/session");
2111 
2112 	iks_insert_attrib(sess, "type", type);
2113 	iks_insert_attrib(sess, "id", session->id);
2114 	iks_insert_attrib(sess, "initiator", session->initiator ? session->initiator : session->them);
2115 
2116 	*sessp = sess;
2117 	*iqp = iq;
2118 	*id = myid;
2119 	return LDL_STATUS_SUCCESS;
2120 }
2121 
schedule_packet(ldl_handle_t * handle,unsigned int id,iks * xml,unsigned int retries)2122 static void schedule_packet(ldl_handle_t *handle, unsigned int id, iks *xml, unsigned int retries)
2123 {
2124 	struct packet_node  *packet_node;
2125 
2126 	apr_thread_mutex_lock(handle->lock);
2127 	if ((packet_node = malloc(sizeof(*packet_node)))) {
2128 		memset(packet_node, 0, sizeof(*packet_node));
2129 		snprintf(packet_node->id, sizeof(packet_node->id), "%u", id);
2130 		packet_node->xml = xml;
2131 		packet_node->retries = retries;
2132 		packet_node->next = apr_time_now();
2133 		apr_hash_set(handle->retry_hash, packet_node->id, APR_HASH_KEY_STRING, packet_node);
2134 		apr_queue_push(handle->retry_queue, packet_node);
2135 		packet_node = NULL;
2136 	}
2137 	apr_thread_mutex_unlock(handle->lock);
2138 
2139 }
2140 
ldl_session_get_caller(ldl_session_t * session)2141 char *ldl_session_get_caller(ldl_session_t *session)
2142 {
2143 	return session->them;
2144 }
2145 
ldl_session_get_callee(ldl_session_t * session)2146 char *ldl_session_get_callee(ldl_session_t *session)
2147 {
2148 	return session->login;
2149 }
2150 
ldl_session_set_ip(ldl_session_t * session,char * ip)2151 void ldl_session_set_ip(ldl_session_t *session, char *ip)
2152 {
2153 	session->ip = apr_pstrdup(session->pool, ip);
2154 }
2155 
ldl_session_get_ip(ldl_session_t * session)2156 char *ldl_session_get_ip(ldl_session_t *session)
2157 {
2158 	return session->ip;
2159 }
2160 
ldl_session_set_private(ldl_session_t * session,void * private_data)2161 void ldl_session_set_private(ldl_session_t *session, void *private_data)
2162 {
2163 	session->private_data = private_data;
2164 }
2165 
ldl_session_get_private(ldl_session_t * session)2166 void *ldl_session_get_private(ldl_session_t *session)
2167 {
2168 	return session->private_data;
2169 }
2170 
ldl_session_accept_candidate(ldl_session_t * session,ldl_candidate_t * candidate)2171 void ldl_session_accept_candidate(ldl_session_t *session, ldl_candidate_t *candidate)
2172 {
2173 	iks *iq, *sess, *tp;
2174 	unsigned int myid;
2175     char idbuf[80];
2176 	myid = next_id();
2177     snprintf(idbuf, sizeof(idbuf), "%u", myid);
2178 
2179 	if ((iq = iks_new("iq"))) {
2180 		if (!iks_insert_attrib(iq, "type", "set")) goto fail;
2181 		if (!iks_insert_attrib(iq, "id", idbuf)) goto fail;
2182 		if (!iks_insert_attrib(iq, "from", session->login)) goto fail;
2183 		if (!iks_insert_attrib(iq, "to", session->them)) goto fail;
2184 		if (!(sess = iks_insert (iq, "ses:session"))) goto fail;
2185 		if (!iks_insert_attrib(sess, "xmlns:ses", "http://www.google.com/session")) goto fail;
2186 		if (!iks_insert_attrib(sess, "type", "transport-accept")) goto fail;
2187 		if (!iks_insert_attrib(sess, "id", candidate->tid)) goto fail;
2188 		if (!iks_insert_attrib(sess, "xmlns", "http://www.google.com/session")) goto fail;
2189 		if (!iks_insert_attrib(sess, "initiator", session->initiator ? session->initiator : session->them)) goto fail;
2190 		if (!(tp = iks_insert (sess, "transport"))) goto fail;
2191 		if (!iks_insert_attrib(tp, "xmlns", "http://www.google.com/transport/p2p")) goto fail;
2192 		apr_queue_push(session->handle->queue, iq);
2193 		iq = NULL;
2194 	}
2195 
2196  fail:
2197 	if (iq) {
2198 		iks_delete(iq);
2199 	}
2200 
2201 }
2202 
ldl_handle_get_private(ldl_handle_t * handle)2203 void *ldl_handle_get_private(ldl_handle_t *handle)
2204 {
2205 	return handle->private_info;
2206 }
2207 
ldl_handle_get_login(ldl_handle_t * handle)2208 char *ldl_handle_get_login(ldl_handle_t *handle)
2209 {
2210 	return handle->login;
2211 }
2212 
ldl_handle_send_presence(ldl_handle_t * handle,char * from,char * to,char * type,char * rpid,char * message,char * avatar)2213 void ldl_handle_send_presence(ldl_handle_t *handle, char *from, char *to, char *type, char *rpid, char *message, char *avatar)
2214 {
2215 	do_presence(handle, from, to, type, rpid, message, avatar);
2216 }
2217 
ldl_random_string(char * buf,uint16_t len,char * set)2218 static void ldl_random_string(char *buf, uint16_t len, char *set)
2219 {
2220     char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
2221     int max;
2222     uint16_t x;
2223 
2224     if (!set) {
2225         set = chars;
2226     }
2227 
2228     max = (int) strlen(set);
2229 
2230     srand((unsigned int) time(NULL));
2231 
2232     for (x = 0; x < len; x++) {
2233         int j = (int) (max * 1.0 * rand() / (RAND_MAX + 1.0));
2234         buf[x] = set[j];
2235     }
2236 }
2237 
2238 #define TLEN 8192
ldl_handle_send_vcard(ldl_handle_t * handle,char * from,char * to,char * id,char * vcard)2239 void ldl_handle_send_vcard(ldl_handle_t *handle, char *from, char *to, char *id, char *vcard)
2240 {
2241 	iks *vxml = NULL, *iq = NULL;
2242 	int e = 0;
2243 	ldl_avatar_t *ap = NULL;
2244 	char *text = NULL;
2245 
2246 	ap = ldl_get_avatar(handle, NULL, from);
2247 
2248 	if (!vcard) {
2249 		char *ext;
2250 
2251 		if (!ap) {
2252 			return;
2253 		}
2254 
2255 		if ((ext = strrchr(ap->path, '.'))) {
2256 			ext++;
2257 		} else {
2258 			ext = "png";
2259 		}
2260 		text = malloc(TLEN);
2261 		snprintf(text, TLEN,
2262 				 "<vCard xmlns='vcard-temp'><PHOTO><TYPE>image/%s</TYPE><BINVAL>%s</BINVAL></PHOTO></vCard>",
2263 				 ext,
2264 				 ap->base64
2265 				 );
2266 		vcard = text;
2267 	} else {
2268 		if (ap && (strstr(vcard, "photo") || strstr(vcard, "PHOTO"))) {
2269 			ldl_random_string(ap->hash, sizeof(ap->hash) -1, NULL);
2270 		}
2271 	}
2272 
2273 
2274 	if (!(vxml = iks_tree(vcard, 0, &e))) {
2275 		globals.logger(DL_LOG_ERR, "Parse returned error [%d]\n", e);
2276 		goto fail;
2277 	}
2278 
2279 	if (!(iq = iks_new("iq"))) {
2280 		globals.logger(DL_LOG_ERR, "Memory Error\n");
2281 		goto fail;
2282 	}
2283 
2284 	if (!iks_insert_attrib(iq, "to", to)) goto fail;
2285 	if (!iks_insert_attrib(iq, "xmlns", "jabber:client")) goto fail;
2286 	if (!iks_insert_attrib(iq,"from", from)) goto fail;
2287 	if (!iks_insert_attrib(iq, "type", "result")) goto fail;
2288 	if (!iks_insert_attrib(iq, "id", id)) goto fail;
2289 	if (!iks_insert_node(iq, vxml)) goto fail;
2290 
2291 	apr_queue_push(handle->queue, iq);
2292 
2293 	iq = NULL;
2294 	vxml = NULL;
2295 
2296  fail:
2297 
2298 	if (iq) {
2299 		iks_delete(iq);
2300 	}
2301 
2302 	if (vxml) {
2303 		iks_delete(vxml);
2304 	}
2305 
2306 	if (text) {
2307 		free(text);
2308 	}
2309 
2310 }
2311 
ldl_handle_send_msg(ldl_handle_t * handle,char * from,char * to,const char * subject,const char * body)2312 void ldl_handle_send_msg(ldl_handle_t *handle, char *from, char *to, const char *subject, const char *body)
2313 {
2314 	iks *msg;
2315 	char *t, *e;
2316 	char *bdup = NULL;
2317 	int on = 0;
2318 	int len = 0;
2319 	char *my_body = strdup(body);
2320 	char *my_body_base = my_body;
2321 
2322 	assert(handle != NULL);
2323 	assert(body != NULL);
2324 
2325 	if (strchr(my_body, '<')) {
2326 		len = (int) strlen(my_body);
2327 		if (!(bdup = malloc(len))) {
2328 			return;
2329 		}
2330 
2331 		memset(bdup, 0, len);
2332 
2333 		e = bdup;
2334 		for(t = my_body; *t; t++) {
2335 			if (*t == '<') {
2336 				on = 1;
2337 			} else if (*t == '>') {
2338 				t++;
2339 				on = 0;
2340 			}
2341 
2342 			if (!on) {
2343 				*e++ = *t;
2344 			}
2345 		}
2346 		my_body = bdup;
2347 	}
2348 
2349 	msg = iks_make_msg(IKS_TYPE_NONE, to, my_body);
2350 	iks_insert_attrib(msg, "type", "chat");
2351 
2352 	if (!from) {
2353 		from = handle->login;
2354 	}
2355 
2356 	iks_insert_attrib(msg, "from", from);
2357 
2358 	if (subject) {
2359 		iks_insert_attrib(msg, "subject", subject);
2360 	}
2361 
2362 	if (bdup) {
2363 		free(bdup);
2364 	}
2365 
2366 	if (my_body_base) {
2367 		free(my_body_base);
2368 	}
2369 
2370 	apr_queue_push(handle->queue, msg);
2371 	msg = NULL;
2372 
2373 }
2374 
ldl_global_debug(int on)2375 int ldl_global_debug(int on)
2376 {
2377 	if (on > -1) {
2378 		globals.debug = on ? 1 : 0;
2379 	}
2380 
2381 	return globals.debug ? 1 : 0;
2382 }
2383 
ldl_global_set_logger(ldl_logger_t logger)2384 void ldl_global_set_logger(ldl_logger_t logger)
2385 {
2386 	globals.logger = logger;
2387 }
2388 
ldl_session_terminate(ldl_session_t * session)2389 unsigned int ldl_session_terminate(ldl_session_t *session)
2390 {
2391 	iks *iq, *sess;
2392 	unsigned int id;
2393 	apr_hash_t *hash = session->handle->sessions;
2394 
2395 	new_session_iq(session, &iq, &sess, &id, "terminate");
2396 
2397 	if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2398 		ldl_set_jingle_tag(session, iq, "session-terminate");
2399 	}
2400 
2401 	schedule_packet(session->handle, id, iq, LDL_RETRY);
2402 
2403 	if (session->id) {
2404 		apr_hash_set(hash, session->id, APR_HASH_KEY_STRING, NULL);
2405 	}
2406 
2407 	if (session->them) {
2408 		apr_hash_set(hash, session->them, APR_HASH_KEY_STRING, NULL);
2409 	}
2410 
2411 	return id;
2412 
2413 }
2414 
2415 
2416 
ldl_session_transport(ldl_session_t * session,ldl_candidate_t * candidates,unsigned int clen)2417 unsigned int ldl_session_transport(ldl_session_t *session,
2418 									ldl_candidate_t *candidates,
2419 									unsigned int clen)
2420 
2421 {
2422 	iks *iq, *sess, *tag;
2423 	unsigned int x, id = 0;
2424 
2425 
2426 	if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2427 		return ldl_session_candidates(session, candidates, clen);
2428 	}
2429 
2430 
2431 
2432 	for (x = 0; x < clen; x++) {
2433 		char buf[512];
2434 		iq = NULL;
2435 		sess = NULL;
2436 		id = 0;
2437 
2438 		new_session_iq(session, &iq, &sess, &id, "transport-info");
2439 
2440 		tag = sess;
2441 
2442 		//if (0) add_elements(session, tag);
2443 		tag = iks_insert(tag, "transport");
2444 		iks_insert_attrib(tag, "xmlns", "http://www.google.com/transport/p2p");
2445 		//iks_insert_attrib(tag, "xmlns", "urn:xmpp:jingle:transports:raw-udp:1");
2446 
2447 		tag = iks_insert(tag, "candidate");
2448 
2449 		if (candidates[x].name) {
2450 			iks_insert_attrib(tag, "name", candidates[x].name);
2451 		}
2452 		if (candidates[x].address) {
2453 			iks_insert_attrib(tag, "address", candidates[x].address);
2454 		}
2455 		if (candidates[x].port) {
2456 			snprintf(buf, sizeof(buf), "%u", candidates[x].port);
2457 			iks_insert_attrib(tag, "port", buf);
2458 		}
2459 		if (candidates[x].username) {
2460 			iks_insert_attrib(tag, "username", candidates[x].username);
2461 		}
2462 		if (candidates[x].password) {
2463 			iks_insert_attrib(tag, "password", candidates[x].password);
2464 		}
2465 		if (candidates[x].pref) {
2466 			snprintf(buf, sizeof(buf), "%0.1f", candidates[x].pref);
2467 			iks_insert_attrib(tag, "preference", buf);
2468 		}
2469 		if (candidates[x].protocol) {
2470 			iks_insert_attrib(tag, "protocol", candidates[x].protocol);
2471 		}
2472 		if (candidates[x].type) {
2473 			iks_insert_attrib(tag, "type", candidates[x].type);
2474 		}
2475 
2476 		iks_insert_attrib(tag, "network", "0");
2477 		iks_insert_attrib(tag, "generation", "0");
2478 		schedule_packet(session->handle, id, iq, LDL_RETRY);
2479 	}
2480 
2481 	return id;
2482 }
2483 
ldl_session_candidates(ldl_session_t * session,ldl_candidate_t * candidates,unsigned int clen)2484 unsigned int ldl_session_candidates(ldl_session_t *session,
2485 									ldl_candidate_t *candidates,
2486 									unsigned int clen)
2487 
2488 {
2489 	iks *iq = NULL, *sess = NULL, *tag = NULL;
2490 	unsigned int x = 0, id = 0;
2491 
2492 
2493 	unsigned int pass = 0;
2494 	iks *jingle = NULL, *jin_content = NULL, *p_trans = NULL;
2495 	const char *tname = "";
2496 	const char *type = "";
2497 
2498 	if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2499 
2500 
2501 		new_jingle_iq(session, &iq, &jingle, &id, "transport-info");
2502 
2503 		for (pass = 0; pass < 2; pass++) {
2504 
2505 			if (pass == 0) {
2506 				type = "rtp";
2507 				tname = "audio";
2508 			} else {
2509 				type = "video_rtp";
2510 				tname = "video";
2511 			}
2512 
2513 			jin_content = iks_insert(jingle, "jin:content");
2514 			iks_insert_attrib(jin_content, "name", tname);
2515 			iks_insert_attrib(jin_content, "creator", "initiator");
2516 
2517 			for (x = 0; x < clen; x++) {
2518 				char buf[512];
2519 
2520 				if (strcasecmp(candidates[x].name, type)) {
2521 					continue;
2522 				}
2523 
2524 				p_trans = iks_insert(jin_content, "p:transport");
2525 				iks_insert_attrib(p_trans, "xmlns:p", "http://www.google.com/transport/p2p");
2526 
2527 
2528 
2529 				tag = iks_insert(p_trans, "candidate");
2530 
2531 				if (candidates[x].name) {
2532 					iks_insert_attrib(tag, "name", candidates[x].name);
2533 				}
2534 				if (candidates[x].address) {
2535 					iks_insert_attrib(tag, "address", candidates[x].address);
2536 				}
2537 				if (candidates[x].port) {
2538 					snprintf(buf, sizeof(buf), "%u", candidates[x].port);
2539 					iks_insert_attrib(tag, "port", buf);
2540 				}
2541 				if (candidates[x].username) {
2542 					iks_insert_attrib(tag, "username", candidates[x].username);
2543 				}
2544 				if (candidates[x].password) {
2545 					iks_insert_attrib(tag, "password", candidates[x].password);
2546 				}
2547 				if (candidates[x].pref) {
2548 					snprintf(buf, sizeof(buf), "%0.1f", candidates[x].pref);
2549 					iks_insert_attrib(tag, "preference", buf);
2550 				}
2551 				if (candidates[x].protocol) {
2552 					iks_insert_attrib(tag, "protocol", candidates[x].protocol);
2553 				}
2554 				if (candidates[x].type) {
2555 					iks_insert_attrib(tag, "type", candidates[x].type);
2556 				}
2557 
2558 				iks_insert_attrib(tag, "network", "0");
2559 				iks_insert_attrib(tag, "generation", "0");
2560 			}
2561 		}
2562 
2563 
2564 		schedule_packet(session->handle, id, iq, LDL_RETRY);
2565 
2566 		iq = NULL;
2567 		sess = NULL;
2568 		tag = NULL;
2569 		id = 0;
2570 	}
2571 
2572 
2573 	new_session_iq(session, &iq, &sess, &id, "candidates");
2574 	add_elements(session, sess);
2575 
2576 	for (x = 0; x < clen; x++) {
2577 		char buf[512];
2578 		//iq = NULL;
2579 		//sess = NULL;
2580 		//id = 0;
2581 
2582 		tag = iks_insert(sess, "ses:candidate");
2583 
2584 
2585 
2586 		if (candidates[x].name) {
2587 			iks_insert_attrib(tag, "name", candidates[x].name);
2588 		}
2589 		if (candidates[x].address) {
2590 			iks_insert_attrib(tag, "address", candidates[x].address);
2591 		}
2592 		if (candidates[x].port) {
2593 			snprintf(buf, sizeof(buf), "%u", candidates[x].port);
2594 			iks_insert_attrib(tag, "port", buf);
2595 		}
2596 		if (candidates[x].username) {
2597 			iks_insert_attrib(tag, "username", candidates[x].username);
2598 		}
2599 		if (candidates[x].password) {
2600 			iks_insert_attrib(tag, "password", candidates[x].password);
2601 		}
2602 		if (candidates[x].pref) {
2603 			snprintf(buf, sizeof(buf), "%0.1f", candidates[x].pref);
2604 			iks_insert_attrib(tag, "preference", buf);
2605 		}
2606 		if (candidates[x].protocol) {
2607 			iks_insert_attrib(tag, "protocol", candidates[x].protocol);
2608 		}
2609 		if (candidates[x].type) {
2610 			iks_insert_attrib(tag, "type", candidates[x].type);
2611 		}
2612 
2613 		iks_insert_attrib(tag, "network", "0");
2614 		iks_insert_attrib(tag, "generation", "0");
2615 
2616 	}
2617 
2618 	schedule_packet(session->handle, id, iq, LDL_RETRY);
2619 
2620 	return id;
2621 }
2622 
2623 
2624 
ldl_handle_probe(ldl_handle_t * handle,char * id,char * from,char * buf,unsigned int len)2625 char *ldl_handle_probe(ldl_handle_t *handle, char *id, char *from, char *buf, unsigned int len)
2626 {
2627 	iks *pres, *msg;
2628 	char *lid = NULL, *low_id = NULL;
2629 	struct ldl_buffer buffer;
2630 	time_t started, elapsed, next = 0;
2631 	char *notice = "Call Me!";
2632 
2633 	buffer.buf = buf;
2634 	buffer.len = len;
2635 	buffer.hit = 0;
2636 
2637 	apr_hash_set(handle->probe_hash, id, APR_HASH_KEY_STRING, &buffer);
2638 
2639 	started = time(NULL);
2640 	for(;;) {
2641 		elapsed = time(NULL) - started;
2642 		if (elapsed == next) {
2643 			msg = iks_make_s10n (IKS_TYPE_SUBSCRIBE, id, notice);
2644 			iks_insert_attrib(msg, "from", from);
2645 			apr_queue_push(handle->queue, msg);
2646 			msg = NULL;
2647 
2648 			pres = iks_new("presence");
2649 			iks_insert_attrib(pres, "xmlns", "jabber:client");
2650 			iks_insert_attrib(pres, "type", "probe");
2651 			iks_insert_attrib(pres, "to", id);
2652 			iks_insert_attrib(pres, "from", from);
2653 			apr_queue_push(handle->queue, pres);
2654 			pres = NULL;
2655 			next += 5;
2656 		}
2657 		if (elapsed >= 17) {
2658 			break;
2659 		}
2660 		if (buffer.hit) {
2661 			lid = buffer.buf;
2662 			break;
2663 		}
2664 		ldl_yield(1000);
2665 	}
2666 
2667 	if ((low_id = strdup(id))) {
2668 		lowercase(id);
2669 		apr_hash_set(handle->probe_hash, low_id, APR_HASH_KEY_STRING, NULL);
2670 		free(low_id);
2671 	}
2672 
2673 	return lid;
2674 }
2675 
2676 
ldl_handle_disco(ldl_handle_t * handle,char * id,char * from,char * buf,unsigned int len)2677 char *ldl_handle_disco(ldl_handle_t *handle, char *id, char *from, char *buf, unsigned int len)
2678 {
2679 	iks *iq, *query, *msg;
2680 	char *lid = NULL;
2681 	struct ldl_buffer buffer;
2682 	apr_time_t started;
2683 	unsigned int elapsed;
2684 	char *notice = "Call Me!";
2685 	int again = 0;
2686 	unsigned int myid;
2687     char idbuf[80];
2688 
2689 	myid = next_id();
2690     snprintf(idbuf, sizeof(idbuf), "%u", myid);
2691 
2692 	buffer.buf = buf;
2693 	buffer.len = len;
2694 	buffer.hit = 0;
2695 
2696 	if ((iq = iks_new("iq"))) {
2697 		if ((query = iks_insert(iq, "query"))) {
2698 			iks_insert_attrib(iq, "type", "get");
2699 			iks_insert_attrib(iq, "to", id);
2700 			iks_insert_attrib(iq,"from", from);
2701 			iks_insert_attrib(iq, "id", idbuf);
2702 			iks_insert_attrib(query, "xmlns", "http://jabber.org/protocol/disco#info");
2703 		} else {
2704 			iks_delete(iq);
2705 			globals.logger(DL_LOG_CRIT, "Memory ERROR!\n");
2706 			return NULL;
2707 		}
2708 	} else {
2709 		globals.logger(DL_LOG_CRIT, "Memory ERROR!\n");
2710 		return NULL;
2711 	}
2712 
2713 	apr_hash_set(handle->probe_hash, id, APR_HASH_KEY_STRING, &buffer);
2714 	msg = iks_make_s10n (IKS_TYPE_SUBSCRIBE, id, notice);
2715 	apr_queue_push(handle->queue, msg);
2716 	msg = NULL;
2717 	msg = iks_make_s10n (IKS_TYPE_SUBSCRIBED, id, notice);
2718 	apr_queue_push(handle->queue, msg);
2719 	msg = NULL;
2720 	apr_queue_push(handle->queue, iq);
2721 	iq = NULL;
2722 
2723 	//schedule_packet(handle, next_id(), pres, LDL_RETRY);
2724 
2725 	started = apr_time_now();
2726 	for(;;) {
2727 		elapsed = (unsigned int)((apr_time_now() - started) / 1000);
2728 		if (elapsed > 5000 && ! again) {
2729 			msg = iks_make_s10n (IKS_TYPE_SUBSCRIBE, id, notice);
2730 			apr_queue_push(handle->queue, msg);
2731 			msg = NULL;
2732 			again++;
2733 		}
2734 		if (elapsed > 10000) {
2735 			break;
2736 		}
2737 		if (buffer.hit) {
2738 			lid = buffer.buf;
2739 			break;
2740 		}
2741 		ldl_yield(1000);
2742 	}
2743 
2744 	apr_hash_set(handle->probe_hash, id, APR_HASH_KEY_STRING, NULL);
2745 	return lid;
2746 }
2747 
2748 
2749 
ldl_session_describe(ldl_session_t * session,ldl_payload_t * payloads,unsigned int plen,ldl_description_t description,unsigned int * audio_ssrc,unsigned int * video_ssrc,ldl_crypto_data_t * audio_crypto_data,ldl_crypto_data_t * video_crypto_data)2750 unsigned int ldl_session_describe(ldl_session_t *session,
2751 								  ldl_payload_t *payloads,
2752 								  unsigned int plen,
2753 								  ldl_description_t description, unsigned int *audio_ssrc, unsigned int *video_ssrc,
2754 								  ldl_crypto_data_t *audio_crypto_data, ldl_crypto_data_t *video_crypto_data)
2755 {
2756 	iks *iq;
2757 	iks *sess, *payload = NULL, *tag = NULL;//, *u = NULL;
2758 
2759 	unsigned int x, id;
2760 	int video_call = 0;
2761 	int compat = 1;
2762 	//char *vid_mux = ldl_session_get_value(session, "video:rtcp-mux");
2763 	//char *aud_mux = ldl_session_get_value(session, "audio:rtcp-mux");
2764  	char tmp[80];
2765 	iks *jpayload = NULL, *tp = NULL;
2766 	iks *jingle, *jin_audio, *jin_audio_desc = NULL, *jin_video = NULL, *jin_video_desc = NULL, *crypto;
2767 
2768 
2769 	if (!*audio_ssrc) {
2770 		*audio_ssrc = (uint32_t) ((intptr_t) session + (uint32_t) time(NULL));
2771 	}
2772 
2773 	if (!*video_ssrc) {
2774 		*video_ssrc = (uint32_t) ((intptr_t) payloads + (uint32_t) time(NULL));
2775 	}
2776 
2777 	if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2778 		new_jingle_iq(session, &iq, &jingle, &id, description == LDL_DESCRIPTION_ACCEPT ? "session-accept" : "session-initiate");
2779 		iks_insert_attrib(jingle, "initiator", session->initiator ? session->initiator : session->them);
2780 
2781 		if (compat) {
2782 			sess = iks_insert (iq, "ses:session");
2783 			iks_insert_attrib(sess, "xmlns:ses", "http://www.google.com/session");
2784 
2785 			iks_insert_attrib(sess, "type", description == LDL_DESCRIPTION_ACCEPT ? "accept" : "initiate");
2786 			iks_insert_attrib(sess, "id", session->id);
2787 			iks_insert_attrib(sess, "initiator", session->initiator ? session->initiator : session->them);
2788 		}
2789 
2790 	} else {
2791 		new_session_iq(session, &iq, &sess, &id, description == LDL_DESCRIPTION_ACCEPT ? "accept" : "initiate");
2792 	}
2793 
2794 
2795 	/* Check if this is a video call */
2796 	for (x = 0; x < plen; x++) {
2797 		if (payloads[x].type == LDL_PAYLOAD_VIDEO) {
2798 			video_call = 1;
2799 			if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2800 				jin_video = iks_insert(jingle, "jin:content");
2801 				iks_insert_attrib(jin_video, "name", "video");
2802 				iks_insert_attrib(jin_video, "creator", "initiator");
2803 				//iks_insert_attrib(jin_video, "senders", "both");
2804 				jin_video_desc = iks_insert(jin_video, "rtp:description");
2805 				iks_insert_attrib(jin_video_desc, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1");
2806 				iks_insert_attrib(jin_video_desc, "media", "video");
2807 				snprintf(tmp, sizeof(tmp), "%u", *video_ssrc);
2808 				iks_insert_attrib(jin_video_desc, "ssrc", tmp);
2809 				tp = iks_insert(jin_video, "p:transport");
2810 				iks_insert_attrib(tp, "xmlns:p", "http://www.google.com/transport/p2p");
2811 
2812 			}
2813 
2814 			break;
2815 		}
2816 	}
2817 
2818 
2819 	if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2820 		jin_audio = iks_insert(jingle, "jin:content");
2821 		iks_insert_attrib(jin_audio, "name", "audio");
2822 		iks_insert_attrib(jin_audio, "creator", "initiator");
2823 		//iks_insert_attrib(jin_audio, "senders", "both");
2824 		jin_audio_desc = iks_insert(jin_audio, "rtp:description");
2825 		iks_insert_attrib(jin_audio_desc, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1");
2826 		iks_insert_attrib(jin_audio_desc, "media", "audio");
2827 		snprintf(tmp, sizeof(tmp), "%u", *audio_ssrc);
2828 		iks_insert_attrib(jin_audio_desc, "ssrc", tmp);
2829 		tp = iks_insert(jin_audio, "p:transport");
2830 		iks_insert_attrib(tp, "xmlns:p", "http://www.google.com/transport/p2p");
2831 	}
2832 
2833 	if (compat) {
2834 
2835 		if (video_call) {
2836 			tag = iks_insert(sess, "vid:description");
2837 			iks_insert_attrib(tag, "xmlns:vid", "http://www.google.com/session/video");
2838 		} else {
2839 			tag = iks_insert(sess, "pho:description");
2840 			iks_insert_attrib(tag, "xmlns:pho", "http://www.google.com/session/phone");
2841 		}
2842 
2843 		if (video_call) {
2844 
2845 			for (x = 0; x < plen; x++) {
2846 				char idbuf[80];
2847 
2848 				if (payloads[x].type != LDL_PAYLOAD_VIDEO) {
2849 					continue;
2850 				}
2851 
2852 				sprintf(idbuf, "%d", payloads[x].id);
2853 
2854 
2855 				payload = iks_insert(tag, "vid:payload-type");
2856 
2857 				iks_insert_attrib(payload, "id", idbuf);
2858 				iks_insert_attrib(payload, "name", payloads[x].name);
2859 
2860 				if (payloads[x].type == LDL_PAYLOAD_VIDEO && video_call) {
2861 					if (payloads[x].width) {
2862 						sprintf(idbuf, "%d", payloads[x].width);
2863 						iks_insert_attrib(payload, "width", idbuf);
2864 					}
2865 					if (payloads[x].height) {
2866 						sprintf(idbuf, "%d", payloads[x].height);
2867 						iks_insert_attrib(payload, "height", idbuf);
2868 					}
2869 					if (payloads[x].framerate) {
2870 						sprintf(idbuf, "%d", payloads[x].framerate);
2871 						iks_insert_attrib(payload, "framerate", idbuf);
2872 					}
2873 				}
2874 
2875 			}
2876 
2877 
2878 			//if (vid_mux) {
2879 			//	iks_insert(tag, "rtcp-mux");
2880 			//}
2881 
2882 			//payload = iks_insert(tag, "vid:src-id");
2883 			//iks_insert_cdata(payload, "123456789", 0);
2884 
2885 
2886 			//iks_insert_attrib(payload, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1");
2887 			//iks_insert(payload, "vid:usage");
2888 		}
2889 	}
2890 
2891 	for (x = 0; x < plen; x++) {
2892 		char idbuf[80];
2893 
2894 		if (payloads[x].type == LDL_PAYLOAD_VIDEO && !video_call) {
2895 			continue;
2896 		}
2897 
2898 		sprintf(idbuf, "%d", payloads[x].id);
2899 
2900 		if (payloads[x].type == LDL_PAYLOAD_AUDIO) {
2901 
2902 			if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2903 				char ratebuf[80];
2904 				char buf[80];
2905 				iks *param;
2906 
2907 				jpayload = iks_insert(jin_audio_desc, "rtp:payload-type");
2908 				iks_insert_attrib(jpayload, "id", idbuf);
2909 				sprintf(ratebuf, "%d", payloads[x].rate);
2910 				iks_insert_attrib(jpayload, "name", payloads[x].name);
2911 				iks_insert_attrib(jpayload, "clockrate", ratebuf);
2912 				param = iks_insert(jpayload, "rtp:parameter");
2913 				iks_insert_attrib(param, "name", "bitrate");
2914 				sprintf(buf, "%d", payloads[x].bps);
2915 				iks_insert_attrib(param, "value", buf);
2916 
2917 				sprintf(buf, "%d", payloads[x].ptime);
2918 				iks_insert_attrib(jpayload, "ptime", ratebuf);
2919 				iks_insert_attrib(jpayload, "maxptime", ratebuf);
2920 
2921 			}
2922 
2923 		} else  if (payloads[x].type == LDL_PAYLOAD_VIDEO && video_call) {
2924 
2925 			if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2926 				char buf[80];
2927 				iks *param;
2928 
2929 				jpayload = iks_insert(jin_video_desc, "rtp:payload-type");
2930 				iks_insert_attrib(jpayload, "id", idbuf);
2931 				iks_insert_attrib(jpayload, "name", payloads[x].name);
2932 				param = iks_insert(jpayload, "rtp:parameter");
2933 				iks_insert_attrib(param, "name", "width");
2934 				sprintf(buf, "%d", payloads[x].width);
2935 				iks_insert_attrib(param, "value", buf);
2936 
2937 
2938 				param = iks_insert(jpayload, "rtp:parameter");
2939 				iks_insert_attrib(param, "name", "height");
2940 				sprintf(buf, "%d", payloads[x].height);
2941 				iks_insert_attrib(param, "value", buf);
2942 
2943 				param = iks_insert(jpayload, "rtp:parameter");
2944 				iks_insert_attrib(param, "name", "framerate");
2945 				sprintf(buf, "%d", payloads[x].framerate);
2946 				iks_insert_attrib(param, "value", buf);
2947 
2948 			}
2949 		}
2950 
2951 		if (compat) {
2952 
2953 			if (payloads[x].type == LDL_PAYLOAD_AUDIO) {
2954 
2955 				payload = iks_insert(tag, "pho:payload-type");
2956 
2957 				iks_insert_attrib(payload, "id", idbuf);
2958 				iks_insert_attrib(payload, "name", payloads[x].name);
2959 
2960 				if (payloads[x].rate) {
2961 					sprintf(idbuf, "%d", payloads[x].rate);
2962 					iks_insert_attrib(payload, "clockrate", idbuf);
2963 				}
2964 
2965 				if (payloads[x].bps) {
2966 					sprintf(idbuf, "%d", payloads[x].bps);
2967 					iks_insert_attrib(payload, "bitrate", idbuf);
2968 				}
2969 
2970 				iks_insert_attrib(payload, "xmlns:pho", "http://www.google.com/session/phone");
2971 			}
2972 		}
2973 		//if (payloads[x].id == 34) payloads[x].id = 98; /* XXX */
2974 
2975 	}
2976 
2977 	if ((session->handle->flags & LDL_FLAG_JINGLE)) {
2978 		if (jin_video_desc && video_crypto_data) {
2979 			payload = iks_insert(jin_video_desc, "rtp:encryption");
2980 			crypto = iks_insert(payload, "rtp:crypto");
2981 			iks_insert_attrib(crypto, "crypto-suite", video_crypto_data->suite);
2982 			iks_insert_attrib(crypto, "key-params", video_crypto_data->key);
2983 			iks_insert_attrib(crypto, "tag", video_crypto_data->tag);
2984 		}
2985 
2986 
2987 		if (jin_audio_desc && audio_crypto_data) {
2988 			payload = iks_insert(jin_audio_desc, "rtp:encryption");
2989 			crypto = iks_insert(payload, "rtp:crypto");
2990 			iks_insert_attrib(crypto, "crypto-suite", audio_crypto_data->suite);
2991 			iks_insert_attrib(crypto, "key-params", audio_crypto_data->key);
2992 			iks_insert_attrib(crypto, "tag", audio_crypto_data->tag);
2993 		}
2994 	}
2995 
2996 	//if (aud_mux) {
2997 	//	iks_insert(tag, "rtcp-mux");
2998 	//}
2999 
3000 	//payload = iks_insert(tag, "pho:src-id");
3001 	//iks_insert_cdata(payload, "987654321", 0);
3002 	//iks_insert_attrib(payload, "xmlns:pho", "http://www.google.com/session/phone");
3003 
3004 	//payload = iks_insert(tag, "rtp:encryption");
3005 	//iks_insert_attrib(payload, "xmlns:rtp", "urn:xmpp:jingle:apps:rtp:1");
3006 	//u = iks_insert(payload, "pho:usage");
3007 	//iks_insert_attrib(u, "xmlns:pho", "http://www.google.com/session/phone");
3008 
3009 #if 0
3010 	if (description == LDL_DESCRIPTION_INITIATE) {
3011 		tp = iks_insert (sess, "transport");
3012 		iks_insert_attrib(tp, "xmlns", "http://www.google.com/transport/p2p");
3013 	}
3014 #endif
3015 
3016 
3017 	schedule_packet(session->handle, id, iq, LDL_RETRY);
3018 
3019 	return id;
3020 }
3021 
ldl_session_get_state(ldl_session_t * session)3022 ldl_state_t ldl_session_get_state(ldl_session_t *session)
3023 {
3024 	return session->state;
3025 }
3026 
ldl_session_get_candidates(ldl_session_t * session,ldl_transport_type_t tport,ldl_candidate_t ** candidates,unsigned int * len)3027 ldl_status ldl_session_get_candidates(ldl_session_t *session, ldl_transport_type_t tport, ldl_candidate_t **candidates, unsigned int *len)
3028 {
3029 	assert(tport < LDL_TPORT_MAX);
3030 
3031 	if (session->candidate_len[tport]) {
3032 		*candidates = session->candidates[tport];
3033 		*len = session->candidate_len[tport];
3034 		return LDL_STATUS_SUCCESS;
3035 	} else {
3036 		*candidates = NULL;
3037 		*len = 0;
3038 		return LDL_STATUS_FALSE;
3039 	}
3040 }
3041 
ldl_session_get_payloads(ldl_session_t * session,ldl_payload_t ** payloads,unsigned int * len)3042 ldl_status ldl_session_get_payloads(ldl_session_t *session, ldl_payload_t **payloads, unsigned int *len)
3043 {
3044 	if (session->payload_len) {
3045 		*payloads = session->payloads;
3046 		*len = session->payload_len;
3047 		return LDL_STATUS_SUCCESS;
3048 	} else {
3049 		*payloads = NULL;
3050 		*len = 0;
3051 		return LDL_STATUS_FALSE;
3052 	}
3053 }
3054 
ldl_global_terminate(void)3055 ldl_status ldl_global_terminate(void)
3056 {
3057 	if (globals.flag_mutex) {
3058 		ldl_clear_flag_locked((&globals), LDL_FLAG_READY);
3059 	} else {
3060 		ldl_clear_flag((&globals), LDL_FLAG_READY);
3061 	}
3062 	return LDL_STATUS_SUCCESS;
3063 }
3064 
ldl_global_init(int debug)3065 ldl_status ldl_global_init(int debug)
3066 {
3067 	if (ldl_test_flag((&globals), LDL_FLAG_INIT)) {
3068 		return LDL_STATUS_FALSE;
3069 	}
3070 
3071 	if (apr_initialize() != LDL_STATUS_SUCCESS) {
3072 		apr_terminate();
3073 		return LDL_STATUS_MEMERR;
3074 	}
3075 
3076 	memset(&globals, 0, sizeof(globals));
3077 
3078 	if (apr_pool_create(&globals.memory_pool, NULL) != LDL_STATUS_SUCCESS) {
3079 		globals.logger(DL_LOG_CRIT, "Could not allocate memory pool\n");
3080 		return LDL_STATUS_MEMERR;
3081 	}
3082 
3083 	apr_thread_mutex_create(&globals.flag_mutex, APR_THREAD_MUTEX_NESTED, globals.memory_pool);
3084 	globals.log_stream = stdout;
3085 	globals.debug = debug;
3086 	globals.id = 300;
3087 	globals.logger = default_logger;
3088 	globals.avatar_hash = apr_hash_make(globals.memory_pool);
3089 	ldl_set_flag_locked((&globals), LDL_FLAG_INIT);
3090 	ldl_set_flag_locked((&globals), LDL_FLAG_READY);
3091 
3092 	return LDL_STATUS_SUCCESS;
3093 }
3094 
ldl_global_destroy(void)3095 ldl_status ldl_global_destroy(void)
3096 {
3097 	if (!ldl_test_flag(&globals, LDL_FLAG_INIT)) {
3098 		return LDL_STATUS_FALSE;
3099 	}
3100 
3101 	apr_pool_destroy(globals.memory_pool);
3102 	ldl_clear_flag(&globals, LDL_FLAG_INIT);
3103 	apr_terminate();
3104 
3105 	return LDL_STATUS_SUCCESS;
3106 }
3107 
ldl_global_set_log_stream(FILE * log_stream)3108 void ldl_global_set_log_stream(FILE *log_stream)
3109 {
3110 	assert(ldl_test_flag(&globals, LDL_FLAG_INIT));
3111 
3112 	globals.log_stream = log_stream;
3113 }
3114 
ldl_handle_ready(ldl_handle_t * handle)3115 int8_t ldl_handle_ready(ldl_handle_t *handle)
3116 {
3117 	return (int8_t) (ldl_test_flag(handle, LDL_FLAG_RUNNING) && ldl_test_flag((&globals), LDL_FLAG_READY));
3118 }
3119 
ldl_handle_init(ldl_handle_t ** handle,char * login,char * password,char * server,ldl_user_flag_t flags,char * status_msg,char * priority,ldl_loop_callback_t loop_callback,ldl_session_callback_t session_callback,ldl_response_callback_t response_callback,void * private_info)3120 ldl_status ldl_handle_init(ldl_handle_t **handle,
3121 						   char *login,
3122 						   char *password,
3123 						   char *server,
3124 						   ldl_user_flag_t flags,
3125 						   char *status_msg,
3126 						   char *priority,
3127 						   ldl_loop_callback_t loop_callback,
3128 						   ldl_session_callback_t session_callback,
3129 						   ldl_response_callback_t response_callback,
3130 						   void *private_info)
3131 {
3132 	apr_pool_t *pool;
3133 	assert(ldl_test_flag(&globals, LDL_FLAG_INIT));
3134 	*handle = NULL;
3135 
3136 	if ((apr_pool_create(&pool, globals.memory_pool)) != LDL_STATUS_SUCCESS) {
3137 		return LDL_STATUS_MEMERR;
3138 	}
3139 
3140 	if (!login) {
3141 		globals.logger(DL_LOG_ERR, "No login supplied!\n");
3142 		return LDL_STATUS_FALSE;
3143 	}
3144 
3145 	if (!password) {
3146 		globals.logger(DL_LOG_ERR, "No password supplied!\n");
3147 		return LDL_STATUS_FALSE;
3148 	}
3149 
3150 
3151 	if ((*handle = apr_palloc(pool, sizeof(ldl_handle_t)))) {
3152 		ldl_handle_t *new_handle = *handle;
3153 		memset(new_handle, 0, sizeof(ldl_handle_t));
3154 		new_handle->log_stream = globals.log_stream;
3155 		new_handle->login = apr_pstrdup(pool, login);
3156 		new_handle->password = apr_pstrdup(pool, password);
3157 
3158 		if (server) {
3159 			char *p;
3160 
3161 			new_handle->server = apr_pstrdup(pool, server);
3162 			if ((p = strchr(new_handle->server, ':'))) {
3163 				*p++ = '\0';
3164 				new_handle->port = (uint16_t)atoi(p);
3165 			}
3166 		}
3167 
3168 		if (status_msg) {
3169 			new_handle->status_msg = apr_pstrdup(pool, status_msg);
3170 		}
3171 
3172 		if (priority) {
3173 			new_handle->priority = apr_pstrdup(pool, priority);
3174 		}
3175 
3176 		if (loop_callback) {
3177 			new_handle->loop_callback = loop_callback;
3178 		}
3179 
3180 		if (session_callback) {
3181 			new_handle->session_callback = session_callback;
3182 		}
3183 
3184 		if (response_callback) {
3185 			new_handle->response_callback = response_callback;
3186 		}
3187 
3188 		new_handle->private_info = private_info;
3189 		new_handle->pool = pool;
3190 		new_handle->flags |= flags;
3191 		apr_queue_create(&new_handle->queue, LDL_HANDLE_QLEN, new_handle->pool);
3192 		apr_queue_create(&new_handle->retry_queue, LDL_HANDLE_QLEN, new_handle->pool);
3193 		new_handle->features |= IKS_STREAM_BIND|IKS_STREAM_SESSION;
3194 
3195 		if (new_handle->flags & LDL_FLAG_SASL_PLAIN) {
3196 			new_handle->features |= IKS_STREAM_SASL_PLAIN;
3197 		} else if (new_handle->flags & LDL_FLAG_SASL_MD5) {
3198 			new_handle->features |= IKS_STREAM_SASL_MD5;
3199 		}
3200 
3201 		new_handle->sessions = apr_hash_make(new_handle->pool);
3202 		new_handle->retry_hash = apr_hash_make(new_handle->pool);
3203 		new_handle->probe_hash = apr_hash_make(new_handle->pool);
3204 		new_handle->sub_hash = apr_hash_make(new_handle->pool);
3205 		apr_thread_mutex_create(&new_handle->lock, APR_THREAD_MUTEX_NESTED, new_handle->pool);
3206 		apr_thread_mutex_create(&new_handle->flag_mutex, APR_THREAD_MUTEX_NESTED, new_handle->pool);
3207 
3208 		return LDL_STATUS_SUCCESS;
3209 	}
3210 
3211 	return LDL_STATUS_FALSE;
3212 }
3213 
ldl_handle_run(ldl_handle_t * handle)3214 void ldl_handle_run(ldl_handle_t *handle)
3215 {
3216 	ldl_clear_flag_locked(handle, LDL_FLAG_STOPPED);
3217 	ldl_set_flag_locked(handle, LDL_FLAG_RUNNING);
3218 	xmpp_connect(handle, handle->login, handle->password);
3219 	ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING);
3220 }
3221 
ldl_handle_running(ldl_handle_t * handle)3222 int ldl_handle_running(ldl_handle_t *handle)
3223 {
3224 	return ldl_test_flag(handle, LDL_FLAG_RUNNING) ? 1 : 0;
3225 }
3226 
3227 
ldl_session_set_gateway(ldl_session_t * session)3228 void ldl_session_set_gateway(ldl_session_t *session)
3229 {
3230 	ldl_set_flag(session, LDL_FLAG_GATEWAY);
3231 }
3232 
ldl_session_gateway(ldl_session_t * session)3233 int ldl_session_gateway(ldl_session_t *session)
3234 {
3235 	return ldl_test_flag(session, LDL_FLAG_GATEWAY) ? 1 : 0;
3236 }
3237 
ldl_handle_connected(ldl_handle_t * handle)3238 int ldl_handle_connected(ldl_handle_t *handle)
3239 {
3240 	return ldl_test_flag(handle, LDL_FLAG_CONNECTED) ? 1 : 0;
3241 }
3242 
ldl_handle_authorized(ldl_handle_t * handle)3243 int ldl_handle_authorized(ldl_handle_t *handle)
3244 {
3245 	return ldl_test_flag(handle, LDL_FLAG_AUTHORIZED) ? 1 : 0;
3246 }
3247 
ldl_handle_stop(ldl_handle_t * handle)3248 void ldl_handle_stop(ldl_handle_t *handle)
3249 {
3250 	ldl_clear_flag_locked(handle, LDL_FLAG_RUNNING);
3251 #if 0
3252 	if (ldl_test_flag(handle, LDL_FLAG_TLS)) {
3253 		int fd;
3254 		if ((fd = iks_fd(handle->parser)) > -1) {
3255 			shutdown(fd, 0x02);
3256 		}
3257 	}
3258 #endif
3259 
3260 	while(!ldl_test_flag(handle, LDL_FLAG_STOPPED)) {
3261 		microsleep(100);
3262 	}
3263 
3264 }
3265 
ldl_handle_destroy(ldl_handle_t ** handle)3266 ldl_status ldl_handle_destroy(ldl_handle_t **handle)
3267 {
3268 	apr_pool_t *pool = (*handle)->pool;
3269 
3270 	ldl_handle_stop(*handle);
3271 	ldl_flush_queue(*handle, 1);
3272 
3273 
3274 	apr_pool_destroy(pool);
3275 	*handle = NULL;
3276 	return LDL_STATUS_SUCCESS;
3277 }
3278 
3279 
ldl_handle_set_log_stream(ldl_handle_t * handle,FILE * log_stream)3280 void ldl_handle_set_log_stream(ldl_handle_t *handle, FILE *log_stream)
3281 {
3282 	assert(ldl_test_flag(&globals, LDL_FLAG_INIT));
3283 
3284 	handle->log_stream = log_stream;
3285 }
3286 
3287 /* For Emacs:
3288  * Local Variables:
3289  * mode:c
3290  * indent-tabs-mode:t
3291  * tab-width:4
3292  * c-basic-offset:4
3293  * End:
3294  * For VIM:
3295  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
3296  */
3297