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_ack_paused_received(LinphoneCore *lc, LinphoneCall *call);
127 static void linphonec_ack_resumed_received(LinphoneCore *lc, LinphoneCall *call);
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 static void linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call);
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_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate);
136 static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf);
137 static void print_prompt(LinphoneCore *opm);
138 void linphonec_out(const char *fmt,...);
139 /***************************************************************************
143 ***************************************************************************/
145 LinphoneCore *linphonec;
148 static char *histfile_name=NULL;
149 static char last_in_history[256];
151 //auto answer (-a) option
152 static bool_t auto_answer=FALSE;
153 static bool_t answer_call=FALSE;
154 static bool_t vcap_enabled=FALSE;
155 static bool_t display_enabled=FALSE;
156 static bool_t preview_enabled=FALSE;
157 static bool_t show_general_state=FALSE;
158 static bool_t unix_socket=FALSE;
159 static bool_t linphonec_running=TRUE;
160 LPC_AUTH_STACK auth_stack;
161 static int trace_level = 0;
162 static char *logfile_name = NULL;
163 static char configfile_name[PATH_MAX];
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*/
178 LinphoneCoreVTable linphonec_vtable
179 #if !defined (_MSC_VER)
181 .show =(ShowInterfaceCb) stub,
182 .inv_recv = linphonec_call_received,
183 .bye_recv = linphonec_bye_received,
184 .ringing_recv = (RingingReceivedCb) stub,
185 .connected_recv = (ConnectedReceivedCb) stub,
186 .failure_recv = (FailureReceivedCb) stub,
187 .paused_recv = linphonec_paused_received,
188 .resumed_recv = linphonec_resumed_received,
189 .notify_recv = linphonec_notify_received,
190 .ack_paused_recv = linphonec_ack_paused_received,
191 .ack_resumed_recv = linphonec_ack_resumed_received,
192 .notify_presence_recv = linphonec_notify_presence_received,
193 .new_unknown_subscriber = linphonec_new_unknown_subscriber,
194 .auth_info_requested = linphonec_prompt_for_auth,
195 .display_status = linphonec_display_status,
196 .display_message=linphonec_display_something,
197 #ifdef VINCENT_MAURY_RSVP
198 /* the yes/no dialog box */
199 .display_yes_no= (DisplayMessageCb) stub,
201 .display_warning=linphonec_display_warning,
202 .display_url=linphonec_display_url,
203 .display_question=(DisplayQuestionCb)stub,
204 .text_received=linphonec_text_received,
205 .general_state=linphonec_general_state,
206 .dtmf_received=linphonec_dtmf_received,
207 .refer_received=linphonec_display_refer
209 #endif /*_WIN32_WCE*/
214 /***************************************************************************
216 * Linphone core callbacks
218 ***************************************************************************/
221 * Linphone core callback
224 linphonec_display_refer (LinphoneCore * lc,LinphoneCall *call, const char *refer_to)
226 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);
231 * Linphone core callback
234 linphonec_display_something (LinphoneCore * lc, const char *something)
236 fprintf (stdout, "%s\n%s", something,prompt);
241 * Linphone core callback
244 linphonec_display_status (LinphoneCore * lc, const char *something)
246 fprintf (stdout, "%s\n%s", something,prompt);
251 * Linphone core callback
254 linphonec_display_warning (LinphoneCore * lc, const char *something)
256 fprintf (stdout, "Warning: %s\n%s", something,prompt);
261 * Linphone core callback
264 linphonec_display_url (LinphoneCore * lc, const char *something, const char *url)
266 fprintf (stdout, "%s : %s\n", something, url);
271 * Linphone core callback
274 linphonec_call_received(LinphoneCore *lc, LinphoneCall *call)
276 char *from=linphone_call_get_remote_address_as_string(call);
277 linphonec_set_caller(from);
284 * Linphone core callback
287 linphonec_paused_received(LinphoneCore *lc, LinphoneCall *call)
289 char *from=linphone_call_get_remote_address_as_string(call);
292 linphonec_out("the call from %s have been paused\n",from);
297 * Linphone core callback
300 linphonec_resumed_received(LinphoneCore *lc, LinphoneCall *call)
302 char *from=linphone_call_get_remote_address_as_string(call);
305 linphonec_out("the call from %s have been resumed\n",from);
313 * Linphone core callback
316 linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username)
318 /* no prompt possible when using pipes or tcp mode*/
320 linphone_core_abort_authentication(lc,NULL);
322 LinphoneAuthInfo *pending_auth;
324 if ( auth_stack.nitems+1 > MAX_PENDING_AUTH )
327 "Can't accept another authentication request.\n"
328 "Consider incrementing MAX_PENDING_AUTH macro.\n");
332 pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm);
333 auth_stack.elem[auth_stack.nitems++]=pending_auth;
338 * Linphone core callback
341 linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg)
343 printf("Notify type %s from %s\n", msg, from);
344 if(!strcmp(msg,"refer"))
346 printf("The distant SIP end point get the refer we can close the call\n");
347 linphonec_parse_command_line(linphonec, "terminate");
352 * Linphone core callback
355 linphonec_ack_paused_received(LinphoneCore *lc, LinphoneCall *call)
357 char *from=linphone_call_get_remote_address_as_string(call);
360 linphonec_out("the previous pause sent to %s has been acknowledged\n",from);
366 * Linphone core callback
369 linphonec_ack_resumed_received(LinphoneCore *lc, LinphoneCall *call)
371 char *from=linphone_call_get_remote_address_as_string(call);
374 linphonec_out("the previous resume sent to %s has been acknowledged\n",from);
380 * Linphone core callback
383 linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid)
385 char *tmp=linphone_address_as_string(linphone_friend_get_address(fid));
386 printf("Friend %s is %s\n", tmp, linphone_online_status_to_string(linphone_friend_get_status(fid)));
388 // todo: update Friend list state (unimplemented)
392 * Linphone core callback
395 linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf,
398 printf("Friend %s requested subscription "
399 "(accept/deny is not implemented yet)\n", url);
400 // This means that this person wishes to be notified
401 // of your presence information (online, busy, away...).
406 * Linphone core callback
409 linphonec_bye_received(LinphoneCore *lc, LinphoneCall *call)
411 // Should change prompt back to original maybe
413 // printing this is unneeded as we'd get a "Communication ended"
414 // message trough display_status callback anyway
415 char *from=linphone_call_get_remote_address_as_string(call);
416 printf("Bye received from %s\n", from);
421 * Linphone core callback
424 linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
425 const char *from, const char *msg)
427 printf("%s: %s\n", from, msg);
428 // TODO: provide mechanism for answering.. ('say' command?)
432 static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf){
433 fprintf(stdout,"Receiving tone %c\n",dtmf);
438 linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate)
440 if (show_general_state) {
441 switch(gstate->new_state) {
442 case GSTATE_POWER_OFF:
443 printf("GSTATE_POWER_OFF");
445 case GSTATE_POWER_STARTUP:
446 printf("GSTATE_POWER_STARTUP");
448 case GSTATE_POWER_ON:
449 printf("GSTATE_POWER_ON");
451 case GSTATE_POWER_SHUTDOWN:
452 printf("GSTATE_POWER_SHUTDOWN");
454 case GSTATE_REG_NONE:
455 printf("GSTATE_REG_NONE");
458 printf("GSTATE_REG_OK");
460 case GSTATE_REG_FAILED:
461 printf("GSTATE_REG_FAILED");
463 case GSTATE_CALL_IDLE:
464 printf("GSTATE_CALL_IDLE");
466 case GSTATE_CALL_OUT_INVITE:
467 printf("GSTATE_CALL_OUT_INVITE");
469 case GSTATE_CALL_OUT_CONNECTED:
470 printf("GSTATE_CALL_OUT_CONNECTED");
472 case GSTATE_CALL_IN_INVITE:
473 printf("GSTATE_CALL_IN_INVITE");
475 case GSTATE_CALL_IN_CONNECTED:
476 printf("GSTATE_CALL_IN_CONNECTED");
478 case GSTATE_CALL_END:
479 printf("GSTATE_CALL_END");
481 case GSTATE_CALL_ERROR:
482 printf("GSTATE_CALL_ERROR");
485 printf("GSTATE_UNKNOWN_%d",gstate->new_state);
487 if (gstate->message) printf(" %s", gstate->message);
492 static char received_prompt[PROMPT_MAX_LEN];
493 static ms_mutex_t prompt_mutex;
494 static bool_t have_prompt=FALSE;
496 static void *prompt_reader_thread(void *arg){
498 char tmp[PROMPT_MAX_LEN];
499 while ((ret=fgets(tmp,sizeof(tmp),stdin))!=NULL){
500 ms_mutex_lock(&prompt_mutex);
501 strcpy(received_prompt,ret);
503 ms_mutex_unlock(&prompt_mutex);
508 static void start_prompt_reader(void){
510 ms_mutex_init(&prompt_mutex,NULL);
511 ortp_thread_create(&th,NULL,prompt_reader_thread,NULL);
513 #if !defined(_WIN32_WCE)
514 static ortp_pipe_t create_server_socket(void){
517 snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
521 DWORD size=sizeof(username)-1;
522 GetUserName(username,&size);
523 snprintf(path,sizeof(path)-1,"linphonec-%s",username);
526 return ortp_server_pipe_create(path);
530 static void *pipe_thread(void*p){
532 server_sock=create_server_socket();
533 if (server_sock==ORTP_PIPE_INVALID) return NULL;
534 while(pipe_reader_run){
535 while(client_sock!=ORTP_PIPE_INVALID){ /*sleep until the last command is finished*/
542 client_sock=ortp_server_pipe_accept_client(server_sock);
543 if (client_sock!=ORTP_PIPE_INVALID){
545 /*now read from the client */
546 if ((len=ortp_pipe_read(client_sock,(uint8_t*)tmp,sizeof(tmp)-1))>0){
547 ortp_mutex_lock(&prompt_mutex);
549 strcpy(received_prompt,tmp);
550 printf("Receiving command '%s'\n",received_prompt);fflush(stdout);
552 ortp_mutex_unlock(&prompt_mutex);
554 printf("read nothing\n");fflush(stdout);
555 ortp_server_pipe_close_client(client_sock);
556 client_sock=ORTP_PIPE_INVALID;
560 if (pipe_reader_run) fprintf(stderr,"accept() failed: %s\n",strerror(errno));
563 ms_message("Exiting pipe_reader_thread.");
568 static void start_pipe_reader(void){
569 ms_mutex_init(&prompt_mutex,NULL);
570 pipe_reader_run=TRUE;
571 ortp_thread_create(&pipe_reader_th,NULL,pipe_thread,NULL);
574 static void stop_pipe_reader(void){
575 pipe_reader_run=FALSE;
576 linphonec_command_finished();
577 ortp_server_pipe_close(server_sock);
578 ortp_thread_join(pipe_reader_th,NULL);
580 #endif /*_WIN32_WCE*/
583 #define BOOL_HAVE_READLINE 1
585 #define BOOL_HAVE_READLINE 0
588 char *linphonec_readline(char *prompt){
589 if (unix_socket || !BOOL_HAVE_READLINE ){
590 static bool_t prompt_reader_started=FALSE;
591 static bool_t pipe_reader_started=FALSE;
592 if (!prompt_reader_started){
593 start_prompt_reader();
594 prompt_reader_started=TRUE;
596 if (unix_socket && !pipe_reader_started){
597 #if !defined(_WIN32_WCE)
599 pipe_reader_started=TRUE;
600 #endif /*_WIN32_WCE*/
602 fprintf(stdout,"%s",prompt);
605 ms_mutex_lock(&prompt_mutex);
607 char *ret=strdup(received_prompt);
609 ms_mutex_unlock(&prompt_mutex);
612 ms_mutex_unlock(&prompt_mutex);
613 linphonec_idle_call();
616 /* Following is to get the video window going as it
617 should. Maybe should we only have this on when the option -V
621 if (PeekMessage(&msg, NULL, 0, 0,1)) {
622 TranslateMessage(&msg);
623 DispatchMessage(&msg);
631 return readline(prompt);
636 void linphonec_out(const char *fmt,...){
639 va_start (args, fmt);
640 res=ortp_strdup_vprintf(fmt,args);
644 #if !defined(_WIN32_WCE)
645 if (client_sock!=ORTP_PIPE_INVALID){
646 if (ortp_pipe_write(client_sock,(uint8_t*)res,strlen(res))==-1){
647 fprintf(stderr,"Fail to send output via pipe: %s",strerror(errno));
650 #endif /*_WIN32_WCE*/
654 void linphonec_command_finished(void){
655 #if !defined(_WIN32_WCE)
656 if (client_sock!=ORTP_PIPE_INVALID){
657 ortp_server_pipe_close_client(client_sock);
658 client_sock=ORTP_PIPE_INVALID;
660 #endif /*_WIN32_WCE*/
663 void linphonec_set_autoanswer(bool_t enabled){
667 bool_t linphonec_get_autoanswer(){
671 /***************************************************************************/
677 * - char *histfile_name
680 #if defined (_WIN32_WCE)
682 char **convert_args_to_ascii(int argc, _TCHAR **wargv){
684 char **result=malloc(argc*sizeof(char*));
687 wcstombs(argtmp,wargv[i],sizeof(argtmp));
688 result[i]=strdup(argtmp);
693 int _tmain(int argc, _TCHAR* wargv[]) {
694 char **argv=convert_args_to_ascii(argc,wargv);
696 linphonec_vtable.show =(ShowInterfaceCb) stub;
697 linphonec_vtable.inv_recv = linphonec_call_received;
698 linphonec_vtable.bye_recv = linphonec_bye_received;
699 linphonec_vtable.notify_presence_recv = linphonec_notify_received;
700 linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
701 linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
702 linphonec_vtable.display_status = linphonec_display_status;
703 linphonec_vtable.display_message=linphonec_display_something;
704 #ifdef VINCENT_MAURY_RSVP
705 /* the yes/no dialog box */
706 linphonec_vtable.display_yes_no= (DisplayMessageCb) stub;
708 linphonec_vtable.display_warning=linphonec_display_warning;
709 linphonec_vtable.display_url=linphonec_display_url;
710 linphonec_vtable.display_question=(DisplayQuestionCb)stub;
711 linphonec_vtable.text_received=linphonec_text_received;
712 linphonec_vtable.general_state=linphonec_general_state;
713 linphonec_vtable.dtmf_received=linphonec_dtmf_received;
717 main (int argc, char *argv[]) {
721 if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
723 linphonec_main_loop (linphonec, sipAddr);
725 linphonec_finish(EXIT_SUCCESS);
727 exit(EXIT_SUCCESS); /* should never reach here */
731 * Initialize linphonec
734 linphonec_init(int argc, char **argv)
737 //g_mem_set_vtable(&dbgtable);
740 * Set initial values for global variables
746 snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
748 #elif defined(_WIN32_WCE)
749 strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX);
750 mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w");
751 printf("Logs are redirected in" PACKAGE_DIR "\\linphonec.log");
753 snprintf(configfile_name, PATH_MAX, "%s/Linphone/linphonerc",
756 /* Handle configuration filename changes */
757 switch (handle_configfile_migration())
759 case -1: /* error during file copies */
761 "Error in configuration file migration\n");
764 case 0: /* nothing done */
765 case 1: /* migrated */
771 if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR))
772 perror ("bindtextdomain failed");
774 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
776 textdomain (GETTEXT_PACKAGE);
778 printf ("NLS disabled.\n");
781 linphonec_parse_cmdline(argc, argv);
785 if (logfile_name != NULL)
786 mylogfile = fopen (logfile_name, "w+");
788 if (mylogfile == NULL)
792 "INFO: no logfile, logging to stdout\n");
794 linphone_core_enable_logs(mylogfile);
798 linphone_core_disable_logs();
801 * Initialize auth stack
806 * Initialize linphone core
808 linphonec=linphone_core_new (&linphonec_vtable, configfile_name, NULL,
810 linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
811 linphone_core_enable_video_preview(linphonec,preview_enabled);
812 if (!(vcap_enabled || display_enabled)) printf("Warning: video is disabled in linphonec, use -V or -C or -D to enable.\n");
815 * Initialize readline
817 linphonec_initialize_readline();
819 #if !defined(_WIN32_WCE)
821 * Initialize signal handlers
823 signal(SIGTERM, linphonec_finish);
824 signal(SIGINT, linphonec_finish);
825 #endif /*_WIN32_WCE*/
830 void linphonec_main_loop_exit(void){
831 linphonec_running=FALSE;
835 * Close linphonec, cleanly terminating
839 linphonec_finish(int exit_status)
841 printf("Terminating...\n");
843 /* Terminate any pending call */
844 linphonec_parse_command_line(linphonec, "terminate");
845 linphonec_command_finished();
847 linphonec_finish_readline();
849 #if !defined(_WIN32_WCE)
852 #endif /*_WIN32_WCE*/
854 linphone_core_destroy (linphonec);
856 if (mylogfile != NULL && mylogfile != stdout)
866 * This is called from idle_call() whenever
867 * pending_auth != NULL.
869 * It prompts user for a password.
870 * Hitting ^D (EOF) would make this function
872 * Any other input would try to set linphone core
873 * auth_password for the pending_auth, add the auth_info
877 linphonec_prompt_for_auth_final(LinphoneCore *lc)
880 char auth_prompt[256];
882 rl_hook_func_t *old_event_hook;
884 LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1];
886 snprintf(auth_prompt, 256, "Password for %s on %s: ",
887 pending_auth->username, pending_auth->realm);
892 * Disable event hook to avoid entering an
893 * infinite loop. This would prevent idle_call
894 * from being called during authentication reads.
895 * Note that it might be undesiderable...
897 old_event_hook=rl_event_hook;
903 input=linphonec_readline(auth_prompt);
906 * If EOF (^D) is sent you probably don't want
907 * to provide an auth password... should give up
908 * the operation, but there's no mechanism to
909 * send this info back to caller currently...
913 printf("Cancel requested, but not implemented.\n");
918 iptr=lpc_strip_blanks(input);
921 * Only blanks, continue asking
929 /* Something typed, let's try */
934 * No check is done here to ensure password is correct.
935 * I guess password will be asked again later.
937 linphone_auth_info_set_passwd(pending_auth, input);
938 linphone_core_add_auth_info(lc, pending_auth);
939 linphone_auth_info_destroy(pending_auth);
940 auth_stack.elem[auth_stack.nitems-1]=0;
941 --(auth_stack.nitems);
944 * Reset line_buffer, to avoid the password
945 * to be used again from outer readline
947 rl_line_buffer[0]='\0';
948 rl_event_hook=old_event_hook;
954 print_usage (int exit_status)
956 fprintf (stdout, "\n\
957 usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\
960 -c file specify path of configuration file.\n\
961 -d level be verbose. 0 is no output. 6 is all output\n\
962 -l logfile specify the log file for your SIP phone\n\
963 -s sipaddress specify the sip call to do at startup\n\
964 -a enable auto answering for incoming calls\n\
965 -V enable video features globally (disabled by default)\n\
966 -C enable video capture only (disabled by default)\n\
967 -D enable video display only (disabled by default)\n\
968 -S show general state messages (disabled by default)\n\
969 -v or --version display version and exits.\n");
977 * Called every second from main read loop.
979 * Will use the following globals:
981 * - LinphoneCore linphonec
982 * - LPC_AUTH_STACK auth_stack;
986 linphonec_idle_call ()
988 LinphoneCore *opm=linphonec;
990 /* Uncomment the following to verify being called */
993 linphone_core_iterate(opm);
995 fprintf (stdout, "-------auto answering to call-------\n" );
996 linphone_core_accept_call(opm,NULL);
1000 if ( auth_stack.nitems )
1003 * Inhibit command completion
1004 * during password prompts
1006 #ifdef HAVE_READLINE
1007 rl_inhibit_completion=1;
1009 linphonec_prompt_for_auth_final(opm);
1010 #ifdef HAVE_READLINE
1011 rl_inhibit_completion=0;
1018 #ifdef HAVE_READLINE
1022 * - char *histfile_name (also sets this)
1023 * - char *last_in_history (allocates it)
1026 linphonec_initialize_readline()
1028 /*rl_bind_key('\t', rl_insert);*/
1030 /* Allow conditional parsing of ~/.inputrc */
1031 rl_readline_name = "linphonec";
1033 /* Call idle_call() every second */
1034 rl_set_keyboard_input_timeout(LPC_READLINE_TIMEOUT);
1035 rl_event_hook=linphonec_idle_call;
1037 /* Set history file and read it */
1038 histfile_name = ms_strdup_printf ("%s/.linphonec_history",
1040 read_history(histfile_name);
1042 /* Initialized last_in_history cache*/
1043 last_in_history[0] = '\0';
1045 /* Register a completion function */
1046 rl_attempted_completion_function = linephonec_readline_completion;
1048 /* printf("Readline initialized.\n"); */
1056 * - char *histfile_name (writes history to file and frees it)
1057 * - char *last_in_history (frees it)
1061 linphonec_finish_readline()
1064 stifle_history(HISTSIZE);
1065 write_history(histfile_name);
1066 free(histfile_name);
1073 static void print_prompt(LinphoneCore *opm){
1074 #ifdef IDENTITY_AS_PROMPT
1075 snprintf(prompt, PROMPT_MAX_LEN, "%s> ",
1076 linphone_core_get_primary_contact(opm));
1078 snprintf(prompt, PROMPT_MAX_LEN, "linphonec> ");
1083 linphonec_main_loop (LinphoneCore * opm, char * sipAddr)
1085 char buf[LINE_MAX_LEN]; /* auto call handling */
1091 /* auto call handling */
1092 if (sipAddr != NULL )
1094 snprintf (buf, sizeof(buf),"call %s", sipAddr);
1095 linphonec_parse_command_line(linphonec, buf);
1098 while (linphonec_running && (input=linphonec_readline(prompt)))
1100 char *iptr; /* input and input pointer */
1104 iptr=lpc_strip_blanks(input);
1106 input_len = strlen(iptr);
1109 * Do nothing but release memory
1110 * if only blanks are read
1118 #ifdef HAVE_READLINE
1120 * Only add to history if not already
1121 * last item in it, and only if the command
1122 * doesn't start with a space (to allow for
1125 if ( iptr == input && strcmp(last_in_history, iptr) )
1127 strncpy(last_in_history,iptr,sizeof(last_in_history));
1128 last_in_history[sizeof(last_in_history)-1]='\0';
1133 linphonec_parse_command_line(linphonec, iptr);
1134 linphonec_command_finished();
1142 * Parse command line switches
1147 * - char *logfile_name
1148 * - char *configfile_name
1152 linphonec_parse_cmdline(int argc, char **argv)
1156 while (arg_num < argc)
1158 int old_arg_num = arg_num;
1159 if (strncmp ("-d", argv[arg_num], 2) == 0)
1163 trace_level = atoi (argv[arg_num]);
1167 else if (strncmp ("-l", argv[arg_num], 2) == 0)
1171 logfile_name = argv[arg_num];
1173 else if (strncmp ("-c", argv[arg_num], 2) == 0)
1175 if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE);
1176 #if !defined(_WIN32_WCE)
1177 if (access(argv[arg_num],F_OK)!=0 )
1180 "Cannot open config file %s.\n",
1184 #endif /*_WIN32_WCE*/
1185 snprintf(configfile_name, PATH_MAX, "%s", argv[arg_num]);
1187 else if (strncmp ("-s", argv[arg_num], 2) == 0)
1191 sipAddr = argv[arg_num];
1193 else if (strncmp ("-a", argv[arg_num], 2) == 0)
1197 else if (strncmp ("-C", argv[arg_num], 2) == 0)
1199 vcap_enabled = TRUE;
1201 else if (strncmp ("-D", argv[arg_num], 2) == 0)
1203 display_enabled = TRUE;
1205 else if (strncmp ("-V", argv[arg_num], 2) == 0)
1207 display_enabled = TRUE;
1208 vcap_enabled = TRUE;
1209 preview_enabled=TRUE;
1211 else if ((strncmp ("-v", argv[arg_num], 2) == 0)
1214 ("--version", argv[arg_num],
1215 strlen ("--version")) == 0))
1217 #if !defined(_WIN32_WCE)
1218 printf ("version: " LINPHONE_VERSION "\n");
1220 exit (EXIT_SUCCESS);
1222 else if (strncmp ("-S", argv[arg_num], 2) == 0)
1224 show_general_state = TRUE;
1226 else if (strncmp ("--pipe", argv[arg_num], 6) == 0)
1230 else if (old_arg_num == arg_num)
1232 fprintf (stderr, "ERROR: bad arguments\n");
1233 print_usage (EXIT_FAILURE);
1242 * Up to version 1.2.1 linphone used ~/.linphonec for
1243 * CLI and ~/.gnome2/linphone for GUI as configuration file.
1244 * In newer version both interfaces will use ~/.linphonerc.
1246 * This function helps transparently migrating from one
1247 * to the other layout using the following heuristic:
1249 * IF new_config EXISTS => do nothing
1250 * ELSE IF old_cli_config EXISTS => copy to new_config
1251 * ELSE IF old_gui_config EXISTS => copy to new_config
1254 * 0 if it did nothing
1255 * 1 if it migrated successfully
1259 handle_configfile_migration()
1261 #if !defined(_WIN32_WCE)
1265 #if !defined(_WIN32_WCE)
1266 const char *home = getenv("HOME");
1268 const char *home = ".";
1269 #endif /*_WIN32_WCE*/
1270 new_cfg = ms_strdup_printf("%s/.linphonerc", home);
1273 * If the *NEW* configuration already exists
1276 if (access(new_cfg,F_OK)==0)
1282 old_cfg_cli = ms_strdup_printf("%s/.linphonec", home);
1285 * If the *OLD* CLI configurations exist copy it to
1286 * the new file and make it a symlink.
1288 if (access(old_cfg_cli, F_OK)==0)
1290 if ( ! copy_file(old_cfg_cli, new_cfg) )
1296 printf("%s copied to %s\n", old_cfg_cli, new_cfg);
1303 old_cfg_gui = ms_strdup_printf("%s/.gnome2/linphone", home);
1306 * If the *OLD* GUI configurations exist copy it to
1307 * the new file and make it a symlink.
1309 if (access(old_cfg_gui, F_OK)==0)
1311 if ( ! copy_file(old_cfg_gui, new_cfg) )
1318 printf("%s copied to %s\n", old_cfg_gui, new_cfg);
1326 #endif /*_WIN32_WCE*/
1329 #if !defined(_WIN32_WCE)
1331 * Copy file "from" to file "to".
1332 * Destination file is truncated if existing.
1333 * Return 1 on success, 0 on error (printing an error).
1336 copy_file(const char *from, const char *to)
1343 /* Open "from" file for reading */
1344 in=fopen(from, "r");
1347 snprintf(message, 255, "Can't open %s for reading: %s\n",
1348 from, strerror(errno));
1349 fprintf(stderr, "%s", message);
1353 /* Open "to" file for writing (will truncate existing files) */
1357 snprintf(message, 255, "Can't open %s for writing: %s\n",
1358 to, strerror(errno));
1359 fprintf(stderr, "%s", message);
1363 /* Copy data from "in" to "out" */
1364 while ( (n=fread(buf, 1, sizeof buf, in)) > 0 )
1366 if ( ! fwrite(buf, 1, n, out) )
1377 #endif /*_WIN32_WCE*/
1379 #ifdef HAVE_READLINE
1381 linephonec_readline_completion(const char *text, int start, int end)
1383 char **matches = NULL;
1386 * Prevent readline from falling
1387 * back to filename-completion
1389 rl_attempted_completion_over=1;
1392 * If this is the start of line we complete with commands
1396 return rl_completion_matches(text, linphonec_command_generator);
1400 * Otherwise, we should peek at command name
1401 * or context to implement a smart completion.
1402 * For example: "call .." could return
1403 * friends' sip-uri as matches
1412 * Strip blanks from a string.
1413 * Return a pointer into the provided string.
1414 * Modifies input adding a NULL at first
1415 * of trailing blanks.
1418 lpc_strip_blanks(char *input)
1422 /* Find first non-blank */
1423 while(*input && isspace(*input)) ++input;
1425 /* Find last non-blank */
1426 iptr=input+strlen(input);
1428 while(isspace(*--iptr));
1435 /****************************************************************************
1437 * $Log: linphonec.c,v $
1438 * Revision 1.57 2007/11/14 13:40:27 smorlat
1439 * fix --disable-video build.
1441 * Revision 1.56 2007/09/26 14:07:27 fixkowalski
1442 * - ANSI/C++ compilation issues with non-GCC compilers
1443 * - Faster epm-based packaging
1444 * - Ability to build & run on FC6's eXosip/osip
1446 * Revision 1.55 2007/09/24 16:01:58 smorlat
1449 * Revision 1.54 2007/08/22 14:06:11 smorlat
1450 * authentication bugs fixed.
1452 * Revision 1.53 2007/02/13 21:31:01 smorlat
1453 * added patch for general state.
1454 * new doxygen for oRTP
1457 * Revision 1.52 2007/01/10 14:11:24 smorlat
1458 * add --video to linphonec.
1460 * Revision 1.51 2006/08/21 12:49:59 smorlat
1461 * merged several little patches.
1463 * Revision 1.50 2006/07/26 08:17:28 smorlat
1466 * Revision 1.49 2006/07/17 18:45:00 smorlat
1467 * support for several event queues in ortp.
1468 * glib dependency removed from coreapi/ and console/
1470 * Revision 1.48 2006/04/09 12:45:32 smorlat
1471 * linphonec improvements.
1473 * Revision 1.47 2006/04/04 08:04:34 smorlat
1474 * switched to mediastreamer2, most bugs fixed.
1476 * Revision 1.46 2006/03/16 17:17:40 smorlat
1479 * Revision 1.45 2006/03/12 21:48:31 smorlat
1480 * gcc-2.95 compile error fixed.
1481 * mediastreamer2 in progress
1483 * Revision 1.44 2006/03/04 11:17:10 smorlat
1484 * mediastreamer2 in progress.
1486 * Revision 1.43 2006/02/13 09:50:50 strk
1487 * fixed unused variable warning.
1489 * Revision 1.42 2006/02/02 15:39:18 strk
1490 * - Added 'friend list' and 'friend call' commands
1491 * - Allowed for multiple DTFM send in a single line
1492 * - Added status-specific callback (bare version)
1494 * Revision 1.41 2006/02/02 13:30:05 strk
1495 * - Padded vtable with missing callbacks
1496 * (fixing a segfault on friends subscription)
1497 * - Handled friends notify (bare version)
1498 * - Handled text messages receive (bare version)
1499 * - Printed message on subscription request (bare version)
1501 * Revision 1.40 2006/01/26 09:48:05 strk
1502 * Added limits.h include
1504 * Revision 1.39 2006/01/26 02:11:01 strk
1505 * Removed unused variables, fixed copyright date
1507 * Revision 1.38 2006/01/25 18:33:02 strk
1508 * Removed the -t swich, terminate_on_close made the default behaviour
1510 * Revision 1.37 2006/01/20 14:12:34 strk
1511 * Added linphonec_init() and linphonec_finish() functions.
1512 * Handled SIGINT and SIGTERM to invoke linphonec_finish().
1513 * Handling of auto-termination (-t) moved to linphonec_finish().
1514 * Reworked main (input read) loop to not rely on 'terminate'
1515 * and 'run' variable (dropped). configfile_name allocated on stack
1516 * using PATH_MAX limit. Changed print_usage signature to allow
1517 * for an exit_status specification.
1519 * Revision 1.36 2006/01/18 09:25:32 strk
1520 * Command completion inhibited in proxy addition and auth request prompts.
1521 * Avoided use of readline's internal filename completion.
1523 * Revision 1.35 2006/01/14 13:29:32 strk
1524 * Reworked commands interface to use a table structure,
1525 * used by command line parser and help function.
1526 * Implemented first level of completion (commands).
1527 * Added notification of invalid "answer" and "terminate"
1528 * commands (no incoming call, no active call).
1529 * Forbidden "call" intialization when a call is already active.
1530 * Cleaned up all commands, adding more feedback and error checks.
1532 * Revision 1.34 2006/01/13 13:00:29 strk
1533 * Added linphonec.h. Code layout change (added comments, forward decl,
1534 * globals on top, copyright notices and Logs). Handled out-of-memory
1535 * condition on history management. Removed assumption on sizeof(char).
1536 * Fixed bug in authentication prompt (introduced by readline).
1537 * Added support for multiple authentication requests (up to MAX_PENDING_AUTH).
1540 ****************************************************************************/