]> sjero.net Git - linphone/blob - console/linphonec.c
apply linphonec patches
[linphone] / console / linphonec.c
1 /****************************************************************************
2  *
3  *  $Id: linphonec.c,v 1.57 2007/11/14 13:40:27 smorlat Exp $
4  *
5  *  Copyright (C) 2006  Sandro Santilli <strk@keybit.net>
6  *  Copyright (C) 2002  Florian Winterstein <flox@gmx.net>
7  *  Copyright (C) 2000  Simon MORLAT <simon.morlat@free.fr>
8  *
9 ****************************************************************************
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  ****************************************************************************/
26 #include <string.h>
27 #ifndef _WIN32_WCE
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include "private.h" /*coreapi/private.h, needed for LINPHONE_VERSION */
34 #endif /*_WIN32_WCE*/
35 #include <limits.h>
36 #include <ctype.h>
37
38 #include <linphonecore.h>
39
40 #include "linphonec.h"
41
42 #ifdef WIN32
43 #include <ws2tcpip.h>
44 #include <ctype.h>
45 #ifndef _WIN32_WCE
46 #include <conio.h>
47 #endif /*_WIN32_WCE*/
48 #else
49 #include <sys/socket.h>
50 #include <netdb.h>
51 #include <sys/un.h>
52 #include <sys/stat.h>
53 #endif
54
55 #if defined(_WIN32_WCE)
56
57 #if !defined(PATH_MAX)
58 #define PATH_MAX 256
59 #endif /*PATH_MAX*/
60
61 #if !defined(strdup)
62 #define strdup _strdup
63 #endif /*strdup*/
64
65 #endif /*_WIN32_WCE*/
66
67 #ifdef HAVE_GETTEXT
68 #include <libintl.h>
69 #ifndef _
70 #define _(String) gettext(String)
71 #endif
72 #else
73 #define _(something)    (something)
74 #endif
75
76 #ifndef PACKAGE_DIR
77 #define PACKAGE_DIR ""
78 #endif
79
80 #ifdef HAVE_X11_XLIB_H
81 #include <X11/Xlib.h>
82 #include <SDL/SDL_syswm.h>
83 #endif
84
85 /***************************************************************************
86  *
87  *  Types
88  *
89  ***************************************************************************/
90
91 typedef struct {
92         LinphoneAuthInfo *elem[MAX_PENDING_AUTH];
93         int nitems;
94 } LPC_AUTH_STACK;
95
96 /***************************************************************************
97  *
98  *  Forward declarations
99  *
100  ***************************************************************************/
101
102 char *lpc_strip_blanks(char *input);
103
104 static int handle_configfile_migration(void);
105 #if !defined(_WIN32_WCE)
106 static int copy_file(const char *from, const char *to);
107 #endif /*_WIN32_WCE*/
108 static int linphonec_parse_cmdline(int argc, char **argv);
109 static int linphonec_init(int argc, char **argv);
110 static int linphonec_main_loop (LinphoneCore * opm, char * sipAddr);
111 static int linphonec_idle_call (void);
112 #ifdef HAVE_READLINE
113 static int linphonec_initialize_readline(void);
114 static int linphonec_finish_readline();
115 static char **linephonec_readline_completion(const char *text,
116         int start, int end);
117 #endif
118
119 /* These are callback for linphone core */
120 static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm,
121         const char *username);
122 static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to);
123 static void linphonec_display_something (LinphoneCore * lc, const char *something);
124 static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
125 static void linphonec_display_warning (LinphoneCore * lc, const char *something);
126 static void linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event);
127
128 static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid);
129 static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
130                 LinphoneFriend *lf, const char *url);
131
132 static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
133                 const char *from, const char *msg);
134 static void linphonec_display_status (LinphoneCore * lc, const char *something);
135 static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf);
136 static void print_prompt(LinphoneCore *opm);
137 void linphonec_out(const char *fmt,...);
138 /***************************************************************************
139  *
140  * Global variables
141  *
142  ***************************************************************************/
143
144 LinphoneCore *linphonec;
145 FILE *mylogfile;
146 #ifdef HAVE_READLINE
147 static char *histfile_name=NULL;
148 static char last_in_history[256];
149 #endif
150 //auto answer (-a) option
151 static bool_t auto_answer=FALSE;
152 static bool_t answer_call=FALSE;
153 static bool_t vcap_enabled=FALSE;
154 static bool_t display_enabled=FALSE;
155 static bool_t preview_enabled=FALSE;
156 static bool_t show_general_state=FALSE;
157 static bool_t unix_socket=FALSE;
158 static bool_t linphonec_running=TRUE;
159 LPC_AUTH_STACK auth_stack;
160 static int trace_level = 0;
161 static char *logfile_name = NULL;
162 static char configfile_name[PATH_MAX];
163 static const char *factory_configfile_name=NULL;
164 static char *sipAddr = NULL; /* for autocall */
165 #if !defined(_WIN32_WCE)
166 static ortp_pipe_t client_sock=ORTP_PIPE_INVALID;
167 #endif /*_WIN32_WCE*/
168 char prompt[PROMPT_MAX_LEN];
169 #if !defined(_WIN32_WCE)
170 static ortp_thread_t pipe_reader_th;
171 static bool_t pipe_reader_run=FALSE;
172 #endif /*_WIN32_WCE*/
173 #if !defined(_WIN32_WCE)
174 static ortp_pipe_t server_sock;
175 #endif /*_WIN32_WCE*/
176
177 bool_t linphonec_camera_enabled=TRUE;
178
179
180 extern VideoParams lpc_video_params;
181
182 void linphonec_call_identify(LinphoneCall* call){
183         static long callid=1;
184         linphone_call_set_user_pointer (call,(void*)callid);
185         callid++;
186 }
187
188 LinphoneCall *linphonec_get_call(long id){
189         const MSList *elem=linphone_core_get_calls(linphonec);
190         for (;elem!=NULL;elem=elem->next){
191                 LinphoneCall *call=(LinphoneCall*)elem->data;
192                 if (linphone_call_get_user_pointer (call)==(void*)id){
193                         return call;
194                 }
195         }
196         linphonec_out("Sorry, no call with id %i exists at this time.\n",id);
197         return NULL;
198 }
199
200 /***************************************************************************
201  *
202  * Linphone core callbacks
203  *
204  ***************************************************************************/
205
206 /*
207  * Linphone core callback
208  */
209 static void
210 linphonec_display_refer (LinphoneCore * lc, const char *refer_to)
211 {
212         linphonec_out("Receiving out of call refer to %s\n", refer_to);
213 }
214
215 /*
216  * Linphone core callback
217  */
218 static void
219 linphonec_display_something (LinphoneCore * lc, const char *something)
220 {
221         fprintf (stdout, "%s\n%s", something,prompt);
222         fflush(stdout);
223 }
224
225 /*
226  * Linphone core callback
227  */
228 static void
229 linphonec_display_status (LinphoneCore * lc, const char *something)
230 {
231         fprintf (stdout, "%s\n%s", something,prompt);
232         fflush(stdout);
233 }
234
235 /*
236  * Linphone core callback
237  */
238 static void
239 linphonec_display_warning (LinphoneCore * lc, const char *something)
240 {
241         fprintf (stdout, "Warning: %s\n%s", something,prompt);
242         fflush(stdout);
243 }
244
245 /*
246  * Linphone core callback
247  */
248 static void
249 linphonec_display_url (LinphoneCore * lc, const char *something, const char *url)
250 {
251         fprintf (stdout, "%s : %s\n", something, url);
252 }
253
254 /*
255  * Linphone core callback
256  */
257 static void
258 linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username)
259 {
260         /* no prompt possible when using pipes or tcp mode*/
261         if (unix_socket){
262                 linphone_core_abort_authentication(lc,NULL);
263         }else{
264                 LinphoneAuthInfo *pending_auth;
265
266                 if ( auth_stack.nitems+1 > MAX_PENDING_AUTH )
267                 {
268                         fprintf(stderr,
269                                 "Can't accept another authentication request.\n"
270                                 "Consider incrementing MAX_PENDING_AUTH macro.\n");
271                         return;
272                 }
273
274                 pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm);
275                 auth_stack.elem[auth_stack.nitems++]=pending_auth;
276         }
277 }
278
279 /*
280  * Linphone core callback
281  */
282 static void
283 linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event)
284 {
285         if(!strcmp(event,"refer"))
286         {
287                 linphonec_out("The distand endpoint %s of call %li has been transfered, you can safely close the call.\n",
288                               from,(long)linphone_call_get_user_pointer (call));
289         }
290 }
291
292
293 /*
294  * Linphone core callback
295  */
296 static void
297 linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid)
298 {
299         char *tmp=linphone_address_as_string(linphone_friend_get_address(fid));
300         printf("Friend %s is %s\n", tmp, linphone_online_status_to_string(linphone_friend_get_status(fid)));
301         ms_free(tmp);
302         // todo: update Friend list state (unimplemented)
303 }
304
305 /*
306  * Linphone core callback
307  */
308 static void
309 linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf,
310                 const char *url)
311 {
312         printf("Friend %s requested subscription "
313                 "(accept/deny is not implemented yet)\n", url);
314         // This means that this person wishes to be notified
315         // of your presence information (online, busy, away...).
316
317 }
318
319 static void linphonec_call_updated(LinphoneCall *call){
320         const LinphoneCallParams *cp=linphone_call_get_current_params(call);
321         if (!linphone_call_camera_enabled (call) && linphone_call_params_video_enabled (cp)){
322                 linphonec_out("Far end requests to share video.\nType 'camera on' if you agree.\n");
323         }
324 }
325
326 static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){
327         char *from=linphone_call_get_remote_address_as_string(call);
328         long id=(long)linphone_call_get_user_pointer (call);
329         switch(st){
330                 case LinphoneCallEnd:
331                         linphonec_out("Call %i with %s ended.\n", id, from);
332                 break;
333                 case LinphoneCallResuming:
334                         linphonec_out("Resuming call %i with %s.\n", id, from);
335                 break;
336                 case LinphoneCallStreamsRunning:
337                         linphonec_out("Media streams established with %s for call %i.\n", from,id);
338                 break;
339                 case LinphoneCallPausing:
340                         linphonec_out("Pausing call %i with %s.\n", id, from);
341                 break;
342                 case LinphoneCallPaused:
343                         linphonec_out("Call %i with %s is now paused.\n", id, from);
344                 break;
345                 case LinphoneCallPausedByRemote:
346                         linphonec_out("Call %i has been paused by %s.\n",id,from);
347                 break;
348                 case LinphoneCallIncomingReceived:
349                         linphonec_call_identify(call);
350                         linphone_call_enable_camera (call,linphonec_camera_enabled);
351                         id=(long)linphone_call_get_user_pointer (call);
352                         linphonec_set_caller(from);
353                         if ( auto_answer)  {
354                                 answer_call=TRUE;
355                         }
356                         linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id);
357                 break;
358                 case LinphoneCallOutgoingInit:
359                         linphonec_call_identify(call);
360                 break;
361                 case LinphoneCallUpdatedByRemote:
362                         linphonec_call_updated(call);
363                 break;
364                 default:
365                 break;
366         }
367         ms_free(from);
368 }
369
370 /*
371  * Linphone core callback
372  */
373 static void
374 linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
375                 const char *from, const char *msg)
376 {
377         printf("%s: %s\n", from, msg);
378         // TODO: provide mechanism for answering.. ('say' command?)
379 }
380
381
382 static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){
383         char *from=linphone_call_get_remote_address_as_string(call);
384         fprintf(stdout,"Receiving tone %c from %s\n",dtmf,from);
385         fflush(stdout);
386         ms_free(from);
387 }
388
389 static char received_prompt[PROMPT_MAX_LEN];
390 static ms_mutex_t prompt_mutex;
391 static bool_t have_prompt=FALSE;
392
393 static void *prompt_reader_thread(void *arg){
394         char *ret;
395         char tmp[PROMPT_MAX_LEN];
396         while ((ret=fgets(tmp,sizeof(tmp),stdin))!=NULL){
397                 ms_mutex_lock(&prompt_mutex);
398                 strcpy(received_prompt,ret);
399                 have_prompt=TRUE;
400                 ms_mutex_unlock(&prompt_mutex);
401         }
402         return NULL;
403 }
404
405 static void start_prompt_reader(void){
406         ortp_thread_t th;
407         ms_mutex_init(&prompt_mutex,NULL);
408         ortp_thread_create(&th,NULL,prompt_reader_thread,NULL);
409 }
410 #if !defined(_WIN32_WCE)
411 static ortp_pipe_t create_server_socket(void){
412         char path[128];
413 #ifndef WIN32
414         snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
415 #else
416         {
417                 TCHAR username[128];
418                 DWORD size=sizeof(username)-1;
419                 GetUserName(username,&size);
420                 snprintf(path,sizeof(path)-1,"linphonec-%s",username);
421         }
422 #endif
423         return ortp_server_pipe_create(path);
424 }
425
426
427 static void *pipe_thread(void*p){
428         char tmp[250];
429         server_sock=create_server_socket();
430         if (server_sock==ORTP_PIPE_INVALID) return NULL;
431         while(pipe_reader_run){
432                 while(client_sock!=ORTP_PIPE_INVALID){ /*sleep until the last command is finished*/
433 #ifndef WIN32
434                         usleep(20000);
435 #else
436                         Sleep(20);
437 #endif
438                 }
439                 client_sock=ortp_server_pipe_accept_client(server_sock);
440                 if (client_sock!=ORTP_PIPE_INVALID){
441                         int len;
442                         /*now read from the client */
443                         if ((len=ortp_pipe_read(client_sock,(uint8_t*)tmp,sizeof(tmp)-1))>0){
444                                 ortp_mutex_lock(&prompt_mutex);
445                                 tmp[len]='\0';
446                                 strcpy(received_prompt,tmp);
447                                 printf("Receiving command '%s'\n",received_prompt);fflush(stdout);
448                                 have_prompt=TRUE;
449                                 ortp_mutex_unlock(&prompt_mutex);
450                         }else{
451                                 printf("read nothing\n");fflush(stdout);
452                                 ortp_server_pipe_close_client(client_sock);
453                                 client_sock=ORTP_PIPE_INVALID;
454                         }
455
456                 }else{
457                         if (pipe_reader_run) fprintf(stderr,"accept() failed: %s\n",strerror(errno));
458                 }
459         }
460         ms_message("Exiting pipe_reader_thread.");
461         fflush(stdout);
462         return NULL;
463 }
464
465 static void start_pipe_reader(void){
466         ms_mutex_init(&prompt_mutex,NULL);
467         pipe_reader_run=TRUE;
468         ortp_thread_create(&pipe_reader_th,NULL,pipe_thread,NULL);
469 }
470
471 static void stop_pipe_reader(void){
472         pipe_reader_run=FALSE;
473         linphonec_command_finished();
474         ortp_server_pipe_close(server_sock);
475         ortp_thread_join(pipe_reader_th,NULL);
476 }
477 #endif /*_WIN32_WCE*/
478
479 #ifdef HAVE_READLINE
480 #define BOOL_HAVE_READLINE 1
481 #else
482 #define BOOL_HAVE_READLINE 0
483 #endif
484
485 char *linphonec_readline(char *prompt){
486         if (unix_socket || !BOOL_HAVE_READLINE ){
487                 static bool_t prompt_reader_started=FALSE;
488                 static bool_t pipe_reader_started=FALSE;
489                 if (!prompt_reader_started){
490                         start_prompt_reader();
491                         prompt_reader_started=TRUE;
492                 }
493                 if (unix_socket && !pipe_reader_started){
494 #if !defined(_WIN32_WCE)
495                         start_pipe_reader();
496                         pipe_reader_started=TRUE;
497 #endif /*_WIN32_WCE*/
498                 }
499                 fprintf(stdout,"%s",prompt);
500                 fflush(stdout);
501                 while(1){
502                         ms_mutex_lock(&prompt_mutex);
503                         if (have_prompt){
504                                 char *ret=strdup(received_prompt);
505                                 have_prompt=FALSE;
506                                 ms_mutex_unlock(&prompt_mutex);
507                                 return ret;
508                         }
509                         ms_mutex_unlock(&prompt_mutex);
510                         linphonec_idle_call();
511 #ifdef WIN32
512                         Sleep(20);
513                         /* Following is to get the video window going as it
514                                  should. Maybe should we only have this on when the option -V
515                                  or -D is on? */
516                         MSG msg;
517         
518                         if (PeekMessage(&msg, NULL, 0, 0,1)) {
519                                 TranslateMessage(&msg);
520                                 DispatchMessage(&msg);
521                         }
522 #else
523                         usleep(20000);
524 #endif
525                 }
526         }else{
527 #ifdef HAVE_READLINE
528                 return readline(prompt);
529 #endif
530         }
531 }
532
533 void linphonec_out(const char *fmt,...){
534         char *res;
535         va_list args;
536         va_start (args, fmt);
537         res=ortp_strdup_vprintf(fmt,args);
538         va_end (args);
539         printf("%s",res);
540         fflush(stdout);
541 #if !defined(_WIN32_WCE)
542         if (client_sock!=ORTP_PIPE_INVALID){
543                 if (ortp_pipe_write(client_sock,(uint8_t*)res,strlen(res))==-1){
544                         fprintf(stderr,"Fail to send output via pipe: %s",strerror(errno));
545                 }
546         }
547 #endif /*_WIN32_WCE*/
548         ortp_free(res);
549 }
550
551 void linphonec_command_finished(void){
552 #if !defined(_WIN32_WCE)
553         if (client_sock!=ORTP_PIPE_INVALID){
554                 ortp_server_pipe_close_client(client_sock);
555                 client_sock=ORTP_PIPE_INVALID;
556         }
557 #endif /*_WIN32_WCE*/
558 }
559
560 void linphonec_set_autoanswer(bool_t enabled){
561         auto_answer=enabled;
562 }
563
564 bool_t linphonec_get_autoanswer(){
565         return auto_answer;
566 }
567
568 LinphoneCoreVTable linphonec_vtable={0};
569
570 /***************************************************************************/
571 /*
572  * Main
573  *
574  * Use globals:
575  *
576  *      - char *histfile_name
577  *      - FILE *mylogfile
578  */
579 #if defined (_WIN32_WCE)
580
581 char **convert_args_to_ascii(int argc, _TCHAR **wargv){
582         int i;
583         char **result=malloc(argc*sizeof(char*));
584         char argtmp[128];
585         for(i=0;i<argc;++i){
586                 wcstombs(argtmp,wargv[i],sizeof(argtmp));
587                 result[i]=strdup(argtmp);
588         }
589         return result;
590 }
591
592 int _tmain(int argc, _TCHAR* wargv[]) {
593         char **argv=convert_args_to_ascii(argc,wargv);
594         trace_level=6;
595
596 #else
597 int
598 main (int argc, char *argv[]) {
599 #endif
600         linphonec_vtable.call_state_changed=linphonec_call_state_changed;
601         linphonec_vtable.notify_presence_recv = linphonec_notify_presence_received;
602         linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
603         linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
604         linphonec_vtable.display_status = linphonec_display_status;
605         linphonec_vtable.display_message=linphonec_display_something;
606         linphonec_vtable.display_warning=linphonec_display_warning;
607         linphonec_vtable.display_url=linphonec_display_url;
608         linphonec_vtable.text_received=linphonec_text_received;
609         linphonec_vtable.dtmf_received=linphonec_dtmf_received;
610         linphonec_vtable.refer_received=linphonec_display_refer;
611         linphonec_vtable.notify_recv=linphonec_notify_received;
612         
613         if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
614
615         linphonec_main_loop (linphonec, sipAddr);
616
617         linphonec_finish(EXIT_SUCCESS);
618
619         exit(EXIT_SUCCESS); /* should never reach here */
620 }
621
622 /*
623  * Initialize linphonec
624  */
625 static int
626 linphonec_init(int argc, char **argv)
627 {
628
629         //g_mem_set_vtable(&dbgtable);
630
631         /*
632          * Set initial values for global variables
633          */
634         mylogfile = NULL;
635         
636         
637 #ifndef _WIN32
638         snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
639                         getenv("HOME"));
640 #elif defined(_WIN32_WCE)
641         strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX);
642         mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w");
643         printf("Logs are redirected in" PACKAGE_DIR "\\linphonec.log");
644 #else
645         snprintf(configfile_name, PATH_MAX, "%s/Linphone/linphonerc",
646                         getenv("APPDATA"));
647 #endif
648         /* Handle configuration filename changes */
649         switch (handle_configfile_migration())
650         {
651                 case -1: /* error during file copies */
652                         fprintf(stderr,
653                                 "Error in configuration file migration\n");
654                         break;
655
656                 case 0: /* nothing done */
657                 case 1: /* migrated */
658                 default:
659                         break;
660         }
661
662 #ifdef ENABLE_NLS
663         if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR))
664                 perror ("bindtextdomain failed");
665 #ifndef __ARM__
666         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
667 #endif
668         textdomain (GETTEXT_PACKAGE);
669 #else
670         printf ("NLS disabled.\n");
671 #endif
672
673         linphonec_parse_cmdline(argc, argv);
674
675         if (trace_level > 0)
676         {
677                 if (logfile_name != NULL)
678                         mylogfile = fopen (logfile_name, "w+");
679
680                 if (mylogfile == NULL)
681                 {
682                         mylogfile = stdout;
683                         fprintf (stderr,
684                                  "INFO: no logfile, logging to stdout\n");
685                 }
686                 linphone_core_enable_logs(mylogfile);
687         }
688         else
689         {
690                 linphone_core_disable_logs();
691         }
692         /*
693          * Initialize auth stack
694          */
695         auth_stack.nitems=0;
696
697         /*
698          * Initialize linphone core
699          */
700         linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL);
701         linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
702         linphone_core_enable_video_preview(linphonec,preview_enabled);
703         if (!(vcap_enabled || display_enabled)) printf("Warning: video is disabled in linphonec, use -V or -C or -D to enable.\n");
704 #ifdef HAVE_READLINE
705         /*
706          * Initialize readline
707          */
708         linphonec_initialize_readline();
709 #endif
710 #if !defined(_WIN32_WCE)
711         /*
712          * Initialize signal handlers
713          */
714         signal(SIGTERM, linphonec_finish);
715         signal(SIGINT, linphonec_finish);
716 #endif /*_WIN32_WCE*/
717         return 1;
718 }
719
720
721 void linphonec_main_loop_exit(void){
722         linphonec_running=FALSE;
723 }
724
725 /*
726  * Close linphonec, cleanly terminating
727  * any pending call
728  */
729 void
730 linphonec_finish(int exit_status)
731 {
732         // Do not allow concurrent destroying to prevent glibc errors
733         static bool_t terminating=FALSE;
734         if (terminating) return; 
735         terminating=TRUE;
736         linphonec_out("Terminating...\n");
737
738         /* Terminate any pending call */
739         linphone_core_terminate_all_calls(linphonec);
740 #ifdef HAVE_READLINE
741         linphonec_finish_readline();
742 #endif
743 #if !defined(_WIN32_WCE)
744         if (pipe_reader_run)
745                 stop_pipe_reader();
746 #endif /*_WIN32_WCE*/
747
748         linphone_core_destroy (linphonec);
749
750         if (mylogfile != NULL && mylogfile != stdout)
751         {
752                 fclose (mylogfile);
753         }
754         printf("\n");
755         exit(exit_status);
756
757 }
758
759 /*
760  * This is called from idle_call() whenever
761  * pending_auth != NULL.
762  *
763  * It prompts user for a password.
764  * Hitting ^D (EOF) would make this function
765  * return 0 (Cancel).
766  * Any other input would try to set linphone core
767  * auth_password for the pending_auth, add the auth_info
768  * and return 1.
769  */
770 int
771 linphonec_prompt_for_auth_final(LinphoneCore *lc)
772 {
773         char *input, *iptr;
774         char auth_prompt[256];
775 #ifdef HAVE_READLINE
776         rl_hook_func_t *old_event_hook;
777 #endif
778         LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1];
779
780         snprintf(auth_prompt, 256, "Password for %s on %s: ",
781                 pending_auth->username, pending_auth->realm);
782
783         printf("\n");
784 #ifdef HAVE_READLINE
785         /*
786          * Disable event hook to avoid entering an
787          * infinite loop. This would prevent idle_call
788          * from being called during authentication reads.
789          * Note that it might be undesiderable...
790          */
791         old_event_hook=rl_event_hook;
792         rl_event_hook=NULL;
793 #endif
794
795         while (1)
796         {
797                 input=linphonec_readline(auth_prompt);
798
799                 /*
800                  * If EOF (^D) is sent you probably don't want
801                  * to provide an auth password... should give up
802                  * the operation, but there's no mechanism to
803                  * send this info back to caller currently...
804                  */
805                 if ( ! input )
806                 {
807                         printf("Cancel requested, but not implemented.\n");
808                         continue;
809                 }
810
811                 /* Strip blanks */
812                 iptr=lpc_strip_blanks(input);
813
814                 /*
815                  * Only blanks, continue asking
816                  */
817                 if ( ! *iptr )
818                 {
819                         free(input);
820                         continue;
821                 }
822
823                 /* Something typed, let's try */
824                 break;
825         }
826
827         /*
828          * No check is done here to ensure password is correct.
829          * I guess password will be asked again later.
830          */
831         linphone_auth_info_set_passwd(pending_auth, input);
832         linphone_core_add_auth_info(lc, pending_auth);
833         linphone_auth_info_destroy(pending_auth);
834         auth_stack.elem[auth_stack.nitems-1]=0;
835         --(auth_stack.nitems);
836 #ifdef HAVE_READLINE
837         /*
838          * Reset line_buffer, to avoid the password
839          * to be used again from outer readline
840          */
841         rl_line_buffer[0]='\0';
842         rl_event_hook=old_event_hook;
843 #endif
844         return 1;
845 }
846
847 void
848 print_usage (int exit_status)
849 {
850         fprintf (stdout, "\n\
851 usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\
852        linphonec -v\n\
853 \n\
854   -b  file             specify path of readonly factory configuration file.\n\
855   -c  file             specify path of configuration file.\n\
856   -d  level            be verbose. 0 is no output. 6 is all output\n\
857   -l  logfile          specify the log file for your SIP phone\n\
858   -s  sipaddress       specify the sip call to do at startup\n\
859   -a                   enable auto answering for incoming calls\n\
860   -V                   enable video features globally (disabled by default)\n\
861   -C                   enable video capture only (disabled by default)\n\
862   -D                   enable video display only (disabled by default)\n\
863   -S                   show general state messages (disabled by default)\n\
864   -v or --version      display version and exits.\n");
865
866         exit(exit_status);
867 }
868
869 #ifdef VIDEO_ENABLED
870
871 #ifdef HAVE_X11_XLIB_H
872 static void sdl_x11_apply_video_params(){
873         static SDL_SysWMinfo info;
874         bool_t wminfo_ready=FALSE;
875         
876         
877         SDL_VERSION(&info.version);
878         if ( SDL_GetWMInfo(&info) ) {
879                 if ( info.subsystem == SDL_SYSWM_X11 ) {
880                         wminfo_ready=TRUE;
881                 }
882         }
883         
884         if ( !wminfo_ready) return;
885         
886         {
887                 XWindowChanges wc;
888                 unsigned int flags=0;
889                 Display *display = info.info.x11.display;
890                 Window window = info.info.x11.wmwindow;
891                 
892                 memset(&wc,0,sizeof(wc));
893                 wc.x=lpc_video_params.x;
894                 wc.y=lpc_video_params.y;
895                 wc.width=lpc_video_params.w;
896                 wc.height=lpc_video_params.h;
897                 if (lpc_video_params.x!=-1 ){
898                         flags|=CWX|CWY;
899                 }
900                 if (lpc_video_params.w!=-1){
901                         flags|=CWWidth|CWHeight;
902                 }
903                 info.info.x11.lock_func();
904                 XConfigureWindow(display,window,flags,&wc);
905                 if (lpc_video_params.show)
906                         XMapWindow(display,window);
907                 else
908                         XUnmapWindow(display,window);
909                 info.info.x11.unlock_func();
910         }
911 }
912 #endif
913
914
915 static void lpc_apply_video_params(){
916         static unsigned long prev_wid=0;
917
918         unsigned long wid=linphone_core_get_native_video_window_id (linphonec);
919
920         if (wid!=0 && (lpc_video_params.refresh || prev_wid!=wid)){
921                 lpc_video_params.refresh=FALSE;
922 #ifdef HAVE_X11_XLIB_H
923                 if (lpc_video_params.wid==0){  // do not manage window if embedded
924                         sdl_x11_apply_video_params();
925                 }
926 #endif
927         }
928         prev_wid=wid;
929 }
930
931 #endif
932
933
934 /*
935  *
936  * Called every second from main read loop.
937  *
938  * Will use the following globals:
939  *
940  *  - LinphoneCore linphonec
941  *  - LPC_AUTH_STACK auth_stack;
942  *
943  */
944 static int
945 linphonec_idle_call ()
946 {
947         LinphoneCore *opm=linphonec;
948
949         /* Uncomment the following to verify being called */
950         /* printf(".\n"); */
951
952         linphone_core_iterate(opm);
953         if (answer_call){
954                 fprintf (stdout, "-------auto answering to call-------\n" );
955                 linphone_core_accept_call(opm,NULL);
956                 answer_call=FALSE;
957         }
958
959         if ( auth_stack.nitems )
960         {
961                 /*
962                  * Inhibit command completion
963                  * during password prompts
964                  */
965 #ifdef HAVE_READLINE
966                 rl_inhibit_completion=1;
967 #endif
968                 linphonec_prompt_for_auth_final(opm);
969 #ifdef HAVE_READLINE
970                 rl_inhibit_completion=0;
971 #endif
972         }
973
974 #ifdef VIDEO_ENABLED
975         lpc_apply_video_params();
976 #endif
977
978         return 0;
979 }
980
981 #ifdef HAVE_READLINE
982 /*
983  * Use globals:
984  *
985  *      - char *histfile_name (also sets this)
986  *      - char *last_in_history (allocates it)
987  */
988 static int
989 linphonec_initialize_readline()
990 {
991         /*rl_bind_key('\t', rl_insert);*/
992
993         /* Allow conditional parsing of ~/.inputrc */
994         rl_readline_name = "linphonec";
995
996         /* Call idle_call() every second */
997         rl_set_keyboard_input_timeout(LPC_READLINE_TIMEOUT);
998         rl_event_hook=linphonec_idle_call;
999
1000         /* Set history file and read it */
1001         histfile_name = ms_strdup_printf ("%s/.linphonec_history",
1002                 getenv("HOME"));
1003         read_history(histfile_name);
1004
1005         /* Initialized last_in_history cache*/
1006         last_in_history[0] = '\0';
1007
1008         /* Register a completion function */
1009         rl_attempted_completion_function = linephonec_readline_completion;
1010
1011         /* printf("Readline initialized.\n"); */
1012         setlinebuf(stdout);
1013         return 0;
1014 }
1015
1016 /*
1017  * Uses globals:
1018  *
1019  *      - char *histfile_name (writes history to file and frees it)
1020  *      - char *last_in_history (frees it)
1021  *
1022  */
1023 static int
1024 linphonec_finish_readline()
1025 {
1026
1027         stifle_history(HISTSIZE);
1028         write_history(histfile_name);
1029         free(histfile_name);
1030         histfile_name=NULL;
1031         return 0;
1032 }
1033
1034 #endif
1035
1036 static void print_prompt(LinphoneCore *opm){
1037 #ifdef IDENTITY_AS_PROMPT
1038         snprintf(prompt, PROMPT_MAX_LEN, "%s> ",
1039                 linphone_core_get_primary_contact(opm));
1040 #else
1041         snprintf(prompt, PROMPT_MAX_LEN, "linphonec> ");
1042 #endif
1043 }
1044
1045 static int
1046 linphonec_main_loop (LinphoneCore * opm, char * sipAddr)
1047 {
1048         char buf[LINE_MAX_LEN]; /* auto call handling */
1049         char *input;
1050
1051         print_prompt(opm);
1052
1053
1054         /* auto call handling */
1055         if (sipAddr != NULL )
1056         {
1057                 snprintf (buf, sizeof(buf),"call %s", sipAddr);
1058                 linphonec_parse_command_line(linphonec, buf);
1059         }
1060
1061         while (linphonec_running && (input=linphonec_readline(prompt)))
1062         {
1063                 char *iptr; /* input and input pointer */
1064                 size_t input_len;
1065
1066                 /* Strip blanks */
1067                 iptr=lpc_strip_blanks(input);
1068
1069                 input_len = strlen(iptr);
1070
1071                 /*
1072                  * Do nothing but release memory
1073                  * if only blanks are read
1074                  */
1075                 if ( ! input_len )
1076                 {
1077                         free(input);
1078                         continue;
1079                 }
1080
1081 #ifdef HAVE_READLINE
1082                 /*
1083                  * Only add to history if not already
1084                  * last item in it, and only if the command
1085                  * doesn't start with a space (to allow for
1086                  * hiding passwords)
1087                  */
1088                 if ( iptr == input && strcmp(last_in_history, iptr) )
1089                 {
1090                         strncpy(last_in_history,iptr,sizeof(last_in_history));
1091                         last_in_history[sizeof(last_in_history)-1]='\0';
1092                         add_history(iptr);
1093                 }
1094 #endif
1095
1096                 linphonec_parse_command_line(linphonec, iptr);
1097                 linphonec_command_finished();
1098                 free(input);
1099         }
1100
1101         return 0;
1102 }
1103
1104 /*
1105  *  Parse command line switches
1106  *
1107  *  Use globals:
1108  *
1109  *      - int trace_level
1110  *      - char *logfile_name
1111  *      - char *configfile_name
1112  *      - char *sipAddr
1113  */
1114 static int
1115 linphonec_parse_cmdline(int argc, char **argv)
1116 {
1117         int arg_num=1;
1118
1119         while (arg_num < argc)
1120         {
1121                 int old_arg_num = arg_num;
1122                 if (strncmp ("-d", argv[arg_num], 2) == 0)
1123                 {
1124                         arg_num++;
1125                         if (arg_num < argc)
1126                                 trace_level = atoi (argv[arg_num]);
1127                         else
1128                                 trace_level = 1;
1129                 }
1130                 else if (strncmp ("-l", argv[arg_num], 2) == 0)
1131                 {
1132                         arg_num++;
1133                         if (arg_num < argc)
1134                                 logfile_name = argv[arg_num];
1135                 }
1136                 else if (strncmp ("-c", argv[arg_num], 2) == 0)
1137                 {
1138                         if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE);
1139 #if !defined(_WIN32_WCE)
1140                         if (access(argv[arg_num],F_OK)!=0 )
1141                         {
1142                                 fprintf (stderr,
1143                                         "Cannot open config file %s.\n",
1144                                          argv[arg_num]);
1145                                 exit(EXIT_FAILURE);
1146                         }
1147 #endif /*_WIN32_WCE*/
1148                         snprintf(configfile_name, PATH_MAX, "%s", argv[arg_num]);
1149                 }
1150                 else if (strncmp ("-b", argv[arg_num], 2) == 0)
1151                 {
1152                         if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE);
1153 #if !defined(_WIN32_WCE)
1154                         if (access(argv[arg_num],F_OK)!=0 )
1155                         {
1156                                 fprintf (stderr,
1157                                         "Cannot open config file %s.\n",
1158                                          argv[arg_num]);
1159                                 exit(EXIT_FAILURE);
1160                         }
1161 #endif /*_WIN32_WCE*/
1162                         factory_configfile_name = argv[arg_num];
1163                 }
1164                 else if (strncmp ("-s", argv[arg_num], 2) == 0)
1165                 {
1166                         arg_num++;
1167                         if (arg_num < argc)
1168                                 sipAddr = argv[arg_num];
1169                 }
1170                 else if (strncmp ("-a", argv[arg_num], 2) == 0)
1171                 {
1172                         auto_answer = TRUE;
1173                 }
1174                 else if (strncmp ("-C", argv[arg_num], 2) == 0)
1175                 {
1176                         vcap_enabled = TRUE;
1177                 }
1178                 else if (strncmp ("-D", argv[arg_num], 2) == 0)
1179                 {
1180                         display_enabled = TRUE;
1181                 }
1182                 else if (strncmp ("-V", argv[arg_num], 2) == 0)
1183                 {
1184                         display_enabled = TRUE;
1185                         vcap_enabled = TRUE;
1186                         preview_enabled=TRUE;
1187                 }
1188                 else if ((strncmp ("-v", argv[arg_num], 2) == 0)
1189                          ||
1190                          (strncmp
1191                           ("--version", argv[arg_num],
1192                            strlen ("--version")) == 0))
1193                 {
1194 #if !defined(_WIN32_WCE)
1195                         printf ("version: " LINPHONE_VERSION "\n");
1196 #endif
1197                         exit (EXIT_SUCCESS);
1198                 }
1199                 else if (strncmp ("-S", argv[arg_num], 2) == 0)
1200                 {
1201                         show_general_state = TRUE;
1202                 }
1203                 else if (strncmp ("--pipe", argv[arg_num], 6) == 0)
1204                 {
1205                         unix_socket=1;
1206                 }
1207                 else if (old_arg_num == arg_num)
1208                 {
1209                         fprintf (stderr, "ERROR: bad arguments\n");
1210                         print_usage (EXIT_FAILURE);
1211                 }
1212                 arg_num++;
1213         }
1214
1215         return 1;
1216 }
1217
1218 /*
1219  * Up to version 1.2.1 linphone used ~/.linphonec for
1220  * CLI and ~/.gnome2/linphone for GUI as configuration file.
1221  * In newer version both interfaces will use ~/.linphonerc.
1222  *
1223  * This function helps transparently migrating from one
1224  * to the other layout using the following heuristic:
1225  *
1226  *      IF new_config EXISTS => do nothing
1227  *      ELSE IF old_cli_config EXISTS => copy to new_config
1228  *      ELSE IF old_gui_config EXISTS => copy to new_config
1229  *
1230  * Returns:
1231  *       0 if it did nothing
1232  *       1 if it migrated successfully
1233  *      -1 on error
1234  */
1235 static int
1236 handle_configfile_migration()
1237 {
1238 #if !defined(_WIN32_WCE)
1239         char *old_cfg_gui;
1240         char *old_cfg_cli;
1241         char *new_cfg;
1242 #if !defined(_WIN32_WCE)
1243         const char *home = getenv("HOME");
1244 #else
1245         const char *home = ".";
1246 #endif /*_WIN32_WCE*/
1247         new_cfg = ms_strdup_printf("%s/.linphonerc", home);
1248
1249         /*
1250          * If the *NEW* configuration already exists
1251          * do nothing.
1252          */
1253         if (access(new_cfg,F_OK)==0)
1254         {
1255                 free(new_cfg);
1256                 return 0;
1257         }
1258
1259         old_cfg_cli = ms_strdup_printf("%s/.linphonec", home);
1260
1261         /*
1262          * If the *OLD* CLI configurations exist copy it to
1263          * the new file and make it a symlink.
1264          */
1265         if (access(old_cfg_cli, F_OK)==0)
1266         {
1267                 if ( ! copy_file(old_cfg_cli, new_cfg) )
1268                 {
1269                         free(old_cfg_cli);
1270                         free(new_cfg);
1271                         return -1;
1272                 }
1273                 printf("%s copied to %s\n", old_cfg_cli, new_cfg);
1274                 free(old_cfg_cli);
1275                 free(new_cfg);
1276                 return 1;
1277         }
1278
1279         free(old_cfg_cli);
1280         old_cfg_gui = ms_strdup_printf("%s/.gnome2/linphone", home);
1281
1282         /*
1283          * If the *OLD* GUI configurations exist copy it to
1284          * the new file and make it a symlink.
1285          */
1286         if (access(old_cfg_gui, F_OK)==0)
1287         {
1288                 if ( ! copy_file(old_cfg_gui, new_cfg) )
1289                 {
1290                         exit(EXIT_FAILURE);
1291                         free(old_cfg_gui);
1292                         free(new_cfg);
1293                         return -1;
1294                 }
1295                 printf("%s copied to %s\n", old_cfg_gui, new_cfg);
1296                 free(old_cfg_gui);
1297                 free(new_cfg);
1298                 return 1;
1299         }
1300
1301         free(old_cfg_gui);
1302         free(new_cfg);
1303 #endif /*_WIN32_WCE*/
1304         return 0;
1305 }
1306 #if !defined(_WIN32_WCE)
1307 /*
1308  * Copy file "from" to file "to".
1309  * Destination file is truncated if existing.
1310  * Return 1 on success, 0 on error (printing an error).
1311  */
1312 static int
1313 copy_file(const char *from, const char *to)
1314 {
1315         char message[256];
1316         FILE *in, *out;
1317         char buf[256];
1318         size_t n;
1319
1320         /* Open "from" file for reading */
1321         in=fopen(from, "r");
1322         if ( in == NULL )
1323         {
1324                 snprintf(message, 255, "Can't open %s for reading: %s\n",
1325                         from, strerror(errno));
1326                 fprintf(stderr, "%s", message);
1327                 return 0;
1328         }
1329
1330         /* Open "to" file for writing (will truncate existing files) */
1331         out=fopen(to, "w");
1332         if ( out == NULL )
1333         {
1334                 snprintf(message, 255, "Can't open %s for writing: %s\n",
1335                         to, strerror(errno));
1336                 fprintf(stderr, "%s", message);
1337                 return 0;
1338         }
1339
1340         /* Copy data from "in" to "out" */
1341         while ( (n=fread(buf, 1, sizeof buf, in)) > 0 )
1342         {
1343                 if ( ! fwrite(buf, 1, n, out) )
1344                 {
1345                         return 0;
1346                 }
1347         }
1348
1349         fclose(in);
1350         fclose(out);
1351
1352         return 1;
1353 }
1354 #endif /*_WIN32_WCE*/
1355
1356 #ifdef HAVE_READLINE
1357 static char **
1358 linephonec_readline_completion(const char *text, int start, int end)
1359 {
1360         char **matches = NULL;
1361
1362         /*
1363          * Prevent readline from falling
1364          * back to filename-completion
1365          */
1366         rl_attempted_completion_over=1;
1367
1368         /*
1369          * If this is the start of line we complete with commands
1370          */
1371         if ( ! start )
1372         {
1373                 return rl_completion_matches(text, linphonec_command_generator);
1374         }
1375
1376         /*
1377          * Otherwise, we should peek at command name
1378          * or context to implement a smart completion.
1379          * For example: "call .." could return
1380          * friends' sip-uri as matches
1381          */
1382
1383         return matches;
1384 }
1385
1386 #endif
1387
1388 /*
1389  * Strip blanks from a string.
1390  * Return a pointer into the provided string.
1391  * Modifies input adding a NULL at first
1392  * of trailing blanks.
1393  */
1394 char *
1395 lpc_strip_blanks(char *input)
1396 {
1397         char *iptr;
1398
1399         /* Find first non-blank */
1400         while(*input && isspace(*input)) ++input;
1401
1402         /* Find last non-blank */
1403         iptr=input+strlen(input);
1404         if (iptr > input) {
1405                 while(isspace(*--iptr));
1406                 *(iptr+1)='\0';
1407         }
1408
1409         return input;
1410 }
1411
1412 /****************************************************************************
1413  *
1414  * $Log: linphonec.c,v $
1415  * Revision 1.57  2007/11/14 13:40:27  smorlat
1416  * fix --disable-video build.
1417  *
1418  * Revision 1.56  2007/09/26 14:07:27  fixkowalski
1419  * - ANSI/C++ compilation issues with non-GCC compilers
1420  * - Faster epm-based packaging
1421  * - Ability to build & run on FC6's eXosip/osip
1422  *
1423  * Revision 1.55  2007/09/24 16:01:58  smorlat
1424  * fix bugs.
1425  *
1426  * Revision 1.54  2007/08/22 14:06:11  smorlat
1427  * authentication bugs fixed.
1428  *
1429  * Revision 1.53  2007/02/13 21:31:01  smorlat
1430  * added patch for general state.
1431  * new doxygen for oRTP
1432  * gtk-doc removed.
1433  *
1434  * Revision 1.52  2007/01/10 14:11:24  smorlat
1435  * add --video to linphonec.
1436  *
1437  * Revision 1.51  2006/08/21 12:49:59  smorlat
1438  * merged several little patches.
1439  *
1440  * Revision 1.50  2006/07/26 08:17:28  smorlat
1441  * fix bugs.
1442  *
1443  * Revision 1.49  2006/07/17 18:45:00  smorlat
1444  * support for several event queues in ortp.
1445  * glib dependency removed from coreapi/ and console/
1446  *
1447  * Revision 1.48  2006/04/09 12:45:32  smorlat
1448  * linphonec improvements.
1449  *
1450  * Revision 1.47  2006/04/04 08:04:34  smorlat
1451  * switched to mediastreamer2, most bugs fixed.
1452  *
1453  * Revision 1.46  2006/03/16 17:17:40  smorlat
1454  * fix various bugs.
1455  *
1456  * Revision 1.45  2006/03/12 21:48:31  smorlat
1457  * gcc-2.95 compile error fixed.
1458  * mediastreamer2 in progress
1459  *
1460  * Revision 1.44  2006/03/04 11:17:10  smorlat
1461  * mediastreamer2 in progress.
1462  *
1463  * Revision 1.43  2006/02/13 09:50:50  strk
1464  * fixed unused variable warning.
1465  *
1466  * Revision 1.42  2006/02/02 15:39:18  strk
1467  * - Added 'friend list' and 'friend call' commands
1468  * - Allowed for multiple DTFM send in a single line
1469  * - Added status-specific callback (bare version)
1470  *
1471  * Revision 1.41  2006/02/02 13:30:05  strk
1472  * - Padded vtable with missing callbacks
1473  *   (fixing a segfault on friends subscription)
1474  * - Handled friends notify (bare version)
1475  * - Handled text messages receive (bare version)
1476  * - Printed message on subscription request (bare version)
1477  *
1478  * Revision 1.40  2006/01/26 09:48:05  strk
1479  * Added limits.h include
1480  *
1481  * Revision 1.39  2006/01/26 02:11:01  strk
1482  * Removed unused variables, fixed copyright date
1483  *
1484  * Revision 1.38  2006/01/25 18:33:02  strk
1485  * Removed the -t swich, terminate_on_close made the default behaviour
1486  *
1487  * Revision 1.37  2006/01/20 14:12:34  strk
1488  * Added linphonec_init() and linphonec_finish() functions.
1489  * Handled SIGINT and SIGTERM to invoke linphonec_finish().
1490  * Handling of auto-termination (-t) moved to linphonec_finish().
1491  * Reworked main (input read) loop to not rely on 'terminate'
1492  * and 'run' variable (dropped). configfile_name allocated on stack
1493  * using PATH_MAX limit. Changed print_usage signature to allow
1494  * for an exit_status specification.
1495  *
1496  * Revision 1.36  2006/01/18 09:25:32  strk
1497  * Command completion inhibited in proxy addition and auth request prompts.
1498  * Avoided use of readline's internal filename completion.
1499  *
1500  * Revision 1.35  2006/01/14 13:29:32  strk
1501  * Reworked commands interface to use a table structure,
1502  * used by command line parser and help function.
1503  * Implemented first level of completion (commands).
1504  * Added notification of invalid "answer" and "terminate"
1505  * commands (no incoming call, no active call).
1506  * Forbidden "call" intialization when a call is already active.
1507  * Cleaned up all commands, adding more feedback and error checks.
1508  *
1509  * Revision 1.34  2006/01/13 13:00:29  strk
1510  * Added linphonec.h. Code layout change (added comments, forward decl,
1511  * globals on top, copyright notices and Logs). Handled out-of-memory
1512  * condition on history management. Removed assumption on sizeof(char).
1513  * Fixed bug in authentication prompt (introduced by readline).
1514  * Added support for multiple authentication requests (up to MAX_PENDING_AUTH).
1515  *
1516  *
1517  ****************************************************************************/
1518