1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * This module (mod_gsmopen) has been contributed by:
25  *
26  * Giovanni Maruzzelli <gmaruzz@gmail.com>
27  *
28  * Maintainer: Giovanni Maruzzelli <gmaruzz@gmail.com>
29  *
30  * mod_skypopen.c -- Skype compatible Endpoint Module
31  *
32  */
33 
34 
35 #include <switch.h>
36 
37 #ifndef WIN32
38 #include <sys/time.h>
39 #include <X11/Xlib.h>
40 #include <X11/Xlibint.h>
41 #include <X11/Xatom.h>
42 
43 // CLOUDTREE (Thomas Hazel)
44 #define XIO_ERROR_BY_SETJMP
45 //#define XIO_ERROR_BY_UCONTEXT
46 
47 // CLOUDTREE (Thomas Hazel)
48 #ifdef XIO_ERROR_BY_SETJMP
49 #include "setjmp.h"
50 #endif
51 // CLOUDTREE (Thomas Hazel)
52 #ifdef XIO_ERROR_BY_UCONTEXT
53 #include "ucontext.h"
54 #endif
55 
56 #endif //WIN32
57 
58 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
59 #include <spandsp.h>
60 #include <spandsp/version.h>
61 
62 #ifndef WIN32
63 #include <netinet/tcp.h>
64 #endif
65 
66 #ifdef _MSC_VER
67 //Windows macro  for FD_SET includes a warning C4127: conditional expression is constant
68 #pragma warning(push)
69 #pragma warning(disable:4127)
70 #endif
71 
72 #define MY_EVENT_INCOMING_CHATMESSAGE "skypopen::incoming_chatmessage"
73 #define MY_EVENT_INCOMING_RAW "skypopen::incoming_raw"
74 
75 #define SAMPLERATE_SKYPOPEN 16000
76 #define MS_SKYPOPEN 20
77 #define SAMPLES_PER_FRAME (SAMPLERATE_SKYPOPEN/(1000/MS_SKYPOPEN))
78 #define BYTES_PER_FRAME (SAMPLES_PER_FRAME * sizeof(short))
79 
80 #ifndef SKYPOPEN_SVN_VERSION
81 #define SKYPOPEN_SVN_VERSION switch_version_full()
82 #endif /* SKYPOPEN_SVN_VERSION */
83 
84 typedef enum {
85 	TFLAG_IO = (1 << 0),
86 	TFLAG_INBOUND = (1 << 1),
87 	TFLAG_OUTBOUND = (1 << 2),
88 	TFLAG_DTMF = (1 << 3),
89 	TFLAG_VOICE = (1 << 4),
90 	TFLAG_HANGUP = (1 << 5),
91 	TFLAG_LINEAR = (1 << 6),
92 	TFLAG_PROGRESS = (1 << 7),
93 	TFLAG_BREAK = (1 << 8)
94 } TFLAGS;
95 
96 typedef enum {
97 	GFLAG_MY_CODEC_PREFS = (1 << 0)
98 } GFLAGS;
99 
100 #define DEBUGA_SKYPE(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"%-*s  [%s ] [DEBUG_SKYPE  %-5d][%-15s][%s,%s] " __VA_ARGS__ );
101 #define DEBUGA_CALL(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"%-*s  [%s ] [DEBUG_CALL  %-5d][%-15s][%s,%s] " __VA_ARGS__ );
102 #define DEBUGA_PBX(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 		"%-*s  [%s ] [DEBUG_PBX  %-5d][%-15s][%s,%s] " __VA_ARGS__ );
103 #define ERRORA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, 		"%-*s   [%s ] [ERRORA       %-5d][%-15s][%s,%s] " __VA_ARGS__ );
104 #define WARNINGA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, 		"%-*s[%s ] [WARNINGA     %-5d][%-15s][%s,%s] " __VA_ARGS__ );
105 #define NOTICA(...)  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, 		"%-*s [%s ] [NOTICA       %-5d][%-15s][%s,%s] " __VA_ARGS__ );
106 
107 #define SKYPOPEN_P_LOG (int)((20 - (strlen(__FILE__))) + ((__LINE__ - 1000) < 0) + ((__LINE__ - 100) < 0)), " ", SKYPOPEN_SVN_VERSION, __LINE__, tech_pvt ? tech_pvt->name ? tech_pvt->name : "none" : "none", tech_pvt ? interface_status[tech_pvt->interface_state] : "N/A", tech_pvt ? skype_callflow[tech_pvt->skype_callflow] : "N/A"
108 
109 /*********************************/
110 #define SKYPOPEN_CAUSE_NORMAL		1
111 /*********************************/
112 #define SKYPOPEN_FRAME_DTMF			1
113 /*********************************/
114 #define SKYPOPEN_CONTROL_RINGING		1
115 #define SKYPOPEN_CONTROL_ANSWER		2
116 
117 /*********************************/
118 // CLOUDTREE (Thomas Hazel)
119 #define SKYPOPEN_RINGING_INIT		0
120 #define SKYPOPEN_RINGING_PRE		1
121 
122 /*********************************/
123 #define		SKYPOPEN_STATE_IDLE					0
124 #define		SKYPOPEN_STATE_DOWN					1
125 #define		SKYPOPEN_STATE_RING					2
126 #define		SKYPOPEN_STATE_DIALING				3
127 #define		SKYPOPEN_STATE_BUSY					4
128 #define		SKYPOPEN_STATE_UP					5
129 #define		SKYPOPEN_STATE_RINGING				6
130 #define		SKYPOPEN_STATE_PRERING				7
131 #define		SKYPOPEN_STATE_ERROR_DOUBLE_CALL		8
132 #define		SKYPOPEN_STATE_SELECTED				9
133 #define 	SKYPOPEN_STATE_HANGUP_REQUESTED		10
134 #define		SKYPOPEN_STATE_PREANSWER				11
135 #define		SKYPOPEN_STATE_DEAD				12
136 /*********************************/
137 /* call flow from the device */
138 #define 	CALLFLOW_CALL_IDLE					0
139 #define 	CALLFLOW_CALL_DOWN					1
140 #define 	CALLFLOW_INCOMING_RING				2
141 #define 	CALLFLOW_CALL_DIALING				3
142 #define 	CALLFLOW_CALL_LINEBUSY				4
143 #define 	CALLFLOW_CALL_ACTIVE				5
144 #define 	CALLFLOW_INCOMING_HANGUP			6
145 #define 	CALLFLOW_CALL_RELEASED				7
146 #define 	CALLFLOW_CALL_NOCARRIER				8
147 #define 	CALLFLOW_CALL_INFLUX				9
148 #define 	CALLFLOW_CALL_INCOMING				10
149 #define 	CALLFLOW_CALL_FAILED				11
150 #define 	CALLFLOW_CALL_NOSERVICE				12
151 #define 	CALLFLOW_CALL_OUTGOINGRESTRICTED	13
152 #define 	CALLFLOW_CALL_SECURITYFAIL			14
153 #define 	CALLFLOW_CALL_NOANSWER				15
154 #define 	CALLFLOW_STATUS_FINISHED			16
155 #define 	CALLFLOW_STATUS_CANCELLED			17
156 #define 	CALLFLOW_STATUS_FAILED				18
157 #define 	CALLFLOW_STATUS_REFUSED				19
158 #define 	CALLFLOW_STATUS_RINGING				20
159 #define 	CALLFLOW_STATUS_INPROGRESS			21
160 #define 	CALLFLOW_STATUS_UNPLACED			22
161 #define 	CALLFLOW_STATUS_ROUTING				23
162 #define 	CALLFLOW_STATUS_EARLYMEDIA			24
163 #define 	CALLFLOW_INCOMING_CALLID			25
164 #define 	CALLFLOW_STATUS_REMOTEHOLD			26
165 
166 /*********************************/
167 
168 #define SKYPOPEN_MAX_INTERFACES 64
169 
170 #ifndef WIN32
171 struct SkypopenHandles {
172 	Window skype_win;
173 	Display *disp;
174 	Window win;
175 	int currentuserhandle;
176 	int api_connected;
177 	int fdesc[2];
178 
179 	// CLOUDTREE (Thomas Hazel)
180 #ifdef XIO_ERROR_BY_SETJMP
181 	jmp_buf ioerror_context;
182 #endif
183 #ifdef XIO_ERROR_BY_UCONTEXT
184 	ucontext_t ioerror_context;
185 #endif
186 
187 	// CLOUDTREE (Thomas Hazel) - is there a capable freeswitch list?
188 	switch_bool_t managed;
189 	void *prev;
190 	void *next;
191 };
192 
193 // CLOUDTREE (Thomas Hazel) - is there a capable freeswitch list?
194 struct SkypopenList {
195 	int entries;
196 	void *head;
197 	void *tail;
198 };
199 
200 // CLOUDTREE (Thomas Hazel) - is there a capable freeswitch list?
201 struct SkypopenHandles *skypopen_list_add(struct SkypopenList *list, struct SkypopenHandles *x);
202 struct SkypopenHandles *skypopen_list_find(struct SkypopenList *list, struct SkypopenHandles *x);
203 struct SkypopenHandles *skypopen_list_remove_by_value(struct SkypopenList *list, Display * display);
204 struct SkypopenHandles *skypopen_list_remove_by_reference(struct SkypopenList *list, struct SkypopenHandles *x);
205 int skypopen_list_size(struct SkypopenList *list);
206 
207 #else //WIN32
208 
209 struct SkypopenHandles {
210 	HWND win32_hInit_MainWindowHandle;
211 	HWND win32_hGlobal_SkypeAPIWindowHandle;
212 	HINSTANCE win32_hInit_ProcessHandle;
213 	char win32_acInit_WindowClassName[128];
214 	UINT win32_uiGlobal_MsgID_SkypeControlAPIAttach;
215 	UINT win32_uiGlobal_MsgID_SkypeControlAPIDiscover;
216 	int currentuserhandle;
217 	int api_connected;
218 	switch_file_t *fdesc[2];
219 };
220 #endif //WIN32
221 
222 #define MAX_CHATS 10
223 
224 struct chat {
225 	char chatname[256];
226 	char dialog_partner[256];
227 };
228 typedef struct chat chat_t;
229 
230 #define MAX_CHATMESSAGES 10
231 
232 struct chatmessage {
233 	char id[256];
234 	char type[256];
235 	char chatname[256];
236 	char from_handle[256];
237 	char from_dispname[256];
238 	char body[512];
239 };
240 typedef struct chatmessage chatmessage_t;
241 struct private_object {
242 	unsigned int flags;
243 	switch_codec_t read_codec;
244 	switch_codec_t write_codec;
245 	switch_frame_t read_frame;
246 	unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
247 	char session_uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
248 	switch_caller_profile_t *caller_profile;
249 	switch_mutex_t *mutex;
250 	switch_mutex_t *flag_mutex;
251 
252 	char interface_id[80];
253 	char name[80];
254 	char dialplan[80];
255 	char context[80];
256 	char dial_regex[256];
257 	char fail_dial_regex[256];
258 	char hold_music[256];
259 	char type[256];
260 	char X11_display[256];
261 #ifdef WIN32
262 	unsigned short tcp_cli_port;
263 	unsigned short tcp_srv_port;
264 #else
265 	int tcp_cli_port;
266 	int tcp_srv_port;
267 #endif
268 	struct SkypopenHandles SkypopenHandles;
269 
270 	// CLOUDTREE (Thomas Hazel)
271 	char ringing_state;
272 
273 	int interface_state;
274 	char language[80];
275 	char exten[80];
276 	int skypopen_sound_rate;
277 	char callid_name[50];
278 	char callid_number[50];
279 	double playback_boost;
280 	double capture_boost;
281 	int stripmsd;
282 	char skype_call_id[512];
283 	int skype_call_ongoing;
284 	char skype_friends[4096];
285 	char skype_fullname[512];
286 	char skype_displayname[512];
287 	int skype_callflow;
288 	int skype;
289 	int control_to_send;
290 #ifdef WIN32
291 	switch_file_t *audiopipe_srv[2];
292 	switch_file_t *audiopipe_cli[2];
293 	switch_file_t *skypopen_sound_capt_fd;
294 #else							/* WIN32 */
295 	int audiopipe_srv[2];
296 	int audiopipe_cli[2];
297 	int skypopen_sound_capt_fd;
298 #endif							/* WIN32 */
299 	switch_thread_t *tcp_srv_thread;
300 	switch_thread_t *tcp_cli_thread;
301 	switch_thread_t *skypopen_signaling_thread;
302 	switch_thread_t *skypopen_api_thread;
303 	short audiobuf[SAMPLES_PER_FRAME];
304 	int audiobuf_is_loaded;
305 	short audiobuf_cli[SAMPLES_PER_FRAME];
306 	switch_mutex_t *mutex_audio_cli;
307 	int flag_audio_cli;
308 	short audiobuf_srv[SAMPLES_PER_FRAME];
309 	switch_mutex_t *mutex_audio_srv;
310 	int flag_audio_srv;
311 	switch_mutex_t *mutex_thread_audio_cli;
312 	switch_mutex_t *mutex_thread_audio_srv;
313 
314 	FILE *phonebook_writing_fp;
315 	int skypopen_dir_entry_extension_prefix;
316 	char skype_user[256];
317 	char initial_skype_user[256];
318 	char skype_password[256];
319 	char destination[256];
320 	struct timeval answer_time;
321 	struct timeval ring_time;
322 
323 	struct timeval transfer_time;
324 	char transfer_callid_number[50];
325 	char skype_transfer_call_id[512];
326 	int running;
327 	uint32_t ib_calls;
328 	uint32_t ob_calls;
329 	uint32_t ib_failed_calls;
330 	uint32_t ob_failed_calls;
331 
332 	chatmessage_t chatmessages[MAX_CHATMESSAGES];
333 	chat_t chats[MAX_CHATS];
334 	uint32_t report_incoming_chatmessages;
335 	switch_timer_t timer_read;
336 	switch_timer_t timer_read_srv;
337 	switch_timer_t timer_write;
338 	int begin_to_write;
339 	int begin_to_read;
340 	dtmf_rx_state_t dtmf_state;
341 	switch_time_t old_dtmf_timestamp;
342 	switch_buffer_t *write_buffer;
343 	switch_buffer_t *read_buffer;
344 	int silent_mode;
345 	int write_silence_when_idle;
346 	int setsockopt;
347 	char answer_id[256];
348 	char answer_value[256];
349 	char ring_id[256];
350 	char ring_value[256];
351 
352 	char message[4096];
353 	char skype_voicemail_id[512];
354 	char skype_voicemail_id_greeting[512];
355 };
356 
357 typedef struct private_object private_t;
358 
359 void *SWITCH_THREAD_FUNC skypopen_api_thread_func(switch_thread_t *thread, void *obj);
360 int skypopen_audio_read(private_t *tech_pvt);
361 int skypopen_audio_init(private_t *tech_pvt);
362 int skypopen_signaling_write(private_t *tech_pvt, char *msg_to_skype);
363 int skypopen_signaling_read(private_t *tech_pvt);
364 
365 int skypopen_call(private_t *tech_pvt, char *idest, int timeout);
366 int skypopen_senddigit(private_t *tech_pvt, char digit);
367 
368 void *skypopen_do_tcp_srv_thread_func(void *obj);
369 void *SWITCH_THREAD_FUNC skypopen_do_tcp_srv_thread(switch_thread_t *thread, void *obj);
370 
371 void *skypopen_do_tcp_cli_thread_func(void *obj);
372 void *SWITCH_THREAD_FUNC skypopen_do_tcp_cli_thread(switch_thread_t *thread, void *obj);
373 
374 void *skypopen_do_skypeapi_thread_func(void *obj);
375 void *SWITCH_THREAD_FUNC skypopen_do_skypeapi_thread(switch_thread_t *thread, void *obj);
376 int dtmf_received(private_t *tech_pvt, char *value);
377 int start_audio_threads(private_t *tech_pvt);
378 int new_inbound_channel(private_t *tech_pvt);
379 int outbound_channel_answered(private_t *tech_pvt);
380 int skypopen_signaling_write(private_t *tech_pvt, char *msg_to_skype);
381 #if defined(WIN32) && !defined(__CYGWIN__)
382 int skypopen_pipe_read(switch_file_t *pipe, short *buf, int howmany);
383 int skypopen_pipe_write(switch_file_t *pipe, short *buf, int howmany);
384 /* Visual C do not have strsep ? */
385 char *strsep(char **stringp, const char *delim);
386 #else
387 int skypopen_pipe_read(int pipe, short *buf, int howmany);
388 int skypopen_pipe_write(int pipe, short *buf, int howmany);
389 #endif /* WIN32 */
390 int skypopen_close_socket(unsigned int fd);
391 private_t *find_available_skypopen_interface_rr(private_t *tech_pvt_calling);
392 int remote_party_is_ringing(private_t *tech_pvt);
393 int remote_party_is_early_media(private_t *tech_pvt);
394 int skypopen_answer(private_t *tech_pvt);
395 int skypopen_transfer(private_t *tech_pvt);
396 #ifndef WIN32
397 int skypopen_socket_create_and_bind(private_t *tech_pvt, int *which_port);
398 #else
399 int skypopen_socket_create_and_bind(private_t *tech_pvt, unsigned short *which_port);
400 #endif //WIN32
401 int incoming_chatmessage(private_t *tech_pvt, int which);
402 int next_port(void);
403 int skypopen_partner_handle_ring(private_t *tech_pvt);
404 int skypopen_answered(private_t *tech_pvt);
405 int inbound_channel_answered(private_t *tech_pvt);
406