]> sjero.net Git - linphone/blob - coreapi/sipwizard.c
Wizard
[linphone] / coreapi / sipwizard.c
1 /*
2 linphone
3 Copyright (C) 2011  Simon MORLAT (simon.morlat@linphone.org)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19
20 #include "linphonecore.h"
21 #include "private.h"
22 #include <ctype.h>
23 #include <libsoup/soup.h>
24
25 typedef struct _BLReq{
26         int status;
27         int result;
28         SoupMessage *msg;
29         SoupSession *session;
30         ortp_thread_t th;
31 }BLReq;
32
33 const int XMLRPC_FAILED = -1;
34 const int XMLRPC_OK = 0;
35 const char *XMLRPC_URL = "https://www.linphone.org/wizard.php";
36
37 static void sip_wizard_init_instance(SipSetupContext *ctx){
38         LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx);
39         /*disable registration until the user logs in*/
40         linphone_proxy_config_enable_register(cfg,FALSE);
41 }
42
43 const char ** sip_wizard_get_domains(SipSetupContext *ctx) {
44         LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx);
45         const char **domains = (const char**) &cfg->reg_proxy;
46         return domains;
47 }
48
49 static SoupMessage * build_xmlrpc_check_account_request(const char *identity){
50         SoupMessage * msg;
51
52         msg=soup_xmlrpc_request_new(XMLRPC_URL,
53                                 "check_account",
54                                 G_TYPE_STRING, identity,
55                                 G_TYPE_INVALID);
56         if (!msg){
57                 ms_error("Fail to create SoupMessage !");
58         }else{
59                 SoupBuffer *sb=soup_message_body_flatten(msg->request_body);
60                 ms_message("This is the XML-RPC request we are going to send:\n%s\n",sb->data);
61                 soup_buffer_free(sb);
62         }
63         return msg;
64 }
65
66 static SoupMessage * build_xmlrpc_check_account_validated(const char *identity){
67         SoupMessage * msg;
68
69         msg=soup_xmlrpc_request_new(XMLRPC_URL,
70                                 "check_account_validated",
71                                 G_TYPE_STRING, identity,
72                                 G_TYPE_INVALID);
73         if (!msg){
74                 ms_error("Fail to create SoupMessage !");
75         }else{
76                 SoupBuffer *sb=soup_message_body_flatten(msg->request_body);
77                 ms_message("This is the XML-RPC request we are going to send:\n%s\n",sb->data);
78                 soup_buffer_free(sb);
79         }
80         return msg;
81 }
82
83 static SoupMessage * build_xmlrpc_create_account_request(const char *identity, const char *passwd, const char *email, int suscribe){
84         SoupMessage * msg;
85
86         msg=soup_xmlrpc_request_new(XMLRPC_URL,
87                                 "create_account",
88                                 G_TYPE_STRING, identity,
89                                 G_TYPE_STRING, passwd,
90                                 G_TYPE_STRING, email,
91                                 G_TYPE_INT, suscribe,
92                                 G_TYPE_INVALID);
93         if (!msg){
94                 ms_error("Fail to create SoupMessage !");
95         }else{
96                 SoupBuffer *sb=soup_message_body_flatten(msg->request_body);
97                 ms_message("This is the XML-RPC request we are going to send:\n%s\n",sb->data);
98                 soup_buffer_free(sb);
99         }
100         return msg;
101 }
102
103 static int xml_rpc_parse_response(BLReq *blreq, SoupMessage *sm){
104         SoupBuffer *sb;
105         GValue retval;
106         GError *error=NULL;
107         sb=soup_message_body_flatten(sm->response_body);
108         ms_message("This the xml-rpc response:\n%s\n",sb->data);
109         if (soup_xmlrpc_parse_method_response(sb->data,sb->length,&retval,&error)==FALSE){
110                 if (error!=NULL){
111                         ms_error("xmlrpc fault: %s",error->message);
112                         g_error_free(error);
113                 }else{
114                         ms_error("Could not parse xml-rpc response !");
115                 }
116                 blreq->status=XMLRPC_FAILED;
117         }else{
118                 ms_message("Extracting values from return type...");
119                 blreq->result = g_value_get_int(&retval);
120                 g_value_unset(&retval);
121                 blreq->status=XMLRPC_OK;
122         }
123         soup_buffer_free(sb);
124         return blreq->status;
125 }
126
127 static void got_headers(BLReq *blreq, SoupMessage*msg){
128         ms_message("Got headers !");
129         blreq->status=XMLRPC_OK;
130 }
131
132 #if SERIALIZE_HTTPS
133 /*on windows libsoup support for threads with gnutls is not yet functionnal (only in git)
134 This will come in next release of libsoup, probably.
135 In the meantime, we are forced to serialize all soup https processing with a big
136 ugly global mutex...*/
137
138 static GStaticMutex big_mutex = G_STATIC_MUTEX_INIT;
139 #endif
140
141 static void * process_xml_rpc_request(void *up){
142         BLReq *blreq=(BLReq*)up;
143         SoupMessage *sm=blreq->msg;
144         int code;
145         g_signal_connect_swapped(G_OBJECT(sm),"got-headers",(GCallback)got_headers,blreq);
146         blreq->status=XMLRPC_OK;
147 #if SERIALIZE_HTTPS
148         g_static_mutex_lock(&big_mutex);
149 #endif
150         code=soup_session_send_message(blreq->session,sm);
151         if (code==200){
152                 ms_message("Got a response from server, yeah !");
153                 xml_rpc_parse_response(blreq,sm);
154         }else{
155                 ms_error("request failed, error-code=%i (%s)",code,soup_status_get_phrase(code));
156                 blreq->status=XMLRPC_FAILED;
157         }
158 #if SERIALIZE_HTTPS
159         g_static_mutex_unlock(&big_mutex);
160 #endif
161         return NULL;
162 }
163
164 int sip_wizard_account_exists(SipSetupContext *ctx, const char *uri) {
165         /*
166          * Return 1 if account already exists
167          * 0 if account doesn't exists
168          * -1 if information isn't available
169          */
170         SoupMessage *sm;
171         BLReq *req=ms_new0(BLReq, 1);
172         req->session=soup_session_sync_new();
173         sm=build_xmlrpc_check_account_request(uri);
174         req->msg=sm;
175         process_xml_rpc_request(req);
176
177         if (req->status == XMLRPC_OK) {
178                 return req->result;
179         } else {
180                 return -1;
181         }
182 }
183
184 int sip_wizard_account_validated(SipSetupContext *ctx, const char *uri) {
185         /*
186          * Return 1 if account already exists
187          * 0 if account doesn't exists
188          * -1 if information isn't available
189          */
190         SoupMessage *sm;
191         BLReq *req=ms_new0(BLReq, 1);
192         req->session=soup_session_sync_new();
193         sm=build_xmlrpc_check_account_validated(uri);
194         req->msg=sm;
195         process_xml_rpc_request(req);
196
197         if (req->status == XMLRPC_OK) {
198                 return req->result;
199         } else {
200                 return -1;
201         }
202 }
203
204 int sip_wizard_create_account(SipSetupContext *ctx, const char *uri, const char *passwd, const char *email, int suscribe) {
205         /*
206          * Return 0 if account successfully created
207          * Else return -1
208          */
209         SoupMessage *sm;
210         BLReq *req=ms_new0(BLReq, 1);
211         req->session=soup_session_sync_new();
212         sm=build_xmlrpc_create_account_request(uri, passwd, email, suscribe);
213         req->msg=sm;
214         process_xml_rpc_request(req);
215
216         if (req->status == XMLRPC_OK) {
217                 return req->result;
218         } else {
219                 return -1;
220         }
221 }
222
223 static void guess_display_name(LinphoneAddress *from){
224         char *dn=(char*)ms_malloc(strlen(linphone_address_get_username(from))+3);
225         const char *it;
226         char *wptr=dn;
227         bool_t begin=TRUE;
228         bool_t surname=0;
229         for(it=linphone_address_get_username(from);*it!='\0';++it){
230                 if (begin){
231                         *wptr=toupper(*it);
232                         begin=FALSE;
233                 }else if (*it=='.'){
234                         if (surname) break;
235                         *wptr=' ';
236                         begin=TRUE;
237                         surname=TRUE;
238                 }else *wptr=*it;
239                 wptr++;
240         }
241         linphone_address_set_display_name(from,dn);
242         ms_free(dn);
243 }
244
245 static int sip_wizard_do_login(SipSetupContext * ctx, const char *uri, const char *passwd){
246         LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx);
247         LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
248         LinphoneAuthInfo *auth;
249         LinphoneAddress *parsed_uri;
250         char *tmp;
251
252         parsed_uri=linphone_address_new(uri);
253         if (parsed_uri==NULL){
254                 return -1;
255         }
256         if (linphone_address_get_display_name(parsed_uri)!=NULL){
257                 guess_display_name(parsed_uri);
258         }
259         tmp=linphone_address_as_string(parsed_uri);
260         linphone_proxy_config_set_identity(cfg,tmp);
261         if (passwd) {
262                 auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL);
263                 linphone_core_add_auth_info(lc,auth);
264         }
265         linphone_proxy_config_enable_register(cfg,TRUE);
266         linphone_proxy_config_done(cfg);
267         ms_free(tmp);
268         linphone_address_destroy(parsed_uri);
269         return 0;
270 }
271
272 /* a simple SipSetup built-in plugin to allow creating accounts at runtime*/
273
274 #ifndef _MSC_VER
275
276 SipSetup linphone_sip_wizard={
277         .name="SipWizard",
278         .capabilities=SIP_SETUP_CAP_ACCOUNT_MANAGER,
279         .init_instance=sip_wizard_init_instance,
280         .account_exists=sip_wizard_account_exists,
281         .create_account=sip_wizard_create_account,
282         .login_account=sip_wizard_do_login,
283         .get_domains=sip_wizard_get_domains,
284         .account_validated=sip_wizard_account_validated
285 };
286
287 #else
288 SipSetup linphone_sip_wizard={
289         "SipWizard",
290         SIP_SETUP_CAP_ACCOUNT_MANAGER,
291         0,
292         NULL,
293         NULL,
294         sip_wizard_init_instance,
295         NULL,
296         sip_wizard_account_exists,
297         sip_wizard_create_account,
298         sip_wizard_do_login,
299         NULL,
300         NULL,
301         NULL,
302         NULL,
303         NULL,
304         NULL,
305         sip_wizard_get_domains,
306         NULL,
307         NULL,
308         sip_wizard_account_validated
309 };
310
311
312
313 #endif