lookup.c 8.14 KB
Newer Older
1 2 3 4
#ifdef IN_LINPHONE
#include "linphonecore.h"
#include "lpconfig.h"
#else
smorlat's avatar
smorlat committed
5 6
#include <linphone/linphonecore.h>
#include <linphone/lpconfig.h>
7
#endif
smorlat's avatar
smorlat committed
8 9
#include <libsoup/soup.h>

smorlat's avatar
smorlat committed
10 11
#define SERIALIZE_HTTPS 0

smorlat's avatar
smorlat committed
12 13
static bool_t buddy_lookup_init(void){
	return TRUE;
14
};
smorlat's avatar
smorlat committed
15

16 17
typedef struct _BLReq{
	BuddyLookupRequest base;
smorlat's avatar
smorlat committed
18
	SoupMessage *msg;
19
	SoupSession *session;
smorlat's avatar
smorlat committed
20
	ortp_thread_t th;
21
}BLReq;
smorlat's avatar
smorlat committed
22 23


smorlat's avatar
smorlat committed
24 25
void set_proxy(SoupSession *session, const char *proxy){
	SoupURI *uri=soup_uri_new(proxy);
smorlat's avatar
smorlat committed
26
	ms_message("Using http proxy %s",proxy);
smorlat's avatar
smorlat committed
27 28
	g_object_set(G_OBJECT(session),"proxy-uri",uri,NULL);
}
29

smorlat's avatar
smorlat committed
30 31 32 33 34 35
static void buddy_lookup_instance_init(SipSetupContext *ctx){
}

static void buddy_lookup_instance_uninit(SipSetupContext *ctx){
}

36
static SoupMessage * build_xmlrpc_request(const char *identity, const char *password, const char *key, const char *domain, const char *url, int max_results){
smorlat's avatar
smorlat committed
37 38 39 40 41 42 43
	SoupMessage * msg;

	msg=soup_xmlrpc_request_new(url,
				"fp.searchUsers",
				G_TYPE_STRING, identity,
				G_TYPE_STRING, password ? password : "",
				G_TYPE_STRING, key,
44
				G_TYPE_INT , max_results,
smorlat's avatar
smorlat committed
45 46 47 48 49 50 51 52 53 54 55 56 57
				G_TYPE_INT , 0,
				G_TYPE_STRING, domain,
				G_TYPE_INVALID);
	if (!msg){
		ms_error("Fail to create SoupMessage !");
	}else{
		SoupBuffer *sb=soup_message_body_flatten(msg->request_body);
		ms_message("This is the XML-RPC request we are going to send:\n%s\n",sb->data);
		soup_buffer_free(sb);
	}
	return msg;
}

58
static void got_headers(BLReq *blreq, SoupMessage*msg){
smorlat's avatar
smorlat committed
59
	ms_message("Got headers !");
60
	blreq->base.status=BuddyLookupConnected;
smorlat's avatar
smorlat committed
61 62 63 64 65 66 67 68 69 70 71 72
}

static void fill_item(GHashTable *ht , const char *name, char *dest, size_t dest_size){
	GValue *v=(GValue*)g_hash_table_lookup(ht,(gconstpointer)name);
	if (v) {
		const char *tmp=g_value_get_string(v);
		if (tmp){
			strncpy(dest,tmp,dest_size-1);
		}
	}else ms_warning("no field named '%s'", name);
}

73
static void fill_buddy_info(BLReq *blreq, BuddyInfo *bi, GHashTable *ht){
74
	char tmp[256];
smorlat's avatar
smorlat committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
	fill_item(ht,"first_name",bi->firstname,sizeof(bi->firstname));
	fill_item(ht,"last_name",bi->lastname,sizeof(bi->lastname));
	fill_item(ht,"display_name",bi->displayname,sizeof(bi->displayname));
	fill_item(ht,"sip",tmp,sizeof(tmp));
	if (strstr(tmp,"sip:")==0){
		snprintf(bi->sip_uri,sizeof(bi->sip_uri)-1,"sip:%s",tmp);
	}else{
		strncpy(bi->sip_uri,tmp,sizeof(bi->sip_uri)-1);
	}
	
	fill_item(ht,"street",bi->address.street,sizeof(bi->address.street));
	fill_item(ht,"zip",bi->address.zip,sizeof(bi->address.zip));
	fill_item(ht,"city",bi->address.town,sizeof(bi->address.town));
	fill_item(ht,"country",bi->address.country,sizeof(bi->address.country));
	fill_item(ht,"email",bi->email,sizeof(bi->email));
90 91 92 93 94 95 96
	tmp[0]='\0';
	fill_item(ht,"image",tmp,sizeof(tmp));
	if (tmp[0]!='\0'){
		SoupMessage *msg;
		guint status;
		ms_message("This buddy has an image, let's download it: %s",tmp);
		msg=soup_message_new("GET",tmp);
97
		if ((status=soup_session_send_message(blreq->session,msg))==200){
98 99 100 101 102 103 104 105 106 107 108
			SoupMessageBody *body=msg->response_body;
			ms_message("Received %i bytes",body->length);
			strncpy(bi->image_type,"png",sizeof(bi->image_type));
			bi->image_length=body->length;
			bi->image_data=ms_malloc(body->length+4); /*add padding bytes*/
			memcpy(bi->image_data,body->data,bi->image_length);
		}else{
			ms_error("Fail to fetch the image %i",status);
		}
	}
	
smorlat's avatar
smorlat committed
109 110
}

111
static MSList * make_buddy_list(BLReq *blreq, GValue *retval){
smorlat's avatar
smorlat committed
112 113 114 115 116 117 118 119 120
	MSList *ret=NULL;
	if (G_VALUE_TYPE(retval)==G_TYPE_VALUE_ARRAY){
		GValueArray *array=(GValueArray*)g_value_get_boxed(retval);
		GValue *gelem;
		int i;
		for(i=0;i<array->n_values;++i){
			gelem=g_value_array_get_nth(array,i);
			if (G_VALUE_TYPE(gelem)==G_TYPE_HASH_TABLE){
				GHashTable *ht=(GHashTable*)g_value_get_boxed(gelem);
121
				BuddyInfo *bi=buddy_info_new();
122
				fill_buddy_info(blreq,bi,ht);
smorlat's avatar
smorlat committed
123 124 125 126 127 128 129 130 131 132
				ret=ms_list_append(ret,bi);
			}else{
				ms_error("Element is not a hash table");
			}
		}
	}else ms_error("Return value is not an array");
	return ret;
}


133
static int xml_rpc_parse_response(BLReq *blreq, SoupMessage *sm){
smorlat's avatar
smorlat committed
134 135 136 137 138 139 140 141 142 143 144 145
	SoupBuffer *sb;
	GValue retval;
	GError *error=NULL;
	sb=soup_message_body_flatten(sm->response_body);
	ms_message("This the xml-rpc response:\n%s\n",sb->data);
	if (soup_xmlrpc_parse_method_response(sb->data,sb->length,&retval,&error)==FALSE){
		if (error!=NULL){
			ms_error("xmlrpc fault: %s",error->message);
			g_error_free(error);
		}else{
			ms_error("Could not parse xml-rpc response !");
		}
146
		blreq->base.status=BuddyLookupFailure;
smorlat's avatar
smorlat committed
147 148
	}else{
		ms_message("Extracting values from return type...");
149
		blreq->base.results=make_buddy_list(blreq,&retval);
smorlat's avatar
smorlat committed
150
		g_value_unset(&retval);
151
		blreq->base.status=BuddyLookupDone;
smorlat's avatar
smorlat committed
152 153
	}
	soup_buffer_free(sb);
154
	return blreq->base.status==BuddyLookupDone ? 0 : -1;
smorlat's avatar
smorlat committed
155 156
}

smorlat's avatar
smorlat committed
157
#if SERIALIZE_HTTPS
158 159 160 161 162 163 164 165 166
/*on windows libsoup support for threads with gnutls is not yet functionnal (only in git)
This will come in next release of libsoup, probably. 
In the meantime, we are forced to serialize all soup https processing with a big
ugly global mutex...*/

static GStaticMutex big_mutex = G_STATIC_MUTEX_INIT;

#endif

smorlat's avatar
smorlat committed
167
static void * process_xml_rpc_request(void *up){
168 169
	BLReq *blreq=(BLReq*)up;
	SoupMessage *sm=blreq->msg;
smorlat's avatar
smorlat committed
170
	int code;
171 172
	g_signal_connect_swapped(G_OBJECT(sm),"got-headers",(GCallback)got_headers,blreq);
	blreq->base.status=BuddyLookupConnecting;
smorlat's avatar
smorlat committed
173
#if SERIALIZE_HTTPS
174 175
	g_static_mutex_lock(&big_mutex);
#endif
176
	code=soup_session_send_message(blreq->session,sm);
smorlat's avatar
smorlat committed
177 178
	if (code==200){
		ms_message("Got a response from server, yeah !");
179
		xml_rpc_parse_response(blreq,sm);
smorlat's avatar
smorlat committed
180
	}else{
181
		ms_error("request failed, error-code=%i (%s)",code,soup_status_get_phrase(code));
182
		blreq->base.status=BuddyLookupFailure;
smorlat's avatar
smorlat committed
183
	}
smorlat's avatar
smorlat committed
184
#if SERIALIZE_HTTPS
185 186
	g_static_mutex_unlock(&big_mutex);
#endif
smorlat's avatar
smorlat committed
187 188 189
	return NULL;
}

190
static int lookup_buddy(SipSetupContext *ctx, BLReq *req){
smorlat's avatar
smorlat committed
191 192 193 194 195 196 197
	LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx);
	LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
	LpConfig *config=linphone_core_get_config(lc);
	const char *identity=linphone_proxy_config_get_identity(cfg);
	const char *url=lp_config_get_string(config,"BuddyLookup","url",NULL);
	LinphoneAuthInfo *aa;
	SoupMessage *sm;
198 199
	LinphoneAddress *from;
	
smorlat's avatar
smorlat committed
200 201 202 203 204
	if (url==NULL){
		ms_error("No url defined for BuddyLookup in config file, aborting search.");
		return -1;
	}

205 206
	from=linphone_address_new(identity);
	if (from==NULL){
smorlat's avatar
smorlat committed
207 208 209
		ms_error("Could not parse identity %s",identity);
		return -1;
	}
210
	aa=linphone_core_find_auth_info(lc,linphone_address_get_domain(from),linphone_address_get_username(from));
smorlat's avatar
smorlat committed
211
	if (aa) ms_message("There is a password: %s",aa->passwd);
212 213 214
	else ms_message("No password for %s on %s",linphone_address_get_username(from),linphone_address_get_domain(from));
	sm=build_xmlrpc_request(identity, aa ? aa->passwd : NULL, req->base.key, linphone_address_get_domain(from), url, req->base.max_results);
	linphone_address_destroy(from);
215 216
	req->msg=sm;
	ortp_thread_create(&req->th,NULL,process_xml_rpc_request,req);
smorlat's avatar
smorlat committed
217 218 219 220
	if (!sm) return -1;
	return 0;
}

221 222 223 224 225 226 227 228 229 230 231 232
static BuddyLookupRequest * create_request(SipSetupContext *ctx){
	BLReq *req=ms_new0(BLReq,1);
	const char *proxy=NULL;
	req->session=soup_session_sync_new();
	proxy=getenv("http_proxy");
	if (proxy && strlen(proxy)>0) set_proxy(req->session,proxy);
	return (BuddyLookupRequest*)req;
}

static int submit_request(SipSetupContext *ctx, BuddyLookupRequest *req){
	BLReq *blreq=(BLReq*)req;
	return lookup_buddy(ctx,blreq);
smorlat's avatar
smorlat committed
233 234
}

235 236 237 238 239 240 241
static int free_request(SipSetupContext *ctx, BuddyLookupRequest *req){
	BLReq *blreq=(BLReq*)req;
	if (blreq->th!=0){
		soup_session_cancel_message(blreq->session,blreq->msg, SOUP_STATUS_CANCELLED);
		ortp_thread_join(blreq->th,NULL);
		blreq->th=0;
		g_object_unref(G_OBJECT(blreq->msg));
smorlat's avatar
smorlat committed
242
	}
243 244 245
	if (blreq->session)
		g_object_unref(G_OBJECT(blreq->session));
	buddy_lookup_request_free(req);
smorlat's avatar
smorlat committed
246 247 248 249 250 251
	return 0;
}

static void buddy_lookup_exit(void){
}

252 253 254 255 256 257 258 259
static BuddyLookupFuncs bl_funcs={
	.request_create=create_request,
	.request_submit=submit_request,
	.request_free=free_request
};



smorlat's avatar
smorlat committed
260 261 262 263 264 265
static SipSetup buddy_lookup_funcs={
	.name="BuddyLookup",
	.capabilities=SIP_SETUP_CAP_BUDDY_LOOKUP,
	.init=buddy_lookup_init,
	.init_instance=buddy_lookup_instance_init,
	.uninit_instance=buddy_lookup_instance_uninit,
266 267
	.exit=buddy_lookup_exit,
	.buddy_lookup_funcs=&bl_funcs,
smorlat's avatar
smorlat committed
268 269 270 271 272 273
};

void libbuddylookup_init(){
	sip_setup_register(&buddy_lookup_funcs);
	ms_message("Buddylookup plugin registered.");
}