linphonec.c 34.9 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8
/****************************************************************************
 *
 *  $Id: linphonec.c,v 1.57 2007/11/14 13:40:27 smorlat Exp $
 *
 *  Copyright (C) 2006  Sandro Santilli <strk@keybit.net>
 *  Copyright (C) 2002  Florian Winterstein <flox@gmx.net>
 *  Copyright (C) 2000  Simon MORLAT <simon.morlat@free.fr>
 *
9
****************************************************************************
aymeric's avatar
aymeric committed
10
 *
11 12 13 14
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
aymeric's avatar
aymeric committed
15
 *
16 17 18 19
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
aymeric's avatar
aymeric committed
20
 *
21 22 23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
aymeric's avatar
aymeric committed
24 25
 *
 ****************************************************************************/
Jehan Monnier's avatar
Jehan Monnier committed
26 27
#include <string.h>
#ifndef _WIN32_WCE
aymeric's avatar
aymeric committed
28 29 30
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
Jehan Monnier's avatar
Jehan Monnier committed
31
#include <errno.h>
aymeric's avatar
aymeric committed
32
#include <signal.h>
Jehan Monnier's avatar
Jehan Monnier committed
33 34
#include "private.h" /*coreapi/private.h, needed for LINPHONE_VERSION */
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
35
#include <limits.h>
36
#include <ctype.h>
37

aymeric's avatar
aymeric committed
38
#include <linphonecore.h>
Jehan Monnier's avatar
Jehan Monnier committed
39

aymeric's avatar
aymeric committed
40 41
#include "linphonec.h"

42 43 44
#ifdef WIN32
#include <ws2tcpip.h>
#include <ctype.h>
Jehan Monnier's avatar
Jehan Monnier committed
45
#ifndef _WIN32_WCE
46
#include <conio.h>
Jehan Monnier's avatar
Jehan Monnier committed
47
#endif /*_WIN32_WCE*/
48 49 50
#else
#include <sys/socket.h>
#include <netdb.h>
51 52
#include <sys/un.h>
#include <sys/stat.h>
53 54
#endif

Jehan Monnier's avatar
Jehan Monnier committed
55 56 57 58 59 60 61 62 63 64 65
#if defined(_WIN32_WCE)

#if !defined(PATH_MAX)
#define PATH_MAX 256
#endif /*PATH_MAX*/

#if !defined(strdup)
#define strdup _strdup
#endif /*strdup*/

#endif /*_WIN32_WCE*/
66

aymeric's avatar
aymeric committed
67 68 69 70 71 72 73 74 75
#ifdef HAVE_GETTEXT
#include <libintl.h>
#ifndef _
#define _(String) gettext(String)
#endif
#else
#define _(something)	(something)
#endif

Simon Morlat's avatar
Simon Morlat committed
76 77 78 79
#ifndef PACKAGE_DIR
#define PACKAGE_DIR ""
#endif

aymeric's avatar
aymeric committed
80 81 82 83 84 85 86 87 88 89 90 91 92
/***************************************************************************
 *
 *  Types
 *
 ***************************************************************************/

typedef struct {
	LinphoneAuthInfo *elem[MAX_PENDING_AUTH];
	int nitems;
} LPC_AUTH_STACK;

/***************************************************************************
 *
Jehan Monnier's avatar
Jehan Monnier committed
93
 *  Forward declarations
aymeric's avatar
aymeric committed
94 95 96 97 98 99
 *
 ***************************************************************************/

char *lpc_strip_blanks(char *input);

static int handle_configfile_migration(void);
Jehan Monnier's avatar
Jehan Monnier committed
100
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
101
static int copy_file(const char *from, const char *to);
Jehan Monnier's avatar
Jehan Monnier committed
102
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
103 104 105 106
static int linphonec_parse_cmdline(int argc, char **argv);
static int linphonec_init(int argc, char **argv);
static int linphonec_main_loop (LinphoneCore * opm, char * sipAddr);
static int linphonec_idle_call (void);
107 108 109
#ifdef HAVE_READLINE
static int linphonec_initialize_readline(void);
static int linphonec_finish_readline();
aymeric's avatar
aymeric committed
110 111
static char **linephonec_readline_completion(const char *text,
	int start, int end);
112
#endif
aymeric's avatar
aymeric committed
113 114 115 116 117 118 119 120 121

/* These are callback for linphone core */
static void linphonec_call_received(LinphoneCore *lc, const char *from);
static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm,
	const char *username);
static void linphonec_display_something (LinphoneCore * lc, const char *something);
static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
static void linphonec_display_warning (LinphoneCore * lc, const char *something);
static void stub () {}
122
static void linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid);
aymeric's avatar
aymeric committed
123 124 125 126 127 128 129
static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
		LinphoneFriend *lf, const char *url);
static void linphonec_bye_received(LinphoneCore *lc, const char *from);
static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
		const char *from, const char *msg);
static void linphonec_display_status (LinphoneCore * lc, const char *something);
static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate);
130
static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf);
aymeric's avatar
aymeric committed
131 132 133
static void print_prompt(LinphoneCore *opm);
/***************************************************************************
 *
Jehan Monnier's avatar
Jehan Monnier committed
134
 * Global variables
aymeric's avatar
aymeric committed
135 136 137
 *
 ***************************************************************************/

138
LinphoneCore *linphonec;
aymeric's avatar
aymeric committed
139
FILE *mylogfile;
140
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
141 142
static char *histfile_name=NULL;
static char last_in_history[256];
143
#endif
aymeric's avatar
aymeric committed
144 145 146 147 148
//auto answer (-a) option
static bool_t auto_answer=FALSE;
static bool_t answer_call=FALSE;
static bool_t vcap_enabled=FALSE;
static bool_t display_enabled=FALSE;
149
static bool_t preview_enabled=FALSE;
aymeric's avatar
aymeric committed
150
static bool_t show_general_state=FALSE;
151
static bool_t unix_socket=FALSE;
smorlat's avatar
smorlat committed
152
static bool_t linphonec_running=TRUE;
aymeric's avatar
aymeric committed
153 154 155 156 157
LPC_AUTH_STACK auth_stack;
static int trace_level = 0;
static char *logfile_name = NULL;
static char configfile_name[PATH_MAX];
static char *sipAddr = NULL; /* for autocall */
Jehan Monnier's avatar
Jehan Monnier committed
158
#if !defined(_WIN32_WCE)
159
static ortp_pipe_t client_sock=ORTP_PIPE_INVALID;
Jehan Monnier's avatar
Jehan Monnier committed
160
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
161
char prompt[PROMPT_MAX_LEN];
Jehan Monnier's avatar
Jehan Monnier committed
162
#if !defined(_WIN32_WCE)
163 164
static ortp_thread_t pipe_reader_th;
static bool_t pipe_reader_run=FALSE;
Jehan Monnier's avatar
Jehan Monnier committed
165 166
#endif /*_WIN32_WCE*/
#if !defined(_WIN32_WCE)
167
static ortp_pipe_t server_sock;
Jehan Monnier's avatar
Jehan Monnier committed
168
#endif /*_WIN32_WCE*/
169

aymeric's avatar
aymeric committed
170

Jehan Monnier's avatar
Jehan Monnier committed
171 172 173
LinphoneCoreVTable linphonec_vtable
#if !defined (_MSC_VER)
= {
174 175
	.show =(ShowInterfaceCb) stub,
	.inv_recv = linphonec_call_received,
Jehan Monnier's avatar
Jehan Monnier committed
176
	.bye_recv = linphonec_bye_received,
177 178 179 180 181
	.notify_recv = linphonec_notify_received,
	.new_unknown_subscriber = linphonec_new_unknown_subscriber,
	.auth_info_requested = linphonec_prompt_for_auth,
	.display_status = linphonec_display_status,
	.display_message=linphonec_display_something,
aymeric's avatar
aymeric committed
182 183
#ifdef VINCENT_MAURY_RSVP
	/* the yes/no dialog box */
184
	.display_yes_no= (DisplayMessageCb) stub,
aymeric's avatar
aymeric committed
185
#endif
186 187 188 189
	.display_warning=linphonec_display_warning,
	.display_url=linphonec_display_url,
	.display_question=(DisplayQuestionCb)stub,
	.text_received=linphonec_text_received,
190
	.general_state=linphonec_general_state,
191
	.dtmf_received=linphonec_dtmf_received
Jehan Monnier's avatar
Jehan Monnier committed
192 193 194
}
#endif /*_WIN32_WCE*/
;
aymeric's avatar
aymeric committed
195

196 197


aymeric's avatar
aymeric committed
198 199 200 201 202 203 204
/***************************************************************************
 *
 * Linphone core callbacks
 *
 ***************************************************************************/

/*
Jehan Monnier's avatar
Jehan Monnier committed
205
 * Linphone core callback
aymeric's avatar
aymeric committed
206 207 208 209 210 211 212 213 214
 */
static void
linphonec_display_something (LinphoneCore * lc, const char *something)
{
	fprintf (stdout, "%s\n%s", something,prompt);
	fflush(stdout);
}

/*
Jehan Monnier's avatar
Jehan Monnier committed
215
 * Linphone core callback
aymeric's avatar
aymeric committed
216 217 218 219 220 221 222 223 224
 */
static void
linphonec_display_status (LinphoneCore * lc, const char *something)
{
	fprintf (stdout, "%s\n%s", something,prompt);
	fflush(stdout);
}

/*
Jehan Monnier's avatar
Jehan Monnier committed
225
 * Linphone core callback
aymeric's avatar
aymeric committed
226 227 228 229 230 231 232 233 234
 */
static void
linphonec_display_warning (LinphoneCore * lc, const char *something)
{
	fprintf (stdout, "Warning: %s\n%s", something,prompt);
	fflush(stdout);
}

/*
Jehan Monnier's avatar
Jehan Monnier committed
235
 * Linphone core callback
aymeric's avatar
aymeric committed
236 237 238 239 240 241 242 243 244
 */
static void
linphonec_display_url (LinphoneCore * lc, const char *something, const char *url)
{
	fprintf (stdout, "%s : %s\n", something, url);
}


/*
Jehan Monnier's avatar
Jehan Monnier committed
245
 * Linphone core callback
aymeric's avatar
aymeric committed
246 247 248 249
 */
static void
linphonec_call_received(LinphoneCore *lc, const char *from)
{
250
	linphonec_set_caller(from);
aymeric's avatar
aymeric committed
251 252 253 254 255 256
	if ( auto_answer)  {
		answer_call=TRUE;
	}
}

/*
Jehan Monnier's avatar
Jehan Monnier committed
257
 * Linphone core callback
aymeric's avatar
aymeric committed
258 259 260 261
 */
static void
linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username)
{
262
	/* no prompt possible when using pipes or tcp mode*/
263
	if (unix_socket){
264 265 266
		linphone_core_abort_authentication(lc,NULL);
	}else{
		LinphoneAuthInfo *pending_auth;
Jehan Monnier's avatar
Jehan Monnier committed
267

268 269 270 271 272 273
		if ( auth_stack.nitems+1 > MAX_PENDING_AUTH )
		{
			fprintf(stderr,
				"Can't accept another authentication request.\n"
				"Consider incrementing MAX_PENDING_AUTH macro.\n");
			return;
Jehan Monnier's avatar
Jehan Monnier committed
274 275
		}

276 277 278
		pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm);
		auth_stack.elem[auth_stack.nitems++]=pending_auth;
	}
aymeric's avatar
aymeric committed
279 280 281 282 283 284
}

/*
 * Linphone core callback
 */
static void
285
linphonec_notify_received(LinphoneCore *lc,LinphoneFriend *fid)
aymeric's avatar
aymeric committed
286
{
287 288 289
	char *tmp=linphone_address_as_string(linphone_friend_get_address(fid));
	printf("Friend %s is %s\n", tmp, linphone_online_status_to_string(linphone_friend_get_status(fid)));
	ms_free(tmp);
aymeric's avatar
aymeric committed
290 291 292 293 294 295 296 297 298 299 300
	// todo: update Friend list state (unimplemented)
}

/*
 * Linphone core callback
 */
static void
linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf,
		const char *url)
{
	printf("Friend %s requested subscription "
Jehan Monnier's avatar
Jehan Monnier committed
301 302
		"(accept/deny is not implemented yet)\n", url);
	// This means that this person wishes to be notified
aymeric's avatar
aymeric committed
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
	// of your presence information (online, busy, away...).

}

/*
 * Linphone core callback
 */
static void
linphonec_bye_received(LinphoneCore *lc, const char *from)
{
	// Should change prompt back to original maybe

	// printing this is unneeded as we'd get a "Communication ended"
	// message trough display_status callback anyway
	//printf("Bye received from %s\n", from);
}

/*
 * Linphone core callback
 */
static void
linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
		const char *from, const char *msg)
{
	printf("%s: %s\n", from, msg);
	// TODO: provide mechanism for answering.. ('say' command?)
}


332
static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf){
333 334
	fprintf(stdout,"Receiving tone %c\n",dtmf);
	fflush(stdout);
335 336
}

Jehan Monnier's avatar
Jehan Monnier committed
337
static void
aymeric's avatar
aymeric committed
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate)
{
        if (show_general_state) {
          switch(gstate->new_state) {
           case GSTATE_POWER_OFF:
             printf("GSTATE_POWER_OFF");
             break;
           case GSTATE_POWER_STARTUP:
             printf("GSTATE_POWER_STARTUP");
             break;
           case GSTATE_POWER_ON:
             printf("GSTATE_POWER_ON");
             break;
           case GSTATE_POWER_SHUTDOWN:
             printf("GSTATE_POWER_SHUTDOWN");
             break;
           case GSTATE_REG_NONE:
             printf("GSTATE_REG_NONE");
             break;
           case GSTATE_REG_OK:
             printf("GSTATE_REG_OK");
             break;
           case GSTATE_REG_FAILED:
             printf("GSTATE_REG_FAILED");
             break;
           case GSTATE_CALL_IDLE:
             printf("GSTATE_CALL_IDLE");
             break;
           case GSTATE_CALL_OUT_INVITE:
             printf("GSTATE_CALL_OUT_INVITE");
             break;
           case GSTATE_CALL_OUT_CONNECTED:
             printf("GSTATE_CALL_OUT_CONNECTED");
             break;
           case GSTATE_CALL_IN_INVITE:
             printf("GSTATE_CALL_IN_INVITE");
             break;
           case GSTATE_CALL_IN_CONNECTED:
             printf("GSTATE_CALL_IN_CONNECTED");
             break;
           case GSTATE_CALL_END:
             printf("GSTATE_CALL_END");
             break;
           case GSTATE_CALL_ERROR:
             printf("GSTATE_CALL_ERROR");
             break;
           default:
Jehan Monnier's avatar
Jehan Monnier committed
385
              printf("GSTATE_UNKNOWN_%d",gstate->new_state);
aymeric's avatar
aymeric committed
386 387 388
          }
          if (gstate->message) printf(" %s", gstate->message);
          printf("\n");
Jehan Monnier's avatar
Jehan Monnier committed
389
        }
aymeric's avatar
aymeric committed
390 391
}

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
static char received_prompt[PROMPT_MAX_LEN];
static ms_mutex_t prompt_mutex;
static bool_t have_prompt=FALSE;

static void *prompt_reader_thread(void *arg){
	char *ret;
	char tmp[PROMPT_MAX_LEN];
	while ((ret=fgets(tmp,sizeof(tmp),stdin))!=NULL){
		ms_mutex_lock(&prompt_mutex);
		strcpy(received_prompt,ret);
		have_prompt=TRUE;
		ms_mutex_unlock(&prompt_mutex);
	}
	return NULL;
}

static void start_prompt_reader(void){
	ortp_thread_t th;
	ms_mutex_init(&prompt_mutex,NULL);
	ortp_thread_create(&th,NULL,prompt_reader_thread,NULL);
}
Jehan Monnier's avatar
Jehan Monnier committed
413
#if !defined(_WIN32_WCE)
414 415
static ortp_pipe_t create_server_socket(void){
	char path[128];
416
#ifndef WIN32
417
	snprintf(path,sizeof(path)-1,"linphonec-%i",getuid());
418
#else
419
	{
Jehan Monnier's avatar
Jehan Monnier committed
420
		TCHAR username[128];
421 422 423
		DWORD size=sizeof(username)-1;
		GetUserName(username,&size);
		snprintf(path,sizeof(path)-1,"linphonec-%s",username);
424
	}
425 426
#endif
	return ortp_server_pipe_create(path);
427 428
}

Jehan Monnier's avatar
Jehan Monnier committed
429

430
static void *pipe_thread(void*p){
431
	char tmp[250];
432 433 434 435
	server_sock=create_server_socket();
	if (server_sock==ORTP_PIPE_INVALID) return NULL;
	while(pipe_reader_run){
		while(client_sock!=ORTP_PIPE_INVALID){ /*sleep until the last command is finished*/
436 437 438 439 440 441
#ifndef WIN32
			usleep(20000);
#else
			Sleep(20);
#endif
		}
442 443
		client_sock=ortp_server_pipe_accept_client(server_sock);
		if (client_sock!=ORTP_PIPE_INVALID){
444 445
			int len;
			/*now read from the client */
smorlat's avatar
smorlat committed
446
			if ((len=ortp_pipe_read(client_sock,(uint8_t*)tmp,sizeof(tmp)-1))>0){
447 448 449 450 451 452 453 454
				ortp_mutex_lock(&prompt_mutex);
				tmp[len]='\0';
				strcpy(received_prompt,tmp);
				printf("Receiving command '%s'\n",received_prompt);fflush(stdout);
				have_prompt=TRUE;
				ortp_mutex_unlock(&prompt_mutex);
			}else{
				printf("read nothing\n");fflush(stdout);
455 456
				ortp_server_pipe_close_client(client_sock);
				client_sock=ORTP_PIPE_INVALID;
457
			}
Jehan Monnier's avatar
Jehan Monnier committed
458

459
		}else{
460
			if (pipe_reader_run) fprintf(stderr,"accept() failed: %s\n",strerror(errno));
461 462
		}
	}
smorlat's avatar
smorlat committed
463
	ms_message("Exiting pipe_reader_thread.");
464
	fflush(stdout);
465 466 467
	return NULL;
}

468
static void start_pipe_reader(void){
469
	ms_mutex_init(&prompt_mutex,NULL);
470 471
	pipe_reader_run=TRUE;
	ortp_thread_create(&pipe_reader_th,NULL,pipe_thread,NULL);
472 473
}

474 475
static void stop_pipe_reader(void){
	pipe_reader_run=FALSE;
smorlat's avatar
smorlat committed
476
	linphonec_command_finished();
477 478
	ortp_server_pipe_close(server_sock);
	ortp_thread_join(pipe_reader_th,NULL);
479
}
Jehan Monnier's avatar
Jehan Monnier committed
480
#endif /*_WIN32_WCE*/
481

482 483 484 485
#ifdef HAVE_READLINE
#define BOOL_HAVE_READLINE 1
#else
#define BOOL_HAVE_READLINE 0
486 487 488
#endif

char *linphonec_readline(char *prompt){
489
	if (unix_socket || !BOOL_HAVE_READLINE ){
490
		static bool_t prompt_reader_started=FALSE;
491
		static bool_t pipe_reader_started=FALSE;
492 493 494
		if (!prompt_reader_started){
			start_prompt_reader();
			prompt_reader_started=TRUE;
495
		}
496
		if (unix_socket && !pipe_reader_started){
Jehan Monnier's avatar
Jehan Monnier committed
497
#if !defined(_WIN32_WCE)
498 499
			start_pipe_reader();
			pipe_reader_started=TRUE;
Jehan Monnier's avatar
Jehan Monnier committed
500
#endif /*_WIN32_WCE*/
501 502 503 504 505 506 507 508 509 510 511 512 513
		}
		fprintf(stdout,"%s",prompt);
		fflush(stdout);
		while(1){
			ms_mutex_lock(&prompt_mutex);
			if (have_prompt){
				char *ret=strdup(received_prompt);
				have_prompt=FALSE;
				ms_mutex_unlock(&prompt_mutex);
				return ret;
			}
			ms_mutex_unlock(&prompt_mutex);
			linphonec_idle_call();
514
#ifdef WIN32
515
			Sleep(20);
516
#else
517
			usleep(20000);
518
#endif
519 520 521 522
		}
	}else{
#ifdef HAVE_READLINE
		return readline(prompt);
523
#endif
524
	}
525
}
aymeric's avatar
aymeric committed
526

527 528 529 530 531 532
void linphonec_out(const char *fmt,...){
	char *res;
	va_list args;
	va_start (args, fmt);
	res=ortp_strdup_vprintf(fmt,args);
	va_end (args);
533 534
	printf("%s",res);
	fflush(stdout);
Jehan Monnier's avatar
Jehan Monnier committed
535
#if !defined(_WIN32_WCE)
536
	if (client_sock!=ORTP_PIPE_INVALID){
smorlat's avatar
smorlat committed
537
		if (ortp_pipe_write(client_sock,(uint8_t*)res,strlen(res))==-1){
538
			fprintf(stderr,"Fail to send output via pipe: %s",strerror(errno));
539 540
		}
	}
Jehan Monnier's avatar
Jehan Monnier committed
541
#endif /*_WIN32_WCE*/
542 543 544 545
	ortp_free(res);
}

void linphonec_command_finished(void){
Jehan Monnier's avatar
Jehan Monnier committed
546
#if !defined(_WIN32_WCE)
547 548 549
	if (client_sock!=ORTP_PIPE_INVALID){
		ortp_server_pipe_close_client(client_sock);
		client_sock=ORTP_PIPE_INVALID;
550
	}
Jehan Monnier's avatar
Jehan Monnier committed
551
#endif /*_WIN32_WCE*/
552 553
}

smorlat's avatar
smorlat committed
554 555 556
void linphonec_set_autoanswer(bool_t enabled){
	auto_answer=enabled;
}
557

smorlat's avatar
smorlat committed
558 559 560
bool_t linphonec_get_autoanswer(){
	return auto_answer;
}
561

aymeric's avatar
aymeric committed
562 563 564 565 566 567 568 569 570
/***************************************************************************/
/*
 * Main
 *
 * Use globals:
 *
 *	- char *histfile_name
 *	- FILE *mylogfile
 */
Simon Morlat's avatar
Simon Morlat committed
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
#if defined (_WIN32_WCE)

char **convert_args_to_ascii(int argc, _TCHAR **wargv){
	int i;
	char **result=malloc(argc*sizeof(char*));
	char argtmp[128];
	for(i=0;i<argc;++i){
		wcstombs(argtmp,wargv[i],sizeof(argtmp));
		result[i]=strdup(argtmp);
	}
	return result;
}

int _tmain(int argc, _TCHAR* wargv[]) {
	char **argv=convert_args_to_ascii(argc,wargv);
	trace_level=6;
Jehan Monnier's avatar
Jehan Monnier committed
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
	linphonec_vtable.show =(ShowInterfaceCb) stub;
	linphonec_vtable.inv_recv = linphonec_call_received;
	linphonec_vtable.bye_recv = linphonec_bye_received;
	linphonec_vtable.notify_recv = linphonec_notify_received;
	linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
	linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
	linphonec_vtable.display_status = linphonec_display_status;
	linphonec_vtable.display_message=linphonec_display_something;
#ifdef VINCENT_MAURY_RSVP
	/* the yes/no dialog box */
	linphonec_vtable.display_yes_no= (DisplayMessageCb) stub;
#endif
	linphonec_vtable.display_warning=linphonec_display_warning;
	linphonec_vtable.display_url=linphonec_display_url;
	linphonec_vtable.display_question=(DisplayQuestionCb)stub;
	linphonec_vtable.text_received=linphonec_text_received;
	linphonec_vtable.general_state=linphonec_general_state;
	linphonec_vtable.dtmf_received=linphonec_dtmf_received;

#else
aymeric's avatar
aymeric committed
607
int
Jehan Monnier's avatar
Jehan Monnier committed
608 609 610 611
main (int argc, char *argv[]) {
#endif


aymeric's avatar
aymeric committed
612 613
	if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);

614
	linphonec_main_loop (linphonec, sipAddr);
aymeric's avatar
aymeric committed
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633

	linphonec_finish(EXIT_SUCCESS);

	exit(EXIT_SUCCESS); /* should never reach here */
}

/*
 * Initialize linphonec
 */
static int
linphonec_init(int argc, char **argv)
{

	//g_mem_set_vtable(&dbgtable);

	/*
	 * Set initial values for global variables
	 */
	mylogfile = NULL;
Simon Morlat's avatar
Simon Morlat committed
634 635 636
	
	
#ifndef _WIN32
Jehan Monnier's avatar
Jehan Monnier committed
637 638
	snprintf(configfile_name, PATH_MAX, "%s/.linphonerc",
			getenv("HOME"));
Simon Morlat's avatar
Simon Morlat committed
639 640 641 642
#elif defined(_WIN32_WCE)
	strncpy(configfile_name,PACKAGE_DIR "\\linphonerc",PATH_MAX);
	mylogfile=fopen(PACKAGE_DIR "\\" "linphonec.log","w");
	printf("Logs are redirected in" PACKAGE_DIR "\\linphonec.log");
Jehan Monnier's avatar
Jehan Monnier committed
643
#else
Simon Morlat's avatar
Simon Morlat committed
644 645 646
	snprintf(configfile_name, PATH_MAX, "%s/Linphone/linphonerc",
			getenv("APPDATA"));
#endif
aymeric's avatar
aymeric committed
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
	/* Handle configuration filename changes */
	switch (handle_configfile_migration())
	{
		case -1: /* error during file copies */
			fprintf(stderr,
				"Error in configuration file migration\n");
			break;

		case 0: /* nothing done */
		case 1: /* migrated */
		default:
			break;
	}

#ifdef ENABLE_NLS
	if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR))
		perror ("bindtextdomain failed");
#ifndef __ARM__
	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
#endif
	textdomain (GETTEXT_PACKAGE);
#else
	printf ("NLS disabled.\n");
#endif

	linphonec_parse_cmdline(argc, argv);

	if (trace_level > 0)
	{
		if (logfile_name != NULL)
			mylogfile = fopen (logfile_name, "w+");

		if (mylogfile == NULL)
		{
			mylogfile = stdout;
			fprintf (stderr,
				 "INFO: no logfile, logging to stdout\n");
		}
		linphone_core_enable_logs(mylogfile);
	}
	else
	{
		linphone_core_disable_logs();
	}
	/*
	 * Initialize auth stack
	 */
	auth_stack.nitems=0;

	/*
	 * Initialize linphone core
	 */
699
	linphonec=linphone_core_new (&linphonec_vtable, configfile_name, NULL,
aymeric's avatar
aymeric committed
700
			    NULL);
701 702
	linphone_core_enable_video(linphonec,vcap_enabled,display_enabled);
	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
aymeric's avatar
aymeric committed
705 706 707 708
	/*
	 * Initialize readline
	 */
	linphonec_initialize_readline();
709
#endif
Jehan Monnier's avatar
Jehan Monnier committed
710
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
711 712 713
	/*
	 * Initialize signal handlers
	 */
Jehan Monnier's avatar
Jehan Monnier committed
714 715 716
	signal(SIGTERM, linphonec_finish);
	signal(SIGINT, linphonec_finish);
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
717 718 719 720
	return 1;
}


smorlat's avatar
smorlat committed
721 722 723 724
void linphonec_main_loop_exit(void){
	linphonec_running=FALSE;
}

aymeric's avatar
aymeric committed
725 726 727 728 729 730 731 732
/*
 * Close linphonec, cleanly terminating
 * any pending call
 */
void
linphonec_finish(int exit_status)
{
	printf("Terminating...\n");
Jehan Monnier's avatar
Jehan Monnier committed
733

aymeric's avatar
aymeric committed
734
	/* Terminate any pending call */
735
   	linphonec_parse_command_line(linphonec, "terminate");
smorlat's avatar
smorlat committed
736
   	linphonec_command_finished();
737
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
738
	linphonec_finish_readline();
739
#endif
Jehan Monnier's avatar
Jehan Monnier committed
740
#if !defined(_WIN32_WCE)
741 742
	if (pipe_reader_run)
		stop_pipe_reader();
Jehan Monnier's avatar
Jehan Monnier committed
743
#endif /*_WIN32_WCE*/
strk's avatar
strk committed
744

745
	linphone_core_destroy (linphonec);
aymeric's avatar
aymeric committed
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760

	if (mylogfile != NULL && mylogfile != stdout)
	{
		fclose (mylogfile);
	}

	exit(exit_status);

}

/*
 * This is called from idle_call() whenever
 * pending_auth != NULL.
 *
 * It prompts user for a password.
Jehan Monnier's avatar
Jehan Monnier committed
761
 * Hitting ^D (EOF) would make this function
aymeric's avatar
aymeric committed
762 763 764 765 766 767 768 769 770 771
 * return 0 (Cancel).
 * Any other input would try to set linphone core
 * auth_password for the pending_auth, add the auth_info
 * and return 1.
 */
int
linphonec_prompt_for_auth_final(LinphoneCore *lc)
{
	char *input, *iptr;
	char auth_prompt[256];
772
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
773
	rl_hook_func_t *old_event_hook;
774
#endif
aymeric's avatar
aymeric committed
775 776 777 778 779 780
	LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1];

	snprintf(auth_prompt, 256, "Password for %s on %s: ",
		pending_auth->username, pending_auth->realm);

	printf("\n");
781
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
782 783 784 785 786 787 788 789
	/*
	 * Disable event hook to avoid entering an
	 * infinite loop. This would prevent idle_call
	 * from being called during authentication reads.
	 * Note that it might be undesiderable...
	 */
	old_event_hook=rl_event_hook;
	rl_event_hook=NULL;
790
#endif
aymeric's avatar
aymeric committed
791 792 793

	while (1)
	{
794
		input=linphonec_readline(auth_prompt);
aymeric's avatar
aymeric committed
795 796 797 798 799 800 801 802 803

		/*
		 * If EOF (^D) is sent you probably don't want
		 * to provide an auth password... should give up
		 * the operation, but there's no mechanism to
		 * send this info back to caller currently...
		 */
		if ( ! input )
		{
Jehan Monnier's avatar
Jehan Monnier committed
804
			printf("Cancel requested, but not implemented.\n");
aymeric's avatar
aymeric committed
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
			continue;
		}

		/* Strip blanks */
		iptr=lpc_strip_blanks(input);

		/*
		 * Only blanks, continue asking
		 */
		if ( ! *iptr )
		{
			free(input);
			continue;
		}

		/* Something typed, let's try */
		break;
	}

	/*
	 * No check is done here to ensure password is correct.
	 * I guess password will be asked again later.
	 */
	linphone_auth_info_set_passwd(pending_auth, input);
	linphone_core_add_auth_info(lc, pending_auth);
	--(auth_stack.nitems);
831
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
832 833 834 835 836 837
	/*
	 * Reset line_buffer, to avoid the password
	 * to be used again from outer readline
	 */
	rl_line_buffer[0]='\0';
	rl_event_hook=old_event_hook;
838
#endif
aymeric's avatar
aymeric committed
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
	return 1;
}

void
print_usage (int exit_status)
{
	fprintf (stdout, "\n\
usage: linphonec [-c file] [-s sipaddr] [-a] [-V] [-d level ] [-l logfile]\n\
       linphonec -v\n\
\n\
  -c  file             specify path of configuration file.\n\
  -d  level            be verbose. 0 is no output. 6 is all output\n\
  -l  logfile          specify the log file for your SIP phone\n\
  -s  sipaddress       specify the sip call to do at startup\n\
  -a                   enable auto answering for incoming calls\n\
  -V                   enable video features globally (disabled by default)\n\
  -C                   enable video capture only (disabled by default)\n\
  -D                   enable video display only (disabled by default)\n\
  -S                   show general state messages (disabled by default)\n\
  -v or --version      display version and exits.\n");

  	exit(exit_status);
}


/*
 *
 * Called every second from main read loop.
 *
 * Will use the following globals:
 *
 *  - LinphoneCore linphonec
 *  - LPC_AUTH_STACK auth_stack;
 *
 */
static int
linphonec_idle_call ()
{
877
	LinphoneCore *opm=linphonec;
aymeric's avatar
aymeric committed
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894

	/* Uncomment the following to verify being called */
	/* printf(".\n"); */

	linphone_core_iterate(opm);
	if (answer_call){
		fprintf (stdout, "-------auto answering to call-------\n" );
		linphone_core_accept_call(opm,NULL);
		answer_call=FALSE;
	}

	if ( auth_stack.nitems )
	{
		/*
		 * Inhibit command completion
		 * during password prompts
		 */
895
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
896
		rl_inhibit_completion=1;
897
#endif
aymeric's avatar
aymeric committed
898
		linphonec_prompt_for_auth_final(opm);
899
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
900
		rl_inhibit_completion=0;
901
#endif
aymeric's avatar
aymeric committed
902 903 904 905 906
	}

	return 0;
}

907
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922
/*
 * Use globals:
 *
 *	- char *histfile_name (also sets this)
 *      - char *last_in_history (allocates it)
 */
static int
linphonec_initialize_readline()
{
	/*rl_bind_key('\t', rl_insert);*/

	/* Allow conditional parsing of ~/.inputrc */
	rl_readline_name = "linphonec";

	/* Call idle_call() every second */
Jehan Monnier's avatar
Jehan Monnier committed
923
	rl_set_keyboard_input_timeout(LPC_READLINE_TIMEOUT);
aymeric's avatar
aymeric committed
924 925 926 927 928 929 930 931 932 933 934 935 936 937
	rl_event_hook=linphonec_idle_call;

	/* Set history file and read it */
	histfile_name = ms_strdup_printf ("%s/.linphonec_history",
		getenv("HOME"));
	read_history(histfile_name);

	/* Initialized last_in_history cache*/
	last_in_history[0] = '\0';

	/* Register a completion function */
	rl_attempted_completion_function = linephonec_readline_completion;

	/* printf("Readline initialized.\n"); */
Jehan Monnier's avatar
Jehan Monnier committed
938
        setlinebuf(stdout);
aymeric's avatar
aymeric committed
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
	return 0;
}

/*
 * Uses globals:
 *
 *	- char *histfile_name (writes history to file and frees it)
 *	- char *last_in_history (frees it)
 *
 */
static int
linphonec_finish_readline()
{

	stifle_history(HISTSIZE);
	write_history(histfile_name);
	free(histfile_name);
	histfile_name=NULL;
	return 0;
}

960 961
#endif

aymeric's avatar
aymeric committed
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
static void print_prompt(LinphoneCore *opm){
#ifdef IDENTITY_AS_PROMPT
	snprintf(prompt, PROMPT_MAX_LEN, "%s> ",
		linphone_core_get_primary_contact(opm));
#else
	snprintf(prompt, PROMPT_MAX_LEN, "linphonec> ");
#endif
}

static int
linphonec_main_loop (LinphoneCore * opm, char * sipAddr)
{
	char buf[LINE_MAX_LEN]; /* auto call handling */
	char *input;

	print_prompt(opm);


	/* auto call handling */
	if (sipAddr != NULL )
	{
		snprintf (buf, sizeof(buf),"call %s", sipAddr);
984
		linphonec_parse_command_line(linphonec, buf);
aymeric's avatar
aymeric committed
985 986
	}

smorlat's avatar
smorlat committed
987
	while (linphonec_running && (input=linphonec_readline(prompt)))
aymeric's avatar
aymeric committed
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
	{
		char *iptr; /* input and input pointer */
		size_t input_len;

		/* Strip blanks */
		iptr=lpc_strip_blanks(input);

		input_len = strlen(iptr);

		/*
		 * Do nothing but release memory
		 * if only blanks are read
		 */
		if ( ! input_len )
		{
			free(input);
			continue;
		}

1007
#ifdef HAVE_READLINE
aymeric's avatar
aymeric committed
1008 1009
		/*
		 * Only add to history if not already
1010 1011 1012
		 * last item in it, and only if the command
		 * doesn't start with a space (to allow for
		 * hiding passwords)
aymeric's avatar
aymeric committed
1013
		 */
1014
		if ( iptr == input && strcmp(last_in_history, iptr) )
aymeric's avatar
aymeric committed
1015 1016 1017 1018 1019
		{
			strncpy(last_in_history,iptr,sizeof(last_in_history));
			last_in_history[sizeof(last_in_history)-1]='\0';
			add_history(iptr);
		}
1020
#endif
aymeric's avatar
aymeric committed
1021

1022
		linphonec_parse_command_line(linphonec, iptr);
1023
		linphonec_command_finished();
aymeric's avatar
aymeric committed
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
		free(input);
	}

	return 0;
}

/*
 *  Parse command line switches
 *
 *  Use globals:
 *
 *	- int trace_level
 *	- char *logfile_name
 *	- char *configfile_name
 *	- char *sipAddr
 */
static int
linphonec_parse_cmdline(int argc, char **argv)
{
	int arg_num=1;

	while (arg_num < argc)
	{
		int old_arg_num = arg_num;
		if (strncmp ("-d", argv[arg_num], 2) == 0)
		{
			arg_num++;
			if (arg_num < argc)
				trace_level = atoi (argv[arg_num]);
			else
				trace_level = 1;
		}
		else if (strncmp ("-l", argv[arg_num], 2) == 0)
		{
			arg_num++;
			if (arg_num < argc)
				logfile_name = argv[arg_num];
		}
		else if (strncmp ("-c", argv[arg_num], 2) == 0)
		{
			if ( ++arg_num >= argc ) print_usage(EXIT_FAILURE);
Jehan Monnier's avatar
Jehan Monnier committed
1065
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
1066 1067 1068 1069 1070 1071 1072
			if (access(argv[arg_num],F_OK)!=0 )
			{
				fprintf (stderr,
					"Cannot open config file %s.\n",
					 argv[arg_num]);
				exit(EXIT_FAILURE);
			}
Jehan Monnier's avatar
Jehan Monnier committed
1073
#endif /*_WIN32_WCE*/
smorlat's avatar
smorlat committed
1074
			snprintf(configfile_name, PATH_MAX, "%s", argv[arg_num]);
aymeric's avatar
aymeric committed
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
		}
		else if (strncmp ("-s", argv[arg_num], 2) == 0)
		{
			arg_num++;
			if (arg_num < argc)
				sipAddr = argv[arg_num];
		}
                else if (strncmp ("-a", argv[arg_num], 2) == 0)
                {
                        auto_answer = TRUE;
                }
		else if (strncmp ("-C", argv[arg_num], 2) == 0)
                {
                        vcap_enabled = TRUE;
                }
		else if (strncmp ("-D", argv[arg_num], 2) == 0)
                {
                        display_enabled = TRUE;
                }
		else if (strncmp ("-V", argv[arg_num], 2) == 0)
                {
                        display_enabled = TRUE;
			vcap_enabled = TRUE;
1098
			preview_enabled=TRUE;
aymeric's avatar
aymeric committed
1099 1100 1101 1102 1103 1104 1105
                }
		else if ((strncmp ("-v", argv[arg_num], 2) == 0)
			 ||
			 (strncmp
			  ("--version", argv[arg_num],
			   strlen ("--version")) == 0))
		{
Jehan Monnier's avatar
Jehan Monnier committed
1106
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
1107
			printf ("version: " LINPHONE_VERSION "\n");
Jehan Monnier's avatar
Jehan Monnier committed
1108
#endif
aymeric's avatar
aymeric committed
1109 1110 1111 1112 1113 1114
			exit (EXIT_SUCCESS);
		}
		else if (strncmp ("-S", argv[arg_num], 2) == 0)
		{
			show_general_state = TRUE;
		}
1115 1116 1117 1118
		else if (strncmp ("--pipe", argv[arg_num], 6) == 0)
		{
			unix_socket=1;
		}
aymeric's avatar
aymeric committed
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
		else if (old_arg_num == arg_num)
		{
			fprintf (stderr, "ERROR: bad arguments\n");
			print_usage (EXIT_FAILURE);
		}
		arg_num++;
	}

	return 1;
}

/*
 * Up to version 1.2.1 linphone used ~/.linphonec for
 * CLI and ~/.gnome2/linphone for GUI as configuration file.
 * In newer version both interfaces will use ~/.linphonerc.
 *
 * This function helps transparently migrating from one
 * to the other layout using the following heuristic:
 *
 *	IF new_config EXISTS => do nothing
 *	ELSE IF old_cli_config EXISTS => copy to new_config
 *	ELSE IF old_gui_config EXISTS => copy to new_config
 *
 * Returns:
 *	 0 if it did nothing
 *	 1 if it migrated successfully
Jehan Monnier's avatar
Jehan Monnier committed
1145
 *	-1 on error
aymeric's avatar
aymeric committed
1146 1147 1148 1149
 */
static int
handle_configfile_migration()
{
Jehan Monnier's avatar
Jehan Monnier committed
1150
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
1151
	char *old_cfg_gui;
Jehan Monnier's avatar
Jehan Monnier committed
1152
	char *old_cfg_cli;
aymeric's avatar
aymeric committed
1153
	char *new_cfg;
Jehan Monnier's avatar
Jehan Monnier committed
1154
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
1155
	const char *home = getenv("HOME");
Jehan Monnier's avatar
Jehan Monnier committed
1156 1157 1158
#else
	const char *home = ".";
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
	new_cfg = ms_strdup_printf("%s/.linphonerc", home);

	/*
	 * If the *NEW* configuration already exists
	 * do nothing.
	 */
	if (access(new_cfg,F_OK)==0)
	{
		free(new_cfg);
		return 0;
	}

	old_cfg_cli = ms_strdup_printf("%s/.linphonec", home);

	/*
	 * If the *OLD* CLI configurations exist copy it to
	 * the new file and make it a symlink.
	 */
	if (access(old_cfg_cli, F_OK)==0)
	{
		if ( ! copy_file(old_cfg_cli, new_cfg) )
		{
			free(old_cfg_cli);
			free(new_cfg);
			return -1;
		}
		printf("%s copied to %s\n", old_cfg_cli, new_cfg);
		free(old_cfg_cli);
		free(new_cfg);
		return 1;
	}

	free(old_cfg_cli);
	old_cfg_gui = ms_strdup_printf("%s/.gnome2/linphone", home);

	/*
	 * If the *OLD* GUI configurations exist copy it to
	 * the new file and make it a symlink.
	 */
	if (access(old_cfg_gui, F_OK)==0)
	{
		if ( ! copy_file(old_cfg_gui, new_cfg) )
		{
			exit(EXIT_FAILURE);
			free(old_cfg_gui);
			free(new_cfg);
			return -1;
		}
		printf("%s copied to %s\n", old_cfg_gui, new_cfg);
		free(old_cfg_gui);
		free(new_cfg);
		return 1;
	}

	free(old_cfg_gui);
	free(new_cfg);
Jehan Monnier's avatar
Jehan Monnier committed
1215
#endif /*_WIN32_WCE*/
aymeric's avatar
aymeric committed
1216 1217
	return 0;
}
Jehan Monnier's avatar
Jehan Monnier committed
1218
#if !defined(_WIN32_WCE)
aymeric's avatar
aymeric committed
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
/*
 * Copy file "from" to file "to".
 * Destination file is truncated if existing.
 * Return 1 on success, 0 on error (printing an error).
 */
static int
copy_file(const char *from, const char *to)
{
	char message[256];
	FILE *in, *out;
	char buf[256];
	size_t n;

	/* Open "from" file for reading */
	in=fopen(from, "r");
	if ( in == NULL )
	{
		snprintf(message, 255, "Can't open %s for reading: %s\n",
			from, strerror(errno));
smorlat's avatar
smorlat committed
1238
		fprintf(stderr, "%s", message);
aymeric's avatar
aymeric committed
1239 1240 1241 1242 1243 1244 1245 1246 1247
		return 0;
	}

	/* Open "to" file for writing (will truncate existing files) */
	out=fopen(to, "w");
	if ( out == NULL )
	{
		snprintf(message, 255, "Can't open %s for writing: %s\n",
			to, strerror(errno));
smorlat's avatar
smorlat committed
1248
		fprintf(stderr, "%s", message);
aymeric's avatar
aymeric committed
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
		return 0;
	}

	/* Copy data from "in" to "out" */
	while ( (n=fread(buf, 1,