audio: send 486 Busy Here when call is in progress and another call invitation arrives.
[siplcs.git] / src / core / sipe-utils.c
blob2161f3cd9e06259b28ba3e416582e6183b128ca1
1 /**
2 * @file sipe-utils.c
4 * pidgin-sipe
6 * Copyright (C) 2009-2010 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <time.h>
29 #include <glib.h>
31 #ifdef _WIN32
32 #include <nspapi.h>
33 #else
34 #include <unistd.h>
35 #include <net/if.h>
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #endif
42 #include "sipe-backend.h"
43 #include "sipe-core.h" /* to ensure same API for backends */
44 #include "sipe-utils.h"
45 #include "uuid.h"
46 #include "sipe.h"
48 /* Generate 32 random bits */
49 #define RANDOM32BITS (rand() & 0xFFFF)
51 gchar *gencallid(void)
53 return g_strdup_printf("%04Xg%04Xa%04Xi%04Xm%04Xt%04Xb%04Xx%04Xx",
54 RANDOM32BITS, RANDOM32BITS, RANDOM32BITS,
55 RANDOM32BITS, RANDOM32BITS, RANDOM32BITS,
56 RANDOM32BITS, RANDOM32BITS);
59 gchar *gentag(void)
61 return g_strdup_printf("%04d%04d", RANDOM32BITS, RANDOM32BITS);
64 gchar *genconfid(void)
66 return g_strdup_printf("%04X%04X%04X%04X%04X%04X%04X%04X",
67 RANDOM32BITS, RANDOM32BITS, RANDOM32BITS,
68 RANDOM32BITS, RANDOM32BITS, RANDOM32BITS,
69 RANDOM32BITS, RANDOM32BITS);
72 gchar *get_contact(const struct sipe_account_data *sip)
74 return g_strdup(sip->contact);
77 gchar *parse_from(const gchar *hdr)
79 gchar *from;
80 const gchar *tmp, *tmp2 = hdr;
82 if (!hdr) return NULL;
83 SIPE_DEBUG_INFO("parsing address out of %s", hdr);
84 tmp = strchr(hdr, '<');
86 /* i hate the different SIP UA behaviours... */
87 if (tmp) { /* sip address in <...> */
88 tmp2 = tmp + 1;
89 tmp = strchr(tmp2, '>');
90 if (tmp) {
91 from = g_strndup(tmp2, tmp - tmp2);
92 } else {
93 SIPE_DEBUG_INFO_NOFORMAT("found < without > in From");
94 return NULL;
96 } else {
97 tmp = strchr(tmp2, ';');
98 if (tmp) {
99 from = g_strndup(tmp2, tmp - tmp2);
100 } else {
101 from = g_strdup(tmp2);
104 SIPE_DEBUG_INFO("got %s", from);
105 return from;
108 int parse_cseq(const gchar *hdr)
110 int res = -1;
111 gchar **items;
112 items = g_strsplit(hdr, " ", 1);
113 if (items[0]) {
114 res = atoi(items[0]);
116 g_strfreev(items);
117 return res;
120 gchar *sip_uri_from_name(const gchar *name)
122 return(g_strdup_printf("sip:%s", name));
125 gchar *sip_uri(const gchar *string)
127 return(strstr(string, "sip:") ? g_strdup(string) : sip_uri_from_name(string));
130 gchar *
131 get_epid(struct sipe_account_data *sip)
133 if (!sip->epid) {
134 gchar *self_sip_uri = sip_uri_self(sip);
135 sip->epid = sipe_get_epid(self_sip_uri,
136 g_get_host_name(),
137 sipe_backend_network_ip_address());
138 g_free(self_sip_uri);
140 return g_strdup(sip->epid);
143 guint
144 sipe_get_pub_instance(struct sipe_account_data *sip,
145 int publication_key)
147 unsigned res = 0;
148 gchar *epid = get_epid(sip);
150 sscanf(epid, "%08x", &res);
151 g_free(epid);
153 if (publication_key == SIPE_PUB_DEVICE) {
154 /* as is */
155 } else if (publication_key == SIPE_PUB_STATE_MACHINE) { /* First hexadecimal digit is 0x3 */
156 res = (res >> 4) | 0x30000000;
157 } else if (publication_key == SIPE_PUB_STATE_USER) {
158 res = 0x20000000; /* fixed */
159 } else if (publication_key == SIPE_PUB_STATE_CALENDAR) { /* First hexadecimal digit is 0x4 */
160 res = (res >> 4) | 0x40000000;
161 } else if (publication_key == SIPE_PUB_STATE_CALENDAR_OOF) { /* First hexadecimal digit is 0x5 */
162 res = (res >> 4) | 0x50000000;
163 } else if (publication_key == SIPE_PUB_CALENDAR_DATA ||
164 publication_key == SIPE_PUB_NOTE_OOF)
165 { /* First hexadecimal digit is 0x4 */
166 unsigned calendar_id = 0;
167 char *mail_hash = sipe_get_epid(sip->email, "", "");
169 sscanf(mail_hash, "%08x", &calendar_id);
170 g_free(mail_hash);
171 res = (calendar_id >> 4) | 0x40000000;
174 return res;
176 /* an old version
177 guint
178 sipe_get_pub_instance_(struct sipe_account_data *sip,
179 const char *publication_key)
181 unsigned part_1;
182 unsigned part_2;
183 gchar *epid = get_epid(sip);
184 sscanf(epid, "%08x", &part_1);
185 g_free(epid);
186 sscanf(publication_key, "%uh", &part_2);
187 return part_1 + part_2;
190 gboolean
191 sipe_is_bad_alias(const char *uri,
192 const char *alias)
194 char *uri_alias;
195 gboolean result = FALSE;
197 if (!uri) return FALSE;
198 if (!alias) return TRUE;
200 if (g_str_has_prefix(alias, "sip:") || g_str_has_prefix(alias, "sips:")) return TRUE;
202 /* check if alias is just SIP URI but without 'sip:' prefix */
203 uri_alias = sip_uri_from_name(alias);
204 if (sipe_strcase_equal(uri, uri_alias)) {
205 result = TRUE;
207 g_free(uri_alias);
209 return result;
212 gboolean
213 is_empty(const char *st)
215 if (!st || strlen(st) == 0)
217 return TRUE;
219 /* suspecious leading or trailing staces */
220 else if (isspace((unsigned char) *st) ||
221 isspace((unsigned char) *(st + strlen(st) - 1)))
223 /* to not modify original string */
224 char *dup = g_strdup(st);
225 if (strlen(g_strstrip(dup)) == 0) {
226 g_free(dup);
227 return TRUE;
229 g_free(dup);
231 return FALSE;
234 /** Returns newly allocated string. Must be g_free()'d */
235 char *
236 replace(const char *st,
237 const char *search,
238 const char *replace)
240 char **tmp;
241 char *res;
243 if (!st) return NULL;
245 res = g_strjoinv(replace, tmp = g_strsplit(st, search, -1));
246 g_strfreev(tmp);
247 return res;
250 char *
251 fix_newlines(const char *st)
253 return replace(st, "\r\n", "\n");
256 gboolean
257 sipe_strequal(const gchar *left, const gchar *right)
259 #if GLIB_CHECK_VERSION(2,16,0)
260 return (g_strcmp0(left, right) == 0);
261 #else
262 return ((left == NULL && right == NULL) ||
263 (left != NULL && right != NULL && strcmp(left, right) == 0));
264 #endif
267 gboolean
268 sipe_strcase_equal(const gchar *left, const gchar *right)
270 return ((left == NULL && right == NULL) ||
271 (left != NULL && right != NULL && g_ascii_strcasecmp(left, right) == 0));
274 time_t
275 sipe_utils_str_to_time(const gchar *timestamp)
277 GTimeVal time;
278 g_time_val_from_iso8601(timestamp, &time);
279 return time.tv_sec;
282 gchar *
283 sipe_utils_time_to_str(time_t timestamp)
285 GTimeVal time = { timestamp, 0 };
286 return g_time_val_to_iso8601(&time);
289 size_t
290 hex_str_to_buff(const char *hex_str, guint8 **buff)
292 char two_digits[3];
293 size_t length;
294 size_t i;
296 if (!buff) return 0;
297 if (!hex_str) return 0;
299 length = strlen(hex_str)/2;
300 *buff = (unsigned char *)g_malloc(length);
301 for (i = 0; i < length; i++) {
302 two_digits[0] = hex_str[i * 2];
303 two_digits[1] = hex_str[i * 2 + 1];
304 two_digits[2] = '\0';
305 (*buff)[i] = (unsigned char)strtoul(two_digits, NULL, 16);
308 return length;
311 char *
312 buff_to_hex_str(const guint8 *buff, const size_t buff_len)
314 char *res;
315 size_t i, j;
317 if (!buff) return NULL;
319 res = g_malloc(buff_len * 2 + 1);
320 for (i = 0, j = 0; i < buff_len; i++, j+=2) {
321 sprintf(&res[j], "%02X", buff[i]);
323 res[j] = '\0';
324 return res;
327 gboolean
328 sipe_utils_parse_lines(GSList **list, gchar **lines, gchar *delimiter)
330 int i;
331 gchar **parts;
332 gchar *dummy;
333 gchar *dummy2;
334 gchar *tmp;
336 for(i = 0; lines[i] && strlen(lines[i]) > 2; i++) {
337 parts = g_strsplit(lines[i], delimiter, 2);
338 if(!parts[0] || !parts[1]) {
339 g_strfreev(parts);
340 return FALSE;
342 dummy = parts[1];
343 dummy2 = 0;
344 while(*dummy==' ' || *dummy=='\t') dummy++;
345 dummy2 = g_strdup(dummy);
346 while(lines[i+1] && (lines[i+1][0]==' ' || lines[i+1][0]=='\t')) {
347 i++;
348 dummy = lines[i];
349 while(*dummy==' ' || *dummy=='\t') dummy++;
350 tmp = g_strdup_printf("%s %s",dummy2, dummy);
351 g_free(dummy2);
352 dummy2 = tmp;
354 *list = sipe_utils_nameval_add(*list, parts[0], dummy2);
355 g_free(dummy2);
356 g_strfreev(parts);
359 return TRUE;
362 GSList*
363 sipe_utils_nameval_add(GSList* list, const gchar *name, const gchar *value)
365 struct sipnameval *element = g_new0(struct sipnameval,1);
367 /* SANITY CHECK: the calling code must be fixed if this happens! */
368 if (!value) {
369 SIPE_DEBUG_ERROR("sipe_utils_nameval_add: NULL value for %s",
370 name);
371 value = "";
374 element->name = g_strdup(name);
375 element->value = g_strdup(value);
376 return g_slist_append(list, element);
379 void
380 sipe_utils_nameval_free(GSList *list) {
381 struct sipnameval *elem;
382 while(list) {
383 elem = list->data;
384 list = g_slist_remove(list,elem);
385 g_free(elem->name);
386 g_free(elem->value);
387 g_free(elem);
391 const gchar *
392 sipe_utils_nameval_find(const GSList *list, const gchar *name)
394 return sipe_utils_nameval_find_instance (list, name, 0);
397 const gchar *
398 sipe_utils_nameval_find_instance(const GSList *list, const gchar *name, int which)
400 const GSList *tmp;
401 struct sipnameval *elem;
402 int i = 0;
403 tmp = list;
404 while(tmp) {
405 elem = tmp->data;
406 // OCS2005 can send the same header in either all caps or mixed case
407 if (sipe_strcase_equal(elem->name, name)) {
408 if (i == which) {
409 return elem->value;
411 i++;
413 tmp = g_slist_next(tmp);
415 return NULL;
418 gchar *sipe_utils_str_replace(const gchar *string,
419 const gchar *delimiter,
420 const gchar *replacement)
422 gchar **split;
423 gchar *result;
425 if (!string || !delimiter || !replacement) return NULL;
427 split = g_strsplit(string, delimiter, 0);
428 result = g_strjoinv(replacement, split);
429 g_strfreev(split);
431 return result;
434 void sipe_utils_shrink_buffer(struct sipe_transport_connection *conn,
435 const gchar *unread)
437 conn->buffer_used -= unread - conn->buffer;
438 /* string terminator is not included in buffer_used */
439 memmove(conn->buffer, unread, conn->buffer_used + 1);
443 * Calling sizeof(struct ifreq) isn't always correct on
444 * Mac OS X (and maybe others).
446 #ifdef _SIZEOF_ADDR_IFREQ
447 # define HX_SIZE_OF_IFREQ(a) _SIZEOF_ADDR_IFREQ(a)
448 #else
449 # define HX_SIZE_OF_IFREQ(a) sizeof(a)
450 #endif
452 const char * sipe_utils_get_suitable_local_ip(int fd)
454 int source = (fd >= 0) ? fd : socket(PF_INET,SOCK_STREAM, 0);
456 if (source >= 0) {
457 char buffer[1024];
458 static char ip[16];
459 char *tmp;
460 struct ifconf ifc;
461 guint32 lhost = htonl(127 * 256 * 256 * 256 + 1);
462 guint32 llocal = htonl((169 << 24) + (254 << 16));
464 ifc.ifc_len = sizeof(buffer);
465 ifc.ifc_req = (struct ifreq *)buffer;
466 ioctl(source, SIOCGIFCONF, &ifc);
468 if (fd < 0)
469 close(source);
471 tmp = buffer;
472 while (tmp < buffer + ifc.ifc_len)
474 struct ifreq *ifr = (struct ifreq *)tmp;
475 tmp += HX_SIZE_OF_IFREQ(*ifr);
477 if (ifr->ifr_addr.sa_family == AF_INET)
479 struct sockaddr_in *sinptr = (struct sockaddr_in *)&ifr->ifr_addr;
480 if (sinptr->sin_addr.s_addr != lhost
481 && (sinptr->sin_addr.s_addr & htonl(0xFFFF0000)) != llocal)
483 long unsigned int add = ntohl(sinptr->sin_addr.s_addr);
484 g_snprintf(ip, 16, "%lu.%lu.%lu.%lu",
485 ((add >> 24) & 255),
486 ((add >> 16) & 255),
487 ((add >> 8) & 255),
488 add & 255);
490 return ip;
496 return "0.0.0.0";
500 Local Variables:
501 mode: c
502 c-file-style: "bsd"
503 indent-tabs-mode: t
504 tab-width: 8
505 End: