6 * Copyright (C) 2009-2011 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
33 #include "win32/libc_interface.h"
36 #if defined(__APPLE__) || defined(__FreeBSD__)
37 #include <sys/socket.h>
38 #elif defined(__sun__)
39 #include <sys/sockio.h>
43 #include <sys/types.h>
44 #include <sys/ioctl.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
49 #include "sipe-backend.h"
50 #include "sipe-core.h" /* to ensure same API for backends */
51 #include "sipe-core-private.h"
52 #include "sipe-utils.h"
56 /* Generate 32 random bits */
57 #define RANDOM32BITS (rand() & 0xFFFF)
59 gchar
*gencallid(void)
61 return g_strdup_printf("%04Xg%04Xa%04Xi%04Xm%04Xt%04Xb%04Xx%04Xx",
62 RANDOM32BITS
, RANDOM32BITS
, RANDOM32BITS
,
63 RANDOM32BITS
, RANDOM32BITS
, RANDOM32BITS
,
64 RANDOM32BITS
, RANDOM32BITS
);
69 return g_strdup_printf("%04d%04d", RANDOM32BITS
, RANDOM32BITS
);
72 gchar
*genconfid(void)
74 return g_strdup_printf("%04X%04X%04X%04X%04X%04X%04X%04X",
75 RANDOM32BITS
, RANDOM32BITS
, RANDOM32BITS
,
76 RANDOM32BITS
, RANDOM32BITS
, RANDOM32BITS
,
77 RANDOM32BITS
, RANDOM32BITS
);
80 gchar
*get_contact(const struct sipe_core_private
*sipe_private
)
82 return g_strdup(sipe_private
->contact
);
85 gchar
*parse_from(const gchar
*hdr
)
88 const gchar
*tmp
, *tmp2
= hdr
;
90 if (!hdr
) return NULL
;
91 SIPE_DEBUG_INFO("parsing address out of %s", hdr
);
92 tmp
= strchr(hdr
, '<');
94 /* i hate the different SIP UA behaviours... */
95 if (tmp
) { /* sip address in <...> */
97 tmp
= strchr(tmp2
, '>');
99 from
= g_strndup(tmp2
, tmp
- tmp2
);
101 SIPE_DEBUG_INFO_NOFORMAT("found < without > in From");
105 tmp
= strchr(tmp2
, ';');
107 from
= g_strndup(tmp2
, tmp
- tmp2
);
109 from
= g_strdup(tmp2
);
112 SIPE_DEBUG_INFO("got %s", from
);
116 gchar
*sip_uri_from_name(const gchar
*name
)
118 return(g_strdup_printf("sip:%s", name
));
121 gchar
*sip_uri(const gchar
*string
)
123 return(strstr(string
, "sip:") ? g_strdup(string
) : sip_uri_from_name(string
));
127 get_epid(struct sipe_core_private
*sipe_private
)
129 if (!sipe_private
->epid
) {
130 gchar
*self_sip_uri
= sip_uri_self(sipe_private
);
131 sipe_private
->epid
= sipe_get_epid(self_sip_uri
,
133 sipe_backend_network_ip_address());
134 g_free(self_sip_uri
);
136 return g_strdup(sipe_private
->epid
);
140 sipe_get_pub_instance(struct sipe_core_private
*sipe_private
,
144 gchar
*epid
= get_epid(sipe_private
);
146 sscanf(epid
, "%08x", &res
);
149 if (publication_key
== SIPE_PUB_DEVICE
) {
151 } else if (publication_key
== SIPE_PUB_STATE_MACHINE
) { /* First hexadecimal digit is 0x3 */
152 res
= (res
>> 4) | 0x30000000;
153 } else if (publication_key
== SIPE_PUB_STATE_USER
) {
154 res
= 0x20000000; /* fixed */
155 } else if (publication_key
== SIPE_PUB_STATE_CALENDAR
) { /* First hexadecimal digit is 0x4 */
156 res
= (res
>> 4) | 0x40000000;
157 } else if (publication_key
== SIPE_PUB_STATE_CALENDAR_OOF
) { /* First hexadecimal digit is 0x5 */
158 res
= (res
>> 4) | 0x50000000;
159 } else if (publication_key
== SIPE_PUB_CALENDAR_DATA
||
160 publication_key
== SIPE_PUB_NOTE_OOF
)
161 { /* First hexadecimal digit is 0x4 */
162 unsigned calendar_id
= 0;
163 char *mail_hash
= sipe_get_epid(SIPE_ACCOUNT_DATA_PRIVATE
->email
, "", "");
165 sscanf(mail_hash
, "%08x", &calendar_id
);
167 res
= (calendar_id
>> 4) | 0x40000000;
174 sipe_is_bad_alias(const char *uri
,
178 gboolean result
= FALSE
;
180 if (!uri
) return FALSE
;
181 if (!alias
) return TRUE
;
183 if (g_str_has_prefix(alias
, "sip:") || g_str_has_prefix(alias
, "sips:")) return TRUE
;
185 /* check if alias is just SIP URI but without 'sip:' prefix */
186 uri_alias
= sip_uri_from_name(alias
);
187 if (sipe_strcase_equal(uri
, uri_alias
)) {
196 is_empty(const char *st
)
198 if (!st
|| strlen(st
) == 0)
202 /* suspecious leading or trailing staces */
203 else if (isspace((unsigned char) *st
) ||
204 isspace((unsigned char) *(st
+ strlen(st
) - 1)))
206 /* to not modify original string */
207 char *dup
= g_strdup(st
);
208 if (strlen(g_strstrip(dup
)) == 0) {
217 /** Returns newly allocated string. Must be g_free()'d */
219 replace(const char *st
,
226 if (!st
) return NULL
;
228 res
= g_strjoinv(replace
, tmp
= g_strsplit(st
, search
, -1));
233 void sipe_utils_message_debug(const gchar
*type
,
238 if (sipe_backend_debug_enabled()) {
239 GString
*str
= g_string_new("");
242 const char *marker
= sending
?
247 g_get_current_time(&currtime
);
248 time_str
= g_time_val_to_iso8601(&currtime
);
249 g_string_append_printf(str
, "\nMESSAGE START %s %s - %s\n", marker
, type
, time_str
);
250 g_string_append(str
, tmp
= replace(header
, "\r\n", "\n"));
252 g_string_append(str
, "\n");
254 g_string_append(str
, tmp
= replace(body
, "\r\n", "\n"));
256 g_string_append(str
, "\n");
258 g_string_append_printf(str
, "MESSAGE END %s %s - %s", marker
, type
, time_str
);
260 SIPE_DEBUG_INFO_NOFORMAT(str
->str
);
261 g_string_free(str
, TRUE
);
266 sipe_strequal(const gchar
*left
, const gchar
*right
)
268 #if GLIB_CHECK_VERSION(2,16,0)
269 return (g_strcmp0(left
, right
) == 0);
271 return ((left
== NULL
&& right
== NULL
) ||
272 (left
!= NULL
&& right
!= NULL
&& strcmp(left
, right
) == 0));
277 sipe_strcase_equal(const gchar
*left
, const gchar
*right
)
279 return ((left
== NULL
&& right
== NULL
) ||
280 (left
!= NULL
&& right
!= NULL
&& g_ascii_strcasecmp(left
, right
) == 0));
283 gint
sipe_strcompare(gconstpointer a
, gconstpointer b
)
285 #if GLIB_CHECK_VERSION(2,16,0)
286 return (g_strcmp0(a
, b
));
297 sipe_utils_str_to_time(const gchar
*timestamp
)
302 /* We have to make sure that the ISO8601 contains a time zone offset,
303 otherwise the time is interpreted as local time, not UTC!
304 @TODO: is there a better way to check this? */
305 if (timestamp
&& (len
= strlen(timestamp
) > 0) &&
306 isdigit(timestamp
[len
- 1])) {
307 gchar
*tmp
= g_strdup_printf("%sZ", timestamp
);
308 g_time_val_from_iso8601(tmp
, &time
);
311 g_time_val_from_iso8601(timestamp
, &time
);
317 sipe_utils_time_to_str(time_t timestamp
)
319 GTimeVal time
= { timestamp
, 0 };
320 return g_time_val_to_iso8601(&time
);
324 hex_str_to_buff(const char *hex_str
, guint8
**buff
)
331 if (!hex_str
) return 0;
333 length
= strlen(hex_str
)/2;
334 *buff
= (unsigned char *)g_malloc(length
);
335 for (i
= 0; i
< length
; i
++) {
336 two_digits
[0] = hex_str
[i
* 2];
337 two_digits
[1] = hex_str
[i
* 2 + 1];
338 two_digits
[2] = '\0';
339 (*buff
)[i
] = (unsigned char)strtoul(two_digits
, NULL
, 16);
346 buff_to_hex_str(const guint8
*buff
, const size_t buff_len
)
351 if (!buff
) return NULL
;
353 res
= g_malloc(buff_len
* 2 + 1);
354 for (i
= 0, j
= 0; i
< buff_len
; i
++, j
+=2) {
355 sprintf(&res
[j
], "%02X", buff
[i
]);
362 sipe_utils_parse_lines(GSList
**list
, gchar
**lines
, gchar
*delimiter
)
370 for(i
= 0; lines
[i
] && strlen(lines
[i
]) > 2; i
++) {
371 parts
= g_strsplit(lines
[i
], delimiter
, 2);
372 if(!parts
[0] || !parts
[1]) {
378 while(*dummy
==' ' || *dummy
=='\t') dummy
++;
379 dummy2
= g_strdup(dummy
);
380 while(lines
[i
+1] && (lines
[i
+1][0]==' ' || lines
[i
+1][0]=='\t')) {
383 while(*dummy
==' ' || *dummy
=='\t') dummy
++;
384 tmp
= g_strdup_printf("%s %s",dummy2
, dummy
);
388 *list
= sipe_utils_nameval_add(*list
, parts
[0], dummy2
);
397 sipe_utils_nameval_add(GSList
* list
, const gchar
*name
, const gchar
*value
)
399 struct sipnameval
*element
= g_new0(struct sipnameval
,1);
401 /* SANITY CHECK: the calling code must be fixed if this happens! */
403 SIPE_DEBUG_ERROR("sipe_utils_nameval_add: NULL value for %s",
408 element
->name
= g_strdup(name
);
409 element
->value
= g_strdup(value
);
410 return g_slist_append(list
, element
);
414 sipe_utils_nameval_free(GSList
*list
) {
415 struct sipnameval
*elem
;
418 list
= g_slist_remove(list
,elem
);
426 sipe_utils_nameval_find(const GSList
*list
, const gchar
*name
)
428 return sipe_utils_nameval_find_instance (list
, name
, 0);
432 sipe_utils_nameval_find_instance(const GSList
*list
, const gchar
*name
, int which
)
435 struct sipnameval
*elem
;
440 // OCS2005 can send the same header in either all caps or mixed case
441 if (sipe_strcase_equal(elem
->name
, name
)) {
447 tmp
= g_slist_next(tmp
);
452 gchar
*sipe_utils_str_replace(const gchar
*string
,
453 const gchar
*delimiter
,
454 const gchar
*replacement
)
459 if (!string
|| !delimiter
|| !replacement
) return NULL
;
461 split
= g_strsplit(string
, delimiter
, 0);
462 result
= g_strjoinv(replacement
, split
);
468 void sipe_utils_shrink_buffer(struct sipe_transport_connection
*conn
,
471 conn
->buffer_used
-= unread
- conn
->buffer
;
472 /* string terminator is not included in buffer_used */
473 memmove(conn
->buffer
, unread
, conn
->buffer_used
+ 1);
477 * Calling sizeof(struct ifreq) isn't always correct on
478 * Mac OS X (and maybe others).
480 #ifdef _SIZEOF_ADDR_IFREQ
481 # define HX_SIZE_OF_IFREQ(a) _SIZEOF_ADDR_IFREQ(a)
483 # define HX_SIZE_OF_IFREQ(a) sizeof(a)
488 const char * sipe_utils_get_suitable_local_ip(int fd
)
490 int source
= (fd
>= 0) ? fd
: socket(PF_INET
,SOCK_STREAM
, 0);
493 struct ifreq
*buffer
= g_new0(struct ifreq
, IFREQ_MAX
);
495 guint32 lhost
= htonl(127 * 256 * 256 * 256 + 1);
496 guint32 llocal
= htonl((169 << 24) + (254 << 16));
500 ifc
.ifc_len
= sizeof(struct ifreq
) * IFREQ_MAX
;
501 ifc
.ifc_req
= buffer
;
502 ioctl(source
, SIOCGIFCONF
, &ifc
);
507 for (i
= 0; i
< IFREQ_MAX
; i
++)
509 struct ifreq
*ifr
= &buffer
[i
];
511 if (ifr
->ifr_addr
.sa_family
== AF_INET
)
513 struct sockaddr_in sin
;
514 memcpy(&sin
, &ifr
->ifr_addr
, sizeof(struct sockaddr_in
));
515 if (sin
.sin_addr
.s_addr
!= lhost
516 && (sin
.sin_addr
.s_addr
& htonl(0xFFFF0000)) != llocal
)
518 long unsigned int add
= ntohl(sin
.sin_addr
.s_addr
);
519 g_snprintf(ip
, 16, "%lu.%lu.%lu.%lu",
536 gboolean
sipe_utils_ip_is_private(const char *ip
)
538 return g_str_has_prefix(ip
, "10.") ||
539 g_str_has_prefix(ip
, "172.16.") ||
540 g_str_has_prefix(ip
, "192.168.");
543 gchar
*sipe_utils_presence_key(const gchar
*uri
)
545 return g_strdup_printf("<presence><%s>", uri
);
548 gchar
*sipe_utils_subscription_key(const gchar
*event
,
553 if (!is_empty(event
)) {
554 if (!g_ascii_strcasecmp(event
, "presence")) {
555 /* Subscription is identified by <presence><uri> key */
556 key
= sipe_utils_presence_key(uri
);
558 /* Subscription is identified by <event> key */
559 key
= g_strdup_printf("<%s>", event
);