1 /****************************************************************************
3 * $Id: linphonec.c,v 1.57 2007/11/14 13:40:27 smorlat Exp $
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>
9 ****************************************************************************
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.
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.
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.
25 ****************************************************************************/
29 #include <sys/types.h>
33 #include "private.h" /*coreapi/private.h, needed for LINPHONE_VERSION */
38 #include <linphonecore.h>
40 #include "linphonec.h"
49 #include <sys/socket.h>
55 #if defined(_WIN32_WCE)
57 #if !defined(PATH_MAX)
62 #define strdup _strdup
70 #define _(String) gettext(String)
73 #define _(something) (something)
77 #define PACKAGE_DIR ""
80 /***************************************************************************
84 ***************************************************************************/
87 LinphoneAuthInfo *elem[MAX_PENDING_AUTH];
91 /***************************************************************************
93 * Forward declarations
95 ***************************************************************************/
97 char *lpc_strip_blanks(char *input);
99 static int handle_configfile_migration(void);
100 #if !defined(_WIN32_WCE)
101 static int copy_file(const char *from, const char *to);
102 #endif /*_WIN32_WCE*/
103 static int linphonec_parse_cmdline(int argc, char **argv);
104 static int linphonec_init(int argc, char **argv);
105 static int linphonec_main_loop (LinphoneCore * opm, char * sipAddr);
106 static int linphonec_idle_call (void);
108 static int linphonec_initialize_readline(void);
109 static int linphonec_finish_readline();
110 static char **linephonec_readline_completion(const char *text,
114 /* These are callback for linphone core */
115 static void linphonec_call_received(LinphoneCore *lc, LinphoneCall *call);
116 static void linphonec_paused_received(LinphoneCore *lc, LinphoneCall *call);
117 static void linphonec_resumed_received(LinphoneCore *lc, LinphoneCall *call);
118 static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm,
119 const char *username);
120 static void linphonec_display_refer (LinphoneCore * lc,LinphoneCall *call, const char *refer_to);
121 static void linphonec_display_something (LinphoneCore * lc, const char *something);
122 static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
123 static void linphonec_display_warning (LinphoneCore * lc, const char *something);
124 static void stub () {}
125 static void linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg);
126 static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid);
127 static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
128 LinphoneFriend *lf, const char *url);
129 static void linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call);
130 static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
131 const char *from, const char *msg);
132 static void linphonec_display_status (LinphoneCore * lc, const char *something);
133 static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate);
134 static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf);
135 static void print_prompt(LinphoneCore *opm);
136 void linphonec_out(const char *fmt,...);
137 /***************************************************************************
141 ***************************************************************************/
143 LinphoneCore *linphonec;
146 static char *histfile_name=NULL;
147 static char last_in_history[256];
149 //auto answer (-a) option
150 static bool_t auto_answer=FALSE;
151 static bool_t answer_call=FALSE;
152 static bool_t vcap_enabled=FALSE;
153 static bool_t display_enabled=FALSE;
154 static bool_t preview_enabled=FALSE;
155 static bool_t show_general_state=FALSE;
156 static bool_t unix_socket=FALSE;
157 static bool_t linphonec_running=TRUE;
158 LPC_AUTH_STACK auth_stack;
159 static int trace_level = 0;
160 static char *logfile_name = NULL;
161 static char configfile_name[PATH_MAX];
162 static char *sipAddr = NULL; /* for autocall */
163 #if !defined(_WIN32_WCE)
164 static ortp_pipe_t client_sock=ORTP_PIPE_INVALID;
165 #endif /*_WIN32_WCE*/
166 char prompt[PROMPT_MAX_LEN];
167 #if !defined(_WIN32_WCE)
168 static ortp_thread_t pipe_reader_th;
169 static bool_t pipe_reader_run=FALSE;
170 #endif /*_WIN32_WCE*/
171 #if !defined(_WIN32_WCE)
172 static ortp_pipe_t server_sock;
173 #endif /*_WIN32_WCE*/
176 LinphoneCoreVTable linphonec_vtable
177 #if !defined (_MSC_VER)
179 .show =(ShowInterfaceCb) stub,
180 .inv_recv = linphonec_call_received,
181 .bye_recv = linphonec_bye_received,
182 .ringing_recv = (RingingReceivedCb) stub,
183 .connected_recv = (ConnectedReceivedCb) stub,
184 .failure_recv = (FailureReceivedCb) stub,
185 .paused_recv = linphonec_paused_received,
186 .resumed_recv = linphonec_resumed_received,
187 .notify_recv = linphonec_notify_received,
188 .notify_presence_recv = linphonec_notify_presence_received,
189 .new_unknown_subscriber = linphonec_new_unknown_subscriber,
190 .auth_info_requested = linphonec_prompt_for_auth,
191 .display_status = linphonec_display_status,
192 .display_message=linphonec_display_something,
193 #ifdef VINCENT_MAURY_RSVP
194 /* the yes/no dialog box */
195 .display_yes_no= (DisplayMessageCb) stub,
197 .display_warning=linphonec_display_warning,
198 .display_url=linphonec_display_url,
199 .display_question=(DisplayQuestionCb)stub,
200 .text_received=linphonec_text_received,
201 .general_state=linphonec_general_state,
202 .dtmf_received=linphonec_dtmf_received,
203 .refer_received=linphonec_display_refer
205 #endif /*_WIN32_WCE*/
210 /***************************************************************************
212 * Linphone core callbacks
214 ***************************************************************************/
217 * Linphone core callback
220 linphonec_display_refer (LinphoneCore * lc,LinphoneCall *call, const char *refer_to)
222 fprintf (stdout, "The distant end point asked to transfer the call to %s,don't forget to terminate the call if not\n%s", refer_to,prompt);
227 * Linphone core callback
230 linphonec_display_something (LinphoneCore * lc, const char *something)
232 fprintf (stdout, "%s\n%s", something,prompt);
237 * Linphone core callback
240 linphonec_display_status (LinphoneCore * lc, const char *something)
242 fprintf (stdout, "%s\n%s", something,prompt);
247 * Linphone core callback
250 linphonec_display_warning (LinphoneCore * lc, const char *something)
252 fprintf (stdout, "Warning: %s\n%s", something,prompt);
257 * Linphone core callback
260 linphonec_display_url (LinphoneCore * lc, const char *something, const char *url)
262 fprintf (stdout, "%s : %s\n", something, url);
267 * Linphone core callback
270 linphonec_call_received(LinphoneCore *lc, LinphoneCall *call)
272 char *from=linphone_call_get_remote_address_as_string(call);
273 linphonec_set_caller(from);
280 * Linphone core callback
283 linphonec_paused_received(LinphoneCore *lc, LinphoneCall *call)
285 char *from=linphone_call_get_remote_address_as_string(call);
288 linphonec_out("the call from %s have been paused\n",from);
293 * Linphone core callback
296 linphonec_resumed_received(LinphoneCore *lc, LinphoneCall *call)
298 char *from=linphone_call_get_remote_address_as_string(call);
301 linphonec_out("the call from %s have been resumed\n",from);
309 * Linphone core callback
312 linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username)
314 /* no prompt possible when using pipes or tcp mode*/
316 linphone_core_abort_authentication(lc,NULL);
318 LinphoneAuthInfo *pending_auth;
320 if ( auth_stack.nitems+1 > MAX_PENDING_AUTH )
323 "Can't accept another authentication request.\n"
324 "Consider incrementing MAX_PENDING_AUTH macro.\n");
328 pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm);
329 auth_stack.elem[auth_stack.nitems++]=pending_auth;
334 * Linphone core callback
337 linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg)
339 printf("Notify type %s from %s\n", msg, from);
340 if(!strcmp(msg,"refer"))
342 printf("The distant SIP end point get the refer we can close the call\n");
343 linphonec_parse_command_line(linphonec, "terminate");
348 * Linphone core callback
351 linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid)
353 char *tmp=linphone_address_as_string(linphone_friend_get_address(fid));
354 printf("Friend %s is %s\n", tmp, linphone_online_status_to_string(linphone_friend_get_status(fid)));
356 // todo: update Friend list state (unimplemented)
360 * Linphone core callback
363 linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf,
366 printf("Friend %s requested subscription "
367 "(accept/deny is not implemented yet)\n", url);
368 // This means that this person wishes to be notified
369 // of your presence information (online, busy, away...).
374 * Linphone core callback
377 linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call)
379 // Should change prompt back to original maybe
381 // printing this is unneeded as we'd get a "Communication ended"
382 // message trough display_status callback anyway
383 char *from=linphone_call_get_remote_address_as_string(call);
384 printf("Bye received from %s\n", from);
389 * Linphone core callback
392 linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
393 const char *from, const char *msg)
395 printf("%s: %s\n", from, msg);
396 // TODO: provide mechanism for answering.. ('say' command?)
400 static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf){
401 fprintf(stdout,"Receiving tone %c\n",dtmf);
406 linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate)
408 if (show_general_state) {
409 switch(gstate->new_state) {
410 case GSTATE_POWER_OFF:
411 printf("GSTATE_POWER_OFF");
413 case GSTATE_POWER_STARTUP:
414 printf("GSTATE_POWER_STARTUP");
416 case GSTATE_POWER_ON:
417 printf("GSTATE_POWER_ON");
419 case GSTATE_POWER_SHUTDOWN:
420 printf("GSTATE_POWER_SHUTDOWN");
422 case GSTATE_REG_NONE:
423 printf("GSTATE_REG_NONE");
426 printf("GSTATE_REG_OK");
428 case GSTATE_REG_FAILED:
429 printf("GSTATE_REG_FAILED");
431 case GSTATE_CALL_IDLE:
432 printf("GSTATE_CALL_IDLE");
434 case GSTATE_CALL_OUT_INVITE:
435 printf("GSTATE_CALL_OUT_INVITE");
437 case GSTATE_CALL_OUT_CONNECTED:
438 printf("GSTATE_CALL_OUT_CONNECTED");
440 case GSTATE_CALL_IN_INVITE:
441 printf("GSTATE_CALL_IN_INVITE");
443 case GSTATE_CALL_IN_CONNECTED:
444 printf("GSTATE_CALL_IN_CONNECTED");
446 case GSTATE_CALL_END:
447 printf("GSTATE_CALL_END");
449 case GSTATE_CALL_ERROR:
450 printf("GSTATE_CALL_ERROR");
453 printf("GSTATE_UNKNOWN_%d",gstate->new_state);
455 if (gstate->message) printf(" %s", gstate->message);
460 static char received_prompt[PROMPT_MAX_LEN];
461 static ms_mutex_t prompt_mutex;
462 static bool_t have_prompt=FALSE;
464 static void *prompt_reader_thread(void *arg){
466 char tmp[PROMPT_MAX_LEN];
467 while ((ret=fgets(tmp,sizeof(tmp),stdin))!=NULL){
468 ms_mutex_lock(&prompt_mutex);
469 strcpy(received_prompt,ret);
471 ms_mutex_unlock(&prompt_mutex);
476 static void start_prompt_reader(void){
478 ms_mutex_init(&prompt_mutex,NULL);
479 ortp_thread_create(&th,NULL,prompt_reader_thread,NULL);
481 #if !defined(_WIN32_WCE)
482 static ortp_pipe_t create_server_socket(void){
485 snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
489 DWORD size=sizeof(username)-1;
490 GetUserName(username,&size);
491 snprintf(path,sizeof(path)-1,"linphonec-%s",username);
494 return ortp_server_pipe_create(path);
498 static void *pipe_thread(void*p){
500 server_sock=create_server_socket();
501 if (server_sock==ORTP_PIPE_INVALID) return NULL;
502 while(pipe_reader_run){
503 while(client_sock!=ORTP_PIPE_INVALID){ /*sleep until the last command is finished*/
510 client_sock=ortp_server_pipe_accept_client(server_sock);
511 if (client_sock!=ORTP_PIPE_INVALID){
513 /*now read from the client */
514 if ((len=ortp_pipe_read(client_sock,(uint8_t*)tmp,sizeof(tmp)-1))>0){
515 ortp_mutex_lock(&prompt_mutex);
517 strcpy(received_prompt,tmp);
518 printf("Receiving command '%s'\n",received_prompt);fflush(stdout);
520 ortp_mutex_unlock(&prompt_mutex);
522 printf("read nothing\n");fflush(stdout);
523 ortp_server_pipe_close_client(client_sock);
524 client_sock=ORTP_PIPE_INVALID;
528 if (pipe_reader_run) fprintf(stderr,"accept() failed: %s\n",strerror(errno));
531 ms_message("Exiting pipe_reader_thread.");
536 static void start_pipe_reader(void){
537 ms_mutex_init(&prompt_mutex,NULL);
538 pipe_reader_run=TRUE;
539 ortp_thread_create(&pipe_reader_th,NULL,pipe_thread,NULL);
542 static void stop_pipe_reader(void){
543 pipe_reader_run=FALSE;
544 linphonec_command_finished();
545 ortp_server_pipe_close(server_sock);
546 ortp_thread_join(pipe_reader_th,NULL);
548 #endif /*_WIN32_WCE*/
551 #define BOOL_HAVE_READLINE 1
553 #define BOOL_HAVE_READLINE 0
556 char *linphonec_readline(char *prompt){
557 if (unix_socket || !BOOL_HAVE_READLINE ){
558 static bool_t prompt_reader_started=FALSE;
559 static bool_t pipe_reader_started=FALSE;
560 if (!prompt_reader_started){
561 start_prompt_reader();
562 prompt_reader_started=TRUE;
564 if (unix_socket && !pipe_reader_started){
565 #if !defined(_WIN32_WCE)
567 pipe_reader_started=TRUE;
568 #endif /*_WIN32_WCE*/
570 fprintf(stdout,"%s",prompt);
573 ms_mutex_lock(&prompt_mutex);
575 char *ret=strdup(received_prompt);
577 ms_mutex_unlock(&prompt_mutex);
580 ms_mutex_unlock(&prompt_mutex);
581 linphonec_idle_call();
584 /* Following is to get the video window going as it
585 should. Maybe should we only have this on when the option -V
589 if (PeekMessage(&msg, NULL, 0, 0,1)) {
590 TranslateMessage(&msg);
591 DispatchMessage(&msg);
599 return readline(prompt);
604 void linphonec_out(const char *fmt,...){
607 va_start (args, fmt);
608 res=ortp_strdup_vprintf(fmt,args);
612 #if !defined(_WIN32_WCE)
613 if (client_sock!=ORTP_PIPE_INVALID){
614 if (ortp_pipe_write(client_sock,(uint8_t*)res,strlen(res))==-1){
615 fprintf(stderr,"Fail to send output via pipe: %s",strerror(errno));
618 #endif /*_WIN32_WCE*/
622 void linphonec_command_finished(void){
623 #if !defined(_WIN32_WCE)
624 if (client_sock!=ORTP_PIPE_INVALID){
625 ortp_server_pipe_close_client(client_sock);
626 client_sock=ORTP_PIPE_INVALID;
628 #endif /*_WIN32_WCE*/
631 void linphonec_set_autoanswer(bool_t enabled){
635 bool_t linphonec_get_autoanswer(){
639 /***************************************************************************/
645 * - char *histfile_name
648 #if defined (_WIN32_WCE)
650 char **convert_args_to_ascii(int argc, _TCHAR **wargv){
652 char **result=malloc(argc*sizeof(char*));
655 wcstombs(argtmp,wargv[i],sizeof(argtmp));
656 result[i]=strdup(argtmp);
661 int _tmain(int argc, _TCHAR* wargv[]) {
662 char **argv=convert_args_to_ascii(argc,wargv);
664 linphonec_vtable.show =(ShowInterfaceCb) stub;
665 linphonec_vtable.inv_recv = linphonec_call_received;
666 linphonec_vtable.bye_recv = linphonec_bye_received;
667 linphonec_vtable.notify_presence_recv = linphonec_notify_received;
668 linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
669 linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
670 linphonec_vtable.display_status = linphonec_display_status;
671 linphonec_vtable.display_message=linphonec_display_something;
672 #ifdef VINCENT_MAURY_RSVP
673 /* the yes/no dialog box */
674 linphonec_vtable.display_yes_no= (DisplayMessageCb) stub;
676 linphonec_vtable.display_warning=linphonec_display_warning;
677 linphonec_vtable.display_url=linphonec_display_url;
678 linphonec_vtable.display_question=(DisplayQuestionCb)stub;
679 linphonec_vtable.text_received=linphonec_text_received;
680 linphonec_vtable.general_state=linphonec_general_state;
681 linphonec_vtable.dtmf_received=linphonec_dtmf_received;
685 main (int argc, char *argv[]) {
689 if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
691 linphonec_main_loop (linphonec, sipAddr);
693 linphonec_finish(EXIT_SUCCESS);
695 exit(EXIT_SUCCESS); /* should never reach here */
699 * Initialize linphonec
702 linphonec_init(int argc, char **argv)
705 //g_mem_set_vtable(&dbgtable);
708 * Set initial values for global variables
714 snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
716 #elif defined(_WIN32_WCE)
717 strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX);
718 mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w");
719 printf("Logs are redirected in" PACKAGE_DIR "\\linphonec.log");
721 snprintf(configfile_name, PATH_MAX, "%s/Linphone/linphonerc",
724 /* Handle configuration filename changes */
725 switch (handle_configfile_migration())
727 case -1: /* error during file copies */
729 "Error in configuration file migration\n");
732 case 0: /* nothing done */
733 case 1: /* migrated */
739 if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR))
740 perror ("bindtextdomain failed");
742 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
744 textdomain (GETTEXT_PACKAGE);
746 printf ("NLS disabled.\n");
749 linphonec_parse_cmdline(argc, argv);
753 if (logfile_name != NULL)
754 mylogfile = fopen (logfile_name, "w+");
756 if (mylogfile == NULL)
760 "INFO: no logfile, logging to stdout\n");
762 linphone_core_enable_logs(mylogfile);
766 linphone_core_disable_logs();
769 * Initialize auth stack
774 * Initialize linphone core
776 linphonec=linphone_core_new (&linphonec_vtable, configfile_name, NULL,
778 linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
779 linphone_core_enable_video_preview(linphonec,preview_enabled);
780 if (!(vcap_enabled || display_enabled)) printf("Warning: video is disabled in linphonec, use -V or -C or -D to enable.\n");
783 * Initialize readline
785 linphonec_initialize_readline();
787 #if !defined(_WIN32_WCE)
789 * Initialize signal handlers
791 signal(SIGTERM, linphonec_finish);
792 signal(SIGINT, linphonec_finish);
793 #endif /*_WIN32_WCE*/
798 void linphonec_main_loop_exit(void){
799 linphonec_running=FALSE;
803 * Close linphonec, cleanly terminating
807 linphonec_finish(int exit_status)
809 printf("Terminating...\n");
811 /* Terminate any pending call */
812 linphonec_parse_command_line(linphonec, "terminate");
813 linphonec_command_finished();
815 linphonec_finish_readline();
817 #if !defined(_WIN32_WCE)
820 #endif /*_WIN32_WCE*/
822 linphone_core_destroy (linphonec);
824 if (mylogfile != NULL && mylogfile != stdout)
834 * This is called from idle_call() whenever
835 * pending_auth != NULL.
837 * It prompts user for a password.
838 * Hitting ^D (EOF) would make this function
840 * Any other input would try to set linphone core
841 * auth_password for the pending_auth, add the auth_info
845 linphonec_prompt_for_auth_final(LinphoneCore *lc)
848 char auth_prompt[256];
850 rl_hook_func_t *old_event_hook;
852 LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1];
854 snprintf(auth_prompt, 256, "Password for %s on %s: ",
855 pending_auth->username, pending_auth->realm);
860 * Disable event hook to avoid entering an
861 * infinite loop. This would prevent idle_call
862 * from being called during authentication reads.
863 * Note that it might be undesiderable...
865 old_event_hook=rl_event_hook;
871 input=linphonec_readline(auth_prompt);
874 * If EOF (^D) is sent you probably don't want
875 * to provide an auth password... should give up
876 * the operation, but there's no mechanism to
877 * send this info back to caller currently...
881 printf("Cancel requested, but not implemented.\n");
886 iptr=lpc_strip_blanks(input);
889 * Only blanks, continue asking
897 /* Something typed, let's try */
902 * No check is done here to ensure password is correct.
903 * I guess password will be asked again later.
905 linphone_auth_info_set_passwd(pending_auth, input);
906 linphone_core_add_auth_info(lc, pending_auth);
907 linphone_auth_info_destroy(pending_auth);
908 auth_stack.elem[auth_stack.nitems-1]=0;
909 --(auth_stack.nitems);
912 * Reset line_buffer, to avoid the password
913 * to be used again from outer readline
915 rl_line_buffer[0]='\0';
916 rl_event_hook=old_event_hook;
922 print_usage (int exit_status)
924 fprintf (stdout, "\n\
925 usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\
928 -c file specify path of configuration file.\n\
929 -d level be verbose. 0 is no output. 6 is all output\n\
930 -l logfile specify the log file for your SIP phone\n\
931 -s sipaddress specify the sip call to do at startup\n\
932 -a enable auto answering for incoming calls\n\
933 -V enable video features globally (disabled by default)\n\
934 -C enable video capture only (disabled by default)\n\
935 -D enable video display only (disabled by default)\n\
936 -S show general state messages (disabled by default)\n\
937 -v or --version display version and exits.\n");
945 * Called every second from main read loop.
947 * Will use the following globals:
949 * - LinphoneCore linphonec
950 * - LPC_AUTH_STACK auth_stack;
954 linphonec_idle_call ()
956 LinphoneCore *opm=linphonec;
958 /* Uncomment the following to verify being called */
961 linphone_core_iterate(opm);
963 fprintf (stdout, "-------auto answering to call-------\n" );
964 linphone_core_accept_call(opm,NULL);
968 if ( auth_stack.nitems )
971 * Inhibit command completion
972 * during password prompts
975 rl_inhibit_completion=1;
977 linphonec_prompt_for_auth_final(opm);
979 rl_inhibit_completion=0;
990 * - char *histfile_name (also sets this)
991 * - char *last_in_history (allocates it)
994 linphonec_initialize_readline()
996 /*rl_bind_key('\t', rl_insert);*/
998 /* Allow conditional parsing of ~/.inputrc */
999 rl_readline_name = "linphonec";
1001 /* Call idle_call() every second */
1002 rl_set_keyboard_input_timeout(LPC_READLINE_TIMEOUT);
1003 rl_event_hook=linphonec_idle_call;
1005 /* Set history file and read it */
1006 histfile_name = ms_strdup_printf ("%s/.linphonec_history",
1008 read_history(histfile_name);
1010 /* Initialized last_in_history cache*/
1011 last_in_history[0] = '\0';
1013 /* Register a completion function */
1014 rl_attempted_completion_function = linephonec_readline_completion;
1016 /* printf("Readline initialized.\n"); */
1024 * - char *histfile_name (writes history to file and frees it)
1025 * - char *last_in_history (frees it)
1029 linphonec_finish_readline()
1032 stifle_history(HISTSIZE);
1033 write_history(histfile_name);
1034 free(histfile_name);
1041 static void print_prompt(LinphoneCore *opm){
1042 #ifdef IDENTITY_AS_PROMPT
1043 snprintf(prompt, PROMPT_MAX_LEN, "%s> ",
1044 linphone_core_get_primary_contact(opm));
1046 snprintf(prompt, PROMPT_MAX_LEN, "linphonec> ");
1051 linphonec_main_loop (LinphoneCore * opm, char * sipAddr)
1053 char buf[LINE_MAX_LEN]; /* auto call handling */
1059 /* auto call handling */
1060 if (sipAddr != NULL )
1062 snprintf (buf, sizeof(buf),"call %s", sipAddr);
1063 linphonec_parse_command_line(linphonec, buf);
1066 while (linphonec_running && (input=linphonec_readline(prompt)))
1068 char *iptr; /* input and input pointer */
1072 iptr=lpc_strip_blanks(input);
1074 input_len = strlen(iptr);
1077 * Do nothing but release memory
1078 * if only blanks are read
1086 #ifdef HAVE_READLINE
1088 * Only add to history if not already
1089 * last item in it, and only if the command
1090 * doesn't start with a space (to allow for
1093 if ( iptr == input && strcmp(last_in_history, iptr) )
1095 strncpy(last_in_history,iptr,sizeof(last_in_history));
1096 last_in_history[sizeof(last_in_history)-1]='\0';
1101 linphonec_parse_command_line(linphonec, iptr);
1102 linphonec_command_finished();
1110 * Parse command line switches
1115 * - char *logfile_name
1116 * - char *configfile_name
1120 linphonec_parse_cmdline(int argc, char **argv)
1124 while (arg_num < argc)
1126 int old_arg_num = arg_num;
1127 if (strncmp ("-d", argv[arg_num], 2) == 0)
1131 trace_level = atoi (argv[arg_num]);
1135 else if (strncmp ("-l", argv[arg_num], 2) == 0)
1139 logfile_name = argv[arg_num];
1141 else if (strncmp ("-c", argv[arg_num], 2) == 0)
1143 if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE);
1144 #if !defined(_WIN32_WCE)
1145 if (access(argv[arg_num],F_OK)!=0 )
1148 "Cannot open config file %s.\n",
1152 #endif /*_WIN32_WCE*/
1153 snprintf(configfile_name, PATH_MAX, "%s", argv[arg_num]);
1155 else if (strncmp ("-s", argv[arg_num], 2) == 0)
1159 sipAddr = argv[arg_num];
1161 else if (strncmp ("-a", argv[arg_num], 2) == 0)
1165 else if (strncmp ("-C", argv[arg_num], 2) == 0)
1167 vcap_enabled = TRUE;
1169 else if (strncmp ("-D", argv[arg_num], 2) == 0)
1171 display_enabled = TRUE;
1173 else if (strncmp ("-V", argv[arg_num], 2) == 0)
1175 display_enabled = TRUE;
1176 vcap_enabled = TRUE;
1177 preview_enabled=TRUE;
1179 else if ((strncmp ("-v", argv[arg_num], 2) == 0)
1182 ("--version", argv[arg_num],
1183 strlen ("--version")) == 0))
1185 #if !defined(_WIN32_WCE)
1186 printf ("version: " LINPHONE_VERSION "\n");
1188 exit (EXIT_SUCCESS);
1190 else if (strncmp ("-S", argv[arg_num], 2) == 0)
1192 show_general_state = TRUE;
1194 else if (strncmp ("--pipe", argv[arg_num], 6) == 0)
1198 else if (old_arg_num == arg_num)
1200 fprintf (stderr, "ERROR: bad arguments\n");
1201 print_usage (EXIT_FAILURE);
1210 * Up to version 1.2.1 linphone used ~/.linphonec for
1211 * CLI and ~/.gnome2/linphone for GUI as configuration file.
1212 * In newer version both interfaces will use ~/.linphonerc.
1214 * This function helps transparently migrating from one
1215 * to the other layout using the following heuristic:
1217 * IF new_config EXISTS => do nothing
1218 * ELSE IF old_cli_config EXISTS => copy to new_config
1219 * ELSE IF old_gui_config EXISTS => copy to new_config
1222 * 0 if it did nothing
1223 * 1 if it migrated successfully
1227 handle_configfile_migration()
1229 #if !defined(_WIN32_WCE)
1233 #if !defined(_WIN32_WCE)
1234 const char *home = getenv("HOME");
1236 const char *home = ".";
1237 #endif /*_WIN32_WCE*/
1238 new_cfg = ms_strdup_printf("%s/.linphonerc", home);
1241 * If the *NEW* configuration already exists
1244 if (access(new_cfg,F_OK)==0)
1250 old_cfg_cli = ms_strdup_printf("%s/.linphonec", home);
1253 * If the *OLD* CLI configurations exist copy it to
1254 * the new file and make it a symlink.
1256 if (access(old_cfg_cli, F_OK)==0)
1258 if ( ! copy_file(old_cfg_cli, new_cfg) )
1264 printf("%s copied to %s\n", old_cfg_cli, new_cfg);
1271 old_cfg_gui = ms_strdup_printf("%s/.gnome2/linphone", home);
1274 * If the *OLD* GUI configurations exist copy it to
1275 * the new file and make it a symlink.
1277 if (access(old_cfg_gui, F_OK)==0)
1279 if ( ! copy_file(old_cfg_gui, new_cfg) )
1286 printf("%s copied to %s\n", old_cfg_gui, new_cfg);
1294 #endif /*_WIN32_WCE*/
1297 #if !defined(_WIN32_WCE)
1299 * Copy file "from" to file "to".
1300 * Destination file is truncated if existing.
1301 * Return 1 on success, 0 on error (printing an error).
1304 copy_file(const char *from, const char *to)
1311 /* Open "from" file for reading */
1312 in=fopen(from, "r");
1315 snprintf(message, 255, "Can't open %s for reading: %s\n",
1316 from, strerror(errno));
1317 fprintf(stderr, "%s", message);
1321 /* Open "to" file for writing (will truncate existing files) */
1325 snprintf(message, 255, "Can't open %s for writing: %s\n",
1326 to, strerror(errno));
1327 fprintf(stderr, "%s", message);
1331 /* Copy data from "in" to "out" */
1332 while ( (n=fread(buf, 1, sizeof buf, in)) > 0 )
1334 if ( ! fwrite(buf, 1, n, out) )
1345 #endif /*_WIN32_WCE*/
1347 #ifdef HAVE_READLINE
1349 linephonec_readline_completion(const char *text, int start, int end)
1351 char **matches = NULL;
1354 * Prevent readline from falling
1355 * back to filename-completion
1357 rl_attempted_completion_over=1;
1360 * If this is the start of line we complete with commands
1364 return rl_completion_matches(text, linphonec_command_generator);
1368 * Otherwise, we should peek at command name
1369 * or context to implement a smart completion.
1370 * For example: "call .." could return
1371 * friends' sip-uri as matches
1380 * Strip blanks from a string.
1381 * Return a pointer into the provided string.
1382 * Modifies input adding a NULL at first
1383 * of trailing blanks.
1386 lpc_strip_blanks(char *input)
1390 /* Find first non-blank */
1391 while(*input && isspace(*input)) ++input;
1393 /* Find last non-blank */
1394 iptr=input+strlen(input);
1396 while(isspace(*--iptr));
1403 /****************************************************************************
1405 * $Log: linphonec.c,v $
1406 * Revision 1.57 2007/11/14 13:40:27 smorlat
1407 * fix --disable-video build.
1409 * Revision 1.56 2007/09/26 14:07:27 fixkowalski
1410 * - ANSI/C++ compilation issues with non-GCC compilers
1411 * - Faster epm-based packaging
1412 * - Ability to build & run on FC6's eXosip/osip
1414 * Revision 1.55 2007/09/24 16:01:58 smorlat
1417 * Revision 1.54 2007/08/22 14:06:11 smorlat
1418 * authentication bugs fixed.
1420 * Revision 1.53 2007/02/13 21:31:01 smorlat
1421 * added patch for general state.
1422 * new doxygen for oRTP
1425 * Revision 1.52 2007/01/10 14:11:24 smorlat
1426 * add --video to linphonec.
1428 * Revision 1.51 2006/08/21 12:49:59 smorlat
1429 * merged several little patches.
1431 * Revision 1.50 2006/07/26 08:17:28 smorlat
1434 * Revision 1.49 2006/07/17 18:45:00 smorlat
1435 * support for several event queues in ortp.
1436 * glib dependency removed from coreapi/ and console/
1438 * Revision 1.48 2006/04/09 12:45:32 smorlat
1439 * linphonec improvements.
1441 * Revision 1.47 2006/04/04 08:04:34 smorlat
1442 * switched to mediastreamer2, most bugs fixed.
1444 * Revision 1.46 2006/03/16 17:17:40 smorlat
1447 * Revision 1.45 2006/03/12 21:48:31 smorlat
1448 * gcc-2.95 compile error fixed.
1449 * mediastreamer2 in progress
1451 * Revision 1.44 2006/03/04 11:17:10 smorlat
1452 * mediastreamer2 in progress.
1454 * Revision 1.43 2006/02/13 09:50:50 strk
1455 * fixed unused variable warning.
1457 * Revision 1.42 2006/02/02 15:39:18 strk
1458 * - Added 'friend list' and 'friend call' commands
1459 * - Allowed for multiple DTFM send in a single line
1460 * - Added status-specific callback (bare version)
1462 * Revision 1.41 2006/02/02 13:30:05 strk
1463 * - Padded vtable with missing callbacks
1464 * (fixing a segfault on friends subscription)
1465 * - Handled friends notify (bare version)
1466 * - Handled text messages receive (bare version)
1467 * - Printed message on subscription request (bare version)
1469 * Revision 1.40 2006/01/26 09:48:05 strk
1470 * Added limits.h include
1472 * Revision 1.39 2006/01/26 02:11:01 strk
1473 * Removed unused variables, fixed copyright date
1475 * Revision 1.38 2006/01/25 18:33:02 strk
1476 * Removed the -t swich, terminate_on_close made the default behaviour
1478 * Revision 1.37 2006/01/20 14:12:34 strk
1479 * Added linphonec_init() and linphonec_finish() functions.
1480 * Handled SIGINT and SIGTERM to invoke linphonec_finish().
1481 * Handling of auto-termination (-t) moved to linphonec_finish().
1482 * Reworked main (input read) loop to not rely on 'terminate'
1483 * and 'run' variable (dropped). configfile_name allocated on stack
1484 * using PATH_MAX limit. Changed print_usage signature to allow
1485 * for an exit_status specification.
1487 * Revision 1.36 2006/01/18 09:25:32 strk
1488 * Command completion inhibited in proxy addition and auth request prompts.
1489 * Avoided use of readline's internal filename completion.
1491 * Revision 1.35 2006/01/14 13:29:32 strk
1492 * Reworked commands interface to use a table structure,
1493 * used by command line parser and help function.
1494 * Implemented first level of completion (commands).
1495 * Added notification of invalid "answer" and "terminate"
1496 * commands (no incoming call, no active call).
1497 * Forbidden "call" intialization when a call is already active.
1498 * Cleaned up all commands, adding more feedback and error checks.
1500 * Revision 1.34 2006/01/13 13:00:29 strk
1501 * Added linphonec.h. Code layout change (added comments, forward decl,
1502 * globals on top, copyright notices and Logs). Handled out-of-memory
1503 * condition on history management. Removed assumption on sizeof(char).
1504 * Fixed bug in authentication prompt (introduced by readline).
1505 * Added support for multiple authentication requests (up to MAX_PENDING_AUTH).
1508 ****************************************************************************/