]> sjero.net Git - linphone/blob - linphone/coreapi/proxy.c
b836feb53fc0dce0cacfb87d24756e3acd48f2e4
[linphone] / linphone / coreapi / proxy.c
1 /*
2 linphone
3 Copyright (C) 2000  Simon MORLAT (simon.morlat@linphone.org)
4 */
5 /*
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20  
21 #include "linphonecore.h"
22 #include "sipsetup.h"
23 #include <eXosip2/eXosip.h>
24 #include <osipparser2/osip_message.h>
25 #include "lpconfig.h"
26 #include "private.h"
27
28
29 #include <ctype.h>
30
31
32 void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
33         MSList *elem;
34         int i;
35         for(elem=lc->sip_conf.proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){
36                 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
37                 linphone_proxy_config_write_to_config_file(lc->config,cfg,i);
38         }
39 }
40
41 void linphone_proxy_config_init(LinphoneProxyConfig *obj){
42         memset(obj,0,sizeof(LinphoneProxyConfig));
43         obj->rid=-1;
44         obj->expires=3600;
45 }
46
47 /**
48  * @addtogroup proxies
49  * @{
50 **/
51
52 /**
53  * Creates an empty proxy config.
54 **/
55 LinphoneProxyConfig *linphone_proxy_config_new(){
56         LinphoneProxyConfig *obj=NULL;
57         obj=ms_new(LinphoneProxyConfig,1);
58         linphone_proxy_config_init(obj);
59         return obj;
60 }
61
62 /**
63  * Destroys a proxy config.
64  * 
65  * @note: LinphoneProxyConfig that have been removed from LinphoneCore with
66  * linphone_core_remove_proxy_config() must not be freed.
67 **/
68 void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){
69         if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy);
70         if (obj->reg_identity!=NULL) ms_free(obj->reg_identity);
71         if (obj->reg_route!=NULL) ms_free(obj->reg_route);
72         if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx);
73         if (obj->realm!=NULL) ms_free(obj->realm);
74         if (obj->type!=NULL) ms_free(obj->type);
75         if (obj->contact_addr!=NULL) ms_free(obj->contact_addr);
76         if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix);
77 }
78
79 /**
80  * Returns a boolean indicating that the user is sucessfully registered on the proxy.
81 **/
82 bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){
83         return obj->registered;
84 }
85
86 void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port){
87         if (cfg->registered){
88                 *ip=cfg->contact_addr;
89                 *port=cfg->contact_port;
90         }else{
91                 *ip=NULL;
92                 *port=0;
93         }
94 }
95
96 static void update_contact(LinphoneProxyConfig *cfg, const char *ip, const char *port){
97         if (cfg->contact_addr){
98                 ms_free(cfg->contact_addr);
99         }
100         cfg->contact_addr=ms_strdup(ip);
101         if (port!=NULL)
102                 cfg->contact_port=atoi(port);
103         else cfg->contact_port=5060;
104 }
105
106 bool_t linphone_proxy_config_register_again_with_updated_contact(LinphoneProxyConfig *obj, osip_message_t *orig_request, osip_message_t *last_answer){
107         osip_message_t *msg;
108         const char *rport,*received;
109         osip_via_t *via=NULL;
110         osip_generic_param_t *param=NULL;
111         osip_contact_t *ctt=NULL;
112         osip_message_get_via(last_answer,0,&via);
113         if (!via) return FALSE;
114         osip_via_param_get_byname(via,"rport",&param);
115         if (param) rport=param->gvalue;
116         else return FALSE;
117         param=NULL;
118         osip_via_param_get_byname(via,"received",&param);
119         if (param) received=param->gvalue;
120         else return FALSE;
121         osip_message_get_contact(orig_request,0,&ctt);
122         if (strcmp(ctt->url->host,received)==0){
123                 /*ip address matches, check ports*/
124                 const char *contact_port=ctt->url->port;
125                 const char *via_rport=rport;
126                 if (via_rport==NULL || strlen(via_rport)>0)
127                         via_rport="5060";
128                 if (contact_port==NULL || strlen(contact_port)>0)
129                         contact_port="5060";
130                 if (strcmp(contact_port,via_rport)==0){
131                         ms_message("Register has up to date contact, doing nothing.");
132                         return FALSE;
133                 }else ms_message("ports do not match, need to update the register (%s <> %s)", contact_port,via_rport);
134         }
135         eXosip_lock();
136         msg=NULL;
137         eXosip_register_build_register(obj->rid,obj->expires,&msg);
138         if (msg==NULL){
139                 eXosip_unlock();
140                 ms_warning("Fail to create a contact updated register.");
141                 return FALSE;
142         }
143         osip_message_get_contact(msg,0,&ctt);
144         if (ctt->url->host!=NULL){
145                 osip_free(ctt->url->host);
146         }
147         ctt->url->host=osip_strdup(received);
148         if (ctt->url->port!=NULL){
149                 osip_free(ctt->url->port);
150         }
151         ctt->url->port=osip_strdup(rport);
152         eXosip_register_send_register(obj->rid,msg);
153         eXosip_unlock();
154         update_contact(obj,received,rport);
155         ms_message("Resending new register with updated contact %s:%s",received,rport);
156         return TRUE;
157 }
158
159 /**
160  * Sets the proxy address
161  *
162  * Examples of valid sip proxy address are:
163  * - IP address: sip:87.98.157.38
164  * - IP address with port: sip:87.98.157.38:5062
165  * - hostnames : sip:sip.example.net
166 **/
167 int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){
168         int err;
169         osip_from_t *url;
170         if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy);
171         obj->reg_proxy=NULL;
172         if (server_addr!=NULL && strlen(server_addr)>0){
173                 osip_from_init(&url);
174                 err=osip_from_parse(url,server_addr);
175                 if (err==0 && url->url->host!=NULL){
176                         obj->reg_proxy=ms_strdup(server_addr);
177                 }else{
178                         ms_warning("Could not parse %s",server_addr);
179                 }
180                 osip_from_free(url);
181         }
182         return 0;
183 }
184
185 /**
186  * Sets the user identity as a SIP address.
187  *
188  * This identity is normally formed with display name, username and domain, such 
189  * as:
190  * Alice <sip:alice@example.net>
191  * The REGISTER messages will have from and to set to this identity.
192  *
193 **/
194 void linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity){
195         int err=0;
196         osip_from_t *url=NULL;
197         if (identity!=NULL && strlen(identity)>0){
198                 osip_from_init(&url);
199                 err=osip_from_parse(url,identity);
200                 if (err<0 || url->url->host==NULL || url->url->username==NULL){
201                         ms_warning("Could not parse %s",identity);
202                         osip_from_free(url);
203                         return;
204                 }
205         } else err=-2;
206         if (obj->reg_identity!=NULL) {
207                 ms_free(obj->reg_identity);
208                 obj->reg_identity=NULL;
209         }
210         if (err==-2) obj->reg_identity=NULL;
211         else {
212                 obj->reg_identity=ms_strdup(identity);
213                 if (obj->realm)
214                         ms_free(obj->realm);
215                 obj->realm=ms_strdup(url->url->host);
216         }
217         if (url) osip_from_free(url);
218 }
219
220 const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){
221         return cfg->realm;
222 }
223
224 /**
225  * Sets a SIP route.
226  * When a route is set, all outgoing calls will go to the route's destination if this proxy
227  * is the default one (see linphone_core_set_default_proxy() ).
228 **/
229 void linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route)
230 {
231         int err;
232         osip_uri_param_t *lr_param=NULL;
233         osip_route_t *rt=NULL;
234         char *tmproute=NULL;
235         if (route!=NULL && strlen(route)>0){
236                 osip_route_init(&rt);
237                 err=osip_route_parse(rt,route);
238                 if (err<0){
239                         ms_warning("Could not parse %s",route);
240                         osip_route_free(rt);
241                         return ;
242                 }
243                 if (obj->reg_route!=NULL) {
244                         ms_free(obj->reg_route);
245                         obj->reg_route=NULL;
246                 }
247                         
248                 /* check if the lr parameter is set , if not add it */
249                 osip_uri_uparam_get_byname(rt->url, "lr", &lr_param);
250                 if (lr_param==NULL){
251                         osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL);
252                         osip_route_to_str(rt,&tmproute);
253                         obj->reg_route=ms_strdup(tmproute);
254                         osip_free(tmproute);
255                 }else obj->reg_route=ms_strdup(route);
256         }else{
257                 if (obj->reg_route!=NULL) ms_free(obj->reg_route);
258                 obj->reg_route=NULL;
259         }
260 }
261
262 bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *obj){
263         if (obj->reg_proxy==NULL){
264                 if (lc->vtable.display_warning)
265                         lc->vtable.display_warning(lc,_("The sip proxy address you entered is invalid, it must start with \"sip:\""
266                                                 " followed by a hostname."));
267                 return FALSE;
268         }
269         if (obj->reg_identity==NULL){
270                 if (lc->vtable.display_warning)
271                         lc->vtable.display_warning(lc,_("The sip identity you entered is invalid.\nIt should look like "
272                                         "sip:username@proxydomain, such as sip:alice@example.net"));
273                 return FALSE;
274         }
275         return TRUE;
276 }
277
278 /**
279  * Indicates whether a REGISTER request must be sent to the proxy.
280 **/
281 void linphone_proxy_config_enableregister(LinphoneProxyConfig *obj, bool_t val){
282         obj->reg_sendregister=val;
283 }
284
285 /**
286  * Sets the registration expiration time in seconds.
287 **/
288 void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int val){
289         if (val<=0) val=600;
290         obj->expires=val;
291 }
292
293 void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){
294         obj->publish=val;
295 }
296
297 /**
298  * Starts editing a proxy configuration.
299  *
300  * Because proxy configuration must be consistent, applications MUST
301  * call linphone_proxy_config_edit() before doing any attempts to modify
302  * proxy configuration (such as identity, proxy address and so on).
303  * Once the modifications are done, then the application must call
304  * linphone_proxy_config_done() to commit the changes.
305 **/
306 void linphone_proxy_config_edit(LinphoneProxyConfig *obj){
307         obj->auth_failures=0;
308         if (obj->reg_sendregister){
309                 /* unregister */
310                 if (obj->registered) {
311                         osip_message_t *msg;
312                         eXosip_lock();
313                         eXosip_register_build_register(obj->rid,0,&msg);
314                         eXosip_register_send_register(obj->rid,msg);
315                         eXosip_unlock();
316                         obj->registered=FALSE;
317                 }
318         }
319 }
320
321 void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc)
322 {
323         obj->lc=lc;
324         linphone_proxy_config_done(obj);
325 }
326
327 static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
328         const char *id_str;
329         if (obj->reg_identity!=NULL) id_str=obj->reg_identity;
330         else id_str=linphone_core_get_primary_contact(obj->lc);
331         if (obj->reg_sendregister){
332                 char *ct=NULL;
333                 osip_message_t *msg=NULL;
334                 eXosip_lock();
335                 obj->rid=eXosip_register_build_initial_register(id_str,obj->reg_proxy,NULL,obj->expires,&msg);
336                 eXosip_register_send_register(obj->rid,msg);
337                 eXosip_unlock();
338                 if (ct!=NULL) osip_free(ct);
339         }
340 }
341
342
343 /**
344  * Sets a dialing prefix to be automatically prepended when inviting a number with 
345  * #linphone_core_invite.
346  *
347 **/
348 void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix){
349         if (cfg->dial_prefix!=NULL){
350                 ms_free(cfg->dial_prefix);
351                 cfg->dial_prefix=NULL;
352         }
353         if (prefix) cfg->dial_prefix=ms_strdup(prefix);
354 }
355
356 /**
357  * Returns dialing prefix.
358  *
359  * 
360 **/
361 const char *linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg){
362         return cfg->dial_prefix;
363 }
364
365 /**
366  * Sets whether liblinphone should replace "+" by "00" in dialed numbers (passed to
367  * #linphone_core_invite ).
368  *
369 **/
370 void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val){
371         cfg->dial_escape_plus=val;
372 }
373
374 /**
375  * Returns whether liblinphone should replace "+" by "00" in dialed numbers (passed to
376  * #linphone_core_invite ).
377  *
378 **/
379 bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg){
380         return cfg->dial_escape_plus;
381 }
382
383
384 static bool_t is_a_phone_number(const char *username){
385         const char *p;
386         for(p=username;*p!='\0';++p){
387                 if (isdigit(*p) || 
388                     *p==' ' ||
389                     *p=='-' ||
390                     *p==')' ||
391                         *p=='(' ||
392                         *p=='/' ||
393                         *p=='+') continue;
394                 else return FALSE;
395         }
396         return TRUE;
397 }
398
399 static char *flatten_number(const char *number){
400         char *result=ms_malloc0(strlen(number)+1);
401         char *w=result;
402         const char *r;
403         for(r=number;*r!='\0';++r){
404                 if (*r=='+' || isdigit(*r)){
405                         *w++=*r;
406                 }
407         }
408         *w++='\0';
409         return result;
410 }
411
412 static void copy_result(const char *src, char *dest, size_t destlen, bool_t escape_plus){
413         int i=0;
414         
415         if (escape_plus && src[0]=='+' && destlen>2){
416                 dest[0]='0';
417                 dest[1]='0';
418                 src++;
419                 i=2;
420         }
421         
422         for(;i<destlen-1;++i){
423                 dest[i]=*src;
424                 src++;
425         }
426         dest[i]='\0';
427 }
428
429
430 static char *append_prefix(const char *number, const char *prefix){
431         char *res=ms_malloc(strlen(number)+strlen(prefix)+1);
432         strcpy(res,prefix);
433         return strcat(res,number);
434 }
435
436 int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len){
437         char *flatten;
438         int numlen;
439         if (is_a_phone_number(username)){
440                 flatten=flatten_number(username);
441                 ms_message("Flattened number is '%s'",flatten);
442                 numlen=strlen(flatten);
443                 if (numlen>10 || flatten[0]=='+' || proxy->dial_prefix==NULL){
444                         ms_message("No need to add a prefix");
445                         /* prefix is already there */
446                         copy_result(flatten,result,result_len,proxy->dial_escape_plus);
447                         ms_free(flatten);
448                         return 0;
449                 }else if (proxy->dial_prefix){
450                         char *prefixed;
451                         int skipped=0;
452                         ms_message("Need to prefix with %s",proxy->dial_prefix);
453                         if (numlen==10){
454                                 /*remove initial number before prepending prefix*/
455                                 skipped=1;
456                         }
457                         prefixed=append_prefix(flatten+skipped,proxy->dial_prefix);
458                         ms_free(flatten);
459                         copy_result(prefixed,result,result_len,proxy->dial_escape_plus);
460                         ms_free(prefixed);
461                 }
462         }else strncpy(result,username,result_len);
463         return 0;
464 }
465
466 /**
467  * Commits modification made to the proxy configuration.
468 **/
469 int linphone_proxy_config_done(LinphoneProxyConfig *obj)
470 {
471         if (!linphone_proxy_config_check(obj->lc,obj)) return -1;
472         obj->commit=TRUE;
473         linphone_proxy_config_write_all_to_config_file(obj->lc);
474         return 0;
475 }
476
477 void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm)
478 {
479         if (cfg->realm!=NULL) {
480                 ms_free(cfg->realm);
481                 cfg->realm=NULL;
482         }
483         if (realm!=NULL) cfg->realm=ms_strdup(realm);
484 }
485
486 int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy,
487                                LinphoneOnlineStatus presence_mode)
488 {
489   osip_message_t *pub;
490   int i;
491   const char *from=NULL;
492   char buf[5000];
493
494   if (proxy->publish==FALSE) return 0;
495         
496   if (proxy!=NULL) {
497     from=linphone_proxy_config_get_identity(proxy);
498   }
499   if (from==NULL) from=linphone_core_get_primary_contact(proxy->lc);
500
501   if (presence_mode==LINPHONE_STATUS_ONLINE)
502     {
503       snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
504 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
505           entity=\"%s\">\n\
506 <tuple id=\"sg89ae\">\n\
507 <status>\n\
508 <basic>open</basic>\n\
509 </status>\n\
510 <contact priority=\"0.8\">%s</contact>\n\
511 <note>online</note>\n\
512 </tuple>\n\
513 </presence>",
514                from, from);
515     }
516   else if (presence_mode==LINPHONE_STATUS_BUSY
517            ||presence_mode==LINPHONE_STATUS_NOT_DISTURB)
518     {
519       snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
520 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
521           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
522           entity=\"%s\">\n\
523 <tuple id=\"sg89ae\">\n\
524 <status>\n\
525 <basic>open</basic>\n\
526 <es:activities>\n\
527   <es:activity>busy</es:activity>\n\
528 </es:activities>\n\
529 </status>\n\
530 <contact priority=\"0.8\">%s</contact>\n\
531 <note>busy</note>\n\
532 </tuple>\n\
533 </presence>",
534               from, from);
535     }
536   else if (presence_mode==LINPHONE_STATUS_BERIGHTBACK)
537     {
538       snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
539 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
540           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
541           entity=\"%s\">\n\
542 <tuple id=\"sg89ae\">\n\
543 <status>\n\
544 <basic>open</basic>\n\
545 <es:activities>\n\
546   <es:activity>in-transit</es:activity>\n\
547 </es:activities>\n\
548 </status>\n\
549 <contact priority=\"0.8\">%s</contact>\n\
550 <note>be right back</note>\n\
551 </tuple>\n\
552 </presence>",
553               from,from);
554     }
555   else if (presence_mode==LINPHONE_STATUS_AWAY
556            ||presence_mode==LINPHONE_STATUS_MOVED
557            ||presence_mode==LINPHONE_STATUS_ALT_SERVICE)
558     {
559       snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
560 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
561           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
562           entity=\"%s\">\n\
563 <tuple id=\"sg89ae\">\n\
564 <status>\n\
565 <basic>open</basic>\n\
566 <es:activities>\n\
567   <es:activity>away</es:activity>\n\
568 </es:activities>\n\
569 </status>\n\
570 <contact priority=\"0.8\">%s</contact>\n\
571 <note>away</note>\n\
572 </tuple>\n\
573 </presence>",
574               from, from);
575     }
576   else if (presence_mode==LINPHONE_STATUS_ONTHEPHONE)
577     {
578       snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
579 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
580           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
581           entity=\"%s\">\n\
582 <tuple id=\"sg89ae\">\n\
583 <status>\n\
584 <basic>open</basic>\n\
585 <es:activities>\n\
586   <es:activity>on-the-phone</es:activity>\n\
587 </es:activities>\n\
588 </status>\n\
589 <contact priority=\"0.8\">%s</contact>\n\
590 <note>on the phone</note>\n\
591 </tuple>\n\
592 </presence>",
593               from, from);
594     }
595   else if (presence_mode==LINPHONE_STATUS_OUTTOLUNCH)
596     {
597       snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
598 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
599           xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
600           entity=\"%s\">\n\
601 <tuple id=\"sg89ae\">\n\
602 <status>\n\
603 <basic>open</basic>\n\
604 <es:activities>\n\
605   <es:activity>meal</es:activity>\n\
606 </es:activities>\n\
607 </status>\n\
608 <contact priority=\"0.8\">%s</contact>\n\
609 <note>out to lunch</note>\n\
610 </tuple>\n\
611 </presence>",
612               from, from);
613     }
614   else if (presence_mode==LINPHONE_STATUS_OFFLINE)
615     {
616       /* */
617       snprintf(buf, 5000, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
618 <presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
619 xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
620 entity=\"%s\">\n%s",
621               from,
622 "<tuple id=\"sg89ae\">\n\
623 <status>\n\
624 <basic>closed</basic>\n\
625 <es:activities>\n\
626   <es:activity>permanent-absence</e:activity>\n\
627 </es:activities>\n\
628 </status>\n\
629 </tuple>\n\
630 \n</presence>\n");
631     }
632
633   i = eXosip_build_publish(&pub, (char *)from, (char *)from, NULL, "presence", "1800", "application/pidf+xml", buf);
634
635   if (i<0)
636     {
637       ms_message("Failed to build publish request.");
638       return -1;
639     }
640
641   eXosip_lock();
642   i = eXosip_publish(pub, from); /* should update the sip-if-match parameter
643                                     from sip-etag  from last 200ok of PUBLISH */
644   eXosip_unlock();
645   if (i<0)
646     {
647       ms_message("Failed to send publish request.");
648       return -1;
649     }
650   return 0;
651 }
652
653
654 /**
655  * Add a proxy configuration.
656  * This will start registration on the proxy, if registration is enabled.
657 **/
658 int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
659         if (!linphone_proxy_config_check(lc,cfg)) return -1;
660         lc->sip_conf.proxies=ms_list_append(lc->sip_conf.proxies,(void *)cfg);
661         linphone_proxy_config_apply(cfg,lc);
662         return 0;
663 }
664
665 extern void linphone_friend_check_for_removed_proxy(LinphoneFriend *lf, LinphoneProxyConfig *cfg);
666
667 /**
668  * Removes a proxy configuration.
669  *
670  * LinphoneCore will then automatically unregister and place the proxy configuration
671  * on a deleted list. For that reason, a removed proxy does NOT need to be freed.
672 **/
673 void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
674         MSList *elem;
675         lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,(void *)cfg);
676         /* add to the list of destroyed proxies, so that the possible unREGISTER request can succeed authentication */
677         lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,(void *)cfg);
678         /* this will unREGISTER */
679         linphone_proxy_config_edit(cfg);
680         if (lc->default_proxy==cfg){
681                 lc->default_proxy=NULL;
682         }
683         /* invalidate all references to this proxy in our friend list */
684         for (elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){
685                 linphone_friend_check_for_removed_proxy((LinphoneFriend*)elem->data,cfg);
686         }
687         
688 }
689 /**
690  * Erase all proxies from config.
691  *
692  * @ingroup proxy
693 **/
694 void linphone_core_clear_proxy_config(LinphoneCore *lc){
695         MSList* list=ms_list_copy(linphone_core_get_proxy_config_list((const LinphoneCore*)lc));
696         for(;list!=NULL;list=list->next){
697                 linphone_core_remove_proxy_config(lc,(LinphoneProxyConfig *)list->data);
698         }
699         ms_list_free(list);
700 }
701 /**
702  * Sets the default proxy.
703  *
704  * This default proxy must be part of the list of already entered LinphoneProxyConfig.
705  * Toggling it as default will make LinphoneCore use the identity associated with
706  * the proxy configuration in all incoming and outgoing calls.
707 **/
708 void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config){
709         /* check if this proxy is in our list */
710         if (config!=NULL){
711                 if (ms_list_find(lc->sip_conf.proxies,config)==NULL){
712                         ms_warning("Bad proxy address: it is not in the list !");
713                         lc->default_proxy=NULL;
714                         return ;
715                 }
716         }
717         lc->default_proxy=config;
718         
719 }       
720
721 void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index){
722         if (index<0) linphone_core_set_default_proxy(lc,NULL);
723         else linphone_core_set_default_proxy(lc,ms_list_nth_data(lc->sip_conf.proxies,index));
724 }
725
726 /**
727  * Returns the default proxy configuration, that is the one used to determine the current identity.
728 **/
729 int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config){
730         int pos=-1;
731         if (config!=NULL) *config=lc->default_proxy;
732         if (lc->default_proxy!=NULL){
733                 pos=ms_list_position(lc->sip_conf.proxies,ms_list_find(lc->sip_conf.proxies,(void *)lc->default_proxy));
734         }
735         return pos;
736 }
737
738 static int rid_compare(const void *pcfg,const void *prid){
739         const LinphoneProxyConfig *cfg=(const LinphoneProxyConfig*)pcfg;
740         const int *rid=(const int*)prid;
741         ms_message("cfg= %s, cfg->rid=%i, rid=%i",cfg->reg_proxy, cfg->rid, *rid);
742         return cfg->rid-(*rid);
743 }
744
745 LinphoneProxyConfig *linphone_core_get_proxy_config_from_rid(LinphoneCore *lc, int rid){
746         MSList *elem=ms_list_find_custom(lc->sip_conf.proxies,rid_compare, &rid);
747         if (elem==NULL){
748                 ms_message("linphone_core_get_proxy_config_from_rid: searching in deleted proxies...");
749                 elem=ms_list_find_custom(lc->sip_conf.deleted_proxies,rid_compare, &rid);
750         }
751         if (elem==NULL) return NULL;
752         else return (LinphoneProxyConfig*)elem->data;
753 }
754
755 /**
756  * Returns an unmodifiable list of entered proxy configurations.
757 **/
758 const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc){
759         return lc->sip_conf.proxies;
760 }
761
762
763 void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, eXosip_event_t *ev){
764         LinphoneProxyConfig *cfg=linphone_core_get_proxy_config_from_rid(lc, ev->rid);
765         if (cfg){
766                 cfg->auth_failures++;
767                 if (strcmp(ev->request->sip_method,"REGISTER")==0) {
768                         gstate_new_state(lc, GSTATE_REG_FAILED, "Authentication failed.");
769                 }
770                 /*restart a new register so that the user gets a chance to be prompted for a password*/
771                 if (cfg->auth_failures==1){
772                         linphone_proxy_config_register(cfg);
773                 }
774         }
775 }
776
777 void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *obj, int index)
778 {
779         char key[50];
780
781         sprintf(key,"proxy_%i",index);
782         lp_config_clean_section(config,key);
783         if (obj==NULL){
784                 return;
785         }
786         if (obj->type!=NULL){
787                 lp_config_set_string(config,key,"type",obj->type);
788         }
789         if (obj->reg_proxy!=NULL){
790                 lp_config_set_string(config,key,"reg_proxy",obj->reg_proxy);
791         }
792         if (obj->reg_route!=NULL){
793                 lp_config_set_string(config,key,"reg_route",obj->reg_route);
794         }
795         if (obj->reg_identity!=NULL){
796                 lp_config_set_string(config,key,"reg_identity",obj->reg_identity);
797         }
798         lp_config_set_int(config,key,"reg_expires",obj->expires);
799         lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister);
800         lp_config_set_int(config,key,"publish",obj->publish);
801         lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus);
802         lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix);
803 }
804
805
806
807 LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config, int index)
808 {
809         const char *tmp;
810         const char *identity;
811         const char *proxy;
812         LinphoneProxyConfig *cfg;
813         char key[50];
814         
815         sprintf(key,"proxy_%i",index);
816
817         if (!lp_config_has_section(config,key)){
818                 return NULL;
819         }
820
821         cfg=linphone_proxy_config_new();
822
823         identity=lp_config_get_string(config,key,"reg_identity",NULL);  
824         proxy=lp_config_get_string(config,key,"reg_proxy",NULL);
825         
826         linphone_proxy_config_set_identity(cfg,identity);
827         linphone_proxy_config_set_server_addr(cfg,proxy);
828         
829         tmp=lp_config_get_string(config,key,"reg_route",NULL);
830         if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp);
831
832         linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",600));
833         linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0));
834         
835         linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0));
836
837         linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",0));
838         linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",NULL));
839         
840         tmp=lp_config_get_string(config,key,"type",NULL);
841         if (tmp!=NULL && strlen(tmp)>0) 
842                 linphone_proxy_config_set_sip_setup(cfg,tmp);
843
844         return cfg;
845 }
846
847 static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){
848         SipSetupContext *ssc;
849         SipSetup *ss=sip_setup_lookup(cfg->type);
850         LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
851         unsigned int caps;
852         if (!ss) return ;
853         ssc=sip_setup_context_new(ss,cfg);
854         cfg->ssctx=ssc;
855         if (cfg->reg_identity==NULL){
856                 ms_error("Invalid identity for this proxy configuration.");
857                 return;
858         }
859         caps=sip_setup_context_get_capabilities(ssc);
860         if (caps & SIP_SETUP_CAP_ACCOUNT_MANAGER){
861                 if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL)!=0){
862                         if (lc->vtable.display_warning){
863                                 char *tmp=ms_strdup_printf(_("Could not login as %s"),cfg->reg_identity);
864                                 lc->vtable.display_warning(lc,tmp);
865                                 ms_free(tmp);
866                         }
867                         return;
868                 }
869         }
870         if (caps & SIP_SETUP_CAP_PROXY_PROVIDER){
871                 char proxy[256];
872                 if (sip_setup_context_get_proxy(ssc,NULL,proxy,sizeof(proxy))==0){
873                         linphone_proxy_config_set_server_addr(cfg,proxy);
874                 }else{
875                         ms_error("Could not retrieve proxy uri !");
876                 }
877         }
878         
879 }
880
881 SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg){
882         if (cfg->ssctx!=NULL) return cfg->ssctx->funcs;
883         if (cfg->type!=NULL){
884                 return sip_setup_lookup(cfg->type);
885         }
886         return NULL;
887 }
888
889 void linphone_proxy_config_update(LinphoneProxyConfig *cfg){
890         if (cfg->commit){
891                 if (cfg->type && cfg->ssctx==NULL){
892                         linphone_proxy_config_activate_sip_setup(cfg);
893                 }
894                 linphone_proxy_config_register(cfg);
895                 cfg->commit=FALSE;
896         }
897 }
898
899 void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type){
900         if (cfg->type)
901                 ms_free(cfg->type);
902         cfg->type=ms_strdup(type);
903         if (linphone_proxy_config_get_addr(cfg)==NULL){
904                 /*put a placeholder so that the sip setup gets saved into the config */
905                 linphone_proxy_config_set_server_addr(cfg,"sip:undefined");
906         }
907 }
908
909 SipSetupContext *linphone_proxy_config_get_sip_setup_context(LinphoneProxyConfig *cfg){
910         return cfg->ssctx;
911 }
912
913 /**
914  * @}
915 **/
916
917 LinphoneAccountCreator *linphone_account_creator_new(struct _LinphoneCore *core, const char *type){
918         LinphoneAccountCreator *obj;
919         LinphoneProxyConfig *cfg;
920         SipSetup *ss=sip_setup_lookup(type);
921         SipSetupContext *ssctx;
922         if (!ss){
923                 return NULL;
924         }
925         if (!(sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_ACCOUNT_MANAGER)){
926                 ms_error("%s cannot manage accounts.");
927                 return NULL;
928         }
929         obj=ms_new0(LinphoneAccountCreator,1);
930         cfg=linphone_proxy_config_new();
931         ssctx=sip_setup_context_new(ss,cfg);
932         obj->lc=core;
933         obj->ssctx=ssctx;
934         set_string(&obj->domain,sip_setup_context_get_domains(ssctx)[0]);
935         cfg->lc=core;
936         return obj;
937 }
938
939 void linphone_account_creator_set_username(LinphoneAccountCreator *obj, const char *username){
940         set_string(&obj->username,username);
941 }
942
943 void linphone_account_creator_set_password(LinphoneAccountCreator *obj, const char *password){
944         set_string(&obj->password,password);
945 }
946
947 void linphone_account_creator_set_domain(LinphoneAccountCreator *obj, const char *domain){
948         set_string(&obj->domain,domain);
949 }
950
951 const char * linphone_account_creator_get_username(LinphoneAccountCreator *obj){
952         return obj->username;
953 }
954
955 const char * linphone_account_creator_get_domain(LinphoneAccountCreator *obj){
956         return obj->domain;
957 }
958
959 int linphone_account_creator_test_existence(LinphoneAccountCreator *obj){
960         SipSetupContext *ssctx=obj->ssctx;
961         char *uri=ms_strdup_printf("%s@%s",obj->username,obj->domain);
962         int err=sip_setup_context_account_exists(ssctx,uri);
963         ms_free(uri);
964         return err;
965 }
966
967 LinphoneProxyConfig * linphone_account_creator_validate(LinphoneAccountCreator *obj){
968         SipSetupContext *ssctx=obj->ssctx;
969         char *uri=ms_strdup_printf("%s@%s",obj->username,obj->domain);
970         int err=sip_setup_context_create_account(ssctx,uri,obj->password);
971         ms_free(uri);
972         if (err==0) {
973                 obj->succeeded=TRUE;
974                 return sip_setup_context_get_proxy_config(ssctx);
975         }
976         return NULL;
977 }
978
979 void linphone_account_creator_destroy(LinphoneAccountCreator *obj){
980         if (obj->username)
981                 ms_free(obj->username);
982         if (obj->password)
983                 ms_free(obj->password);
984         if (obj->domain)
985                 ms_free(obj->domain);
986         if (!obj->succeeded){
987                 linphone_proxy_config_destroy(sip_setup_context_get_proxy_config(obj->ssctx));
988         }
989 }
990
991
992