Exemple #1
0
void cleanup(void)
{
	terminated=TRUE;

	lprintf(LOG_INFO,"Cleaning up ...");


	if(com_handle!=COM_HANDLE_INVALID) {
		if(!mdm_null && mdm_cleanup[0])
			modem_command(com_handle, mdm_cleanup);
		if(!com_handle_passed)
			comClose(com_handle);
	}

	close_socket(&sock);

#ifdef _WINSOCKAPI_
	WSACleanup();
#endif

	lprintf(LOG_INFO,"Done (handled %lu calls).", total_calls);

#if defined(_WIN32)
	if(daemonize && svc_status_handle!=0) {
		svc_status.dwCurrentState=SERVICE_STOPPED;
		SetServiceStatus(svc_status_handle, &svc_status);
	} else
#endif
	if(pause_on_exit) {
		printf("Hit enter to continue...");
		getchar();
	}
}
Exemple #2
0
static int slip_dial (const char *str)
{
  char dial_str[80];
  WORD mcr = slip_base_reg + 4;
  WORD lcr = slip_base_reg + 3;

  _outportb (lcr, _inportb(lcr) & 0x43);  /* 8N1 */
  _outportb (mcr, _inportb(mcr) | 1);     /* raise DTR */

  if (!modem_command("ATZ\r","OK",5))
     return (0);

  strcpy (dial_str, str);
  strcat (dial_str, "\r");
  outs (_LANG("SLIP dialing.."));

  if (!modem_command(dial_str,"OK",2))
     return (-1);

  if (!modem_command(NULL,"CONNECT",slip_timeout))
     return (-2);
  return (0);
}
Exemple #3
0
static int voice_set_compression(short c)
{
	char command[64];

	if ((c >= 2) && (c <= 6) && (c != 5))
	{
		printstring(command, "AT+VSM=%d+VLS=2", c);

		log(L_DEBUG, "Setting voice compression \"%s\"...\n", compressions[c]);

		return(modem_command(command, "OK|VCON"));
	}

	log(L_FATAL, "Unknown compression %d - can't set.\n", c);
	
	returnerror();
}
Exemple #4
0
BOOL wait_for_call(COM_HANDLE com_handle)
{
	char		str[128];
	char*		p;
	BOOL		result=TRUE;
	DWORD		events=0;
	time_t		start=time(NULL);

	ZERO_VAR(cid_name);
	ZERO_VAR(cid_number);

	if(!comRaiseDTR(com_handle))
		lprintf(LOG_ERR,"ERROR %u raising DTR", COM_ERROR_VALUE);

	if(com_alreadyconnected)
		return TRUE;

	if(!mdm_null) {
		if(mdm_init[0]) {
			lprintf(LOG_INFO,"Initializing modem:");
			if(!modem_command(com_handle, mdm_init))
				return FALSE;
		}
		if(!mdm_manswer && mdm_autoans[0]) {
			lprintf(LOG_INFO,"Setting modem to auto-answer:");
			if(!modem_command(com_handle, mdm_autoans))
				return FALSE;
		}
		if(mdm_cid[0]) {
			lprintf(LOG_INFO,"Enabling modem Caller-ID:");
			if(!modem_command(com_handle, mdm_cid))
				return FALSE;
		}
	}

	lprintf(LOG_INFO,"Waiting for incoming call (%s) ...", mdm_manswer ? "Ring Indication" : "Carrier Detect");
	while(1) {
		if(terminated)
			return FALSE;
		if(comReadLine(com_handle, str, sizeof(str), /* timeout (ms): */250) > 0) {
			truncsp(str);
			if(str[0]==0)
				continue;
			lprintf(LOG_DEBUG,"Received from modem: '%s'", str);
			p=str;
			SKIP_WHITESPACE(p);
			if(*p) {
				lprintf(LOG_INFO, "Modem Message: %s", p);
				if(strncmp(p,"CONNECT ",8)==0) {
					long rate=atoi(p+8);
					if(rate)
						SAFEPRINTF2(termspeed,"%u,%u", rate, rate);
				}
				else if(strncmp(p,"NMBR",4)==0 || strncmp(p,"MESG",4)==0) {
					p+=4;
					FIND_CHAR(p,'=');
					SKIP_CHAR(p,'=');
					SKIP_WHITESPACE(p);
					if(cid_number[0]==0)	/* Don't overwrite, if multiple messages received */
						SAFECOPY(cid_number, p);
				}
				else if(strncmp(p,"NAME",4)==0) {
					p+=4;
					FIND_CHAR(p,'=');
					SKIP_CHAR(p,'=');
					SKIP_WHITESPACE(p);
					SAFECOPY(cid_name, p);
				}
				else if(strcmp(p,"NO CARRIER")==0) {
					ZERO_VAR(cid_name);
					ZERO_VAR(cid_number);
				}
				else if(mdm_ring[0] && strcmp(p,mdm_ring)==0 && mdm_manswer && mdm_answer[0]) {
					if(!modem_send(com_handle, mdm_answer)) {
						lprintf(LOG_ERR,"ERROR %u sending modem command (%s) on %s"
							,COM_ERROR_VALUE, mdm_answer, com_dev);
					}
				}
			}
			continue;	/* don't check DCD until we've received all the modem msgs */
		}
		if(carrier_detect(com_handle))
			break;
		if(mdm_reinit && (time(NULL)-start)/60 >= mdm_reinit) {
			lprintf(LOG_INFO,"Re-initialization timer elapsed: %u minutes", mdm_reinit);
			return TRUE;
		}
	}

	if(strcmp(cid_name,"P")==0)
		SAFECOPY(cid_name,"Private");
	else if(strcmp(cid_name,"O")==0)
		SAFECOPY(cid_name,"Out-of-area");

	if(strcmp(cid_number,"P")==0)
		SAFECOPY(cid_number,"Private");
	else if(strcmp(cid_number,"O")==0)
		SAFECOPY(cid_number,"Out-of-area");

	lprintf(LOG_INFO,"Carrier detected");
	return TRUE;
}
Exemple #5
0
void main(int argc, char **argv)
{
	char *stop;
	int	opts;
	char *debugstr;
	int	debuglvl;
	int	i;
	int	modemstate;
	int	modeminits;

	breaklist_init();

	progbasename = argv[0];

	if ((stop = rindex(argv[0], '/'))) progbasename = ++stop;

		/* Die Argumente des Programms einlesen und den Debuglevel	*/
		/* setzen.																	*/

	debugstr		= NULL;
	isdnttyname	= NULL;

	while ((opts = getopt_long(argc, argv, "vhx:d:", arguments, (int *)0)) != EOF)
	{
		switch (opts)
		{
			case 'x':
				debugstr = optarg;
				break;

			case 'd':
				isdnttyname = optarg;
				break;

			case 'v':
				show_usage(200, 0);
				break;

			case 'h':
			default:
				show_usage(200, 1);
				break;
		}
	}

	if (debugstr)
	{
		if (strcasecmp(debugstr, "FULL") != 0)
		{
			debuglvl = LOG_E;

			for (i = 0; i < strlen(debugstr); i++)
			{
				switch (debugstr[i])
				{
					case 'W':
					case 'w':
						debuglvl |= LOG_W;
						break;
					
					case 'I':
						debuglvl |= LOG_I;
						break;
					
					case 'A':
						debuglvl |= LOG_A;
						break;
					
					case 'D':
						debuglvl |= LOG_D;
						break;
				}
			}
		}
		else debuglvl = LOG_X;

		log_set_debuglevel(debuglvl);
	}

	umask(xstrtoo(VBOX_ROOT_UMASK, 0));

		/* Pfadangaben vom Devicenamen abschneiden und überprüfen ob	*/
		/* das Device vom Benutzer gelesen und beschrieben werden		*/
		/* kann (eigentlich nicht nötig, da nur unter Rootrechten ge-	*/
		/* startet werden kann.														*/

	if (isdnttyname)
	{
		if ((stop = rindex(isdnttyname, '/'))) isdnttyname = ++stop;

		printstring(savettydname, "%s"     , isdnttyname);
		printstring(temppathname, "/dev/%s", isdnttyname);
		
		if (access(temppathname, F_OK|R_OK|W_OK) != 0)
		{
			fprintf(stderr, "\n%s: error: \"%s\" doesn't exist or is not accessible!\n\n", progbasename, temppathname);

			quit_program(100);
		}
	}
	else
	{
		fprintf(stderr, "\n%s: error: isdn tty name is required!\n", progbasename);

		show_usage(100, 1);
	}

		/* Prüfen ob das Programm unter Rootrechten gestartet wurde. Die	*/
		/* Rechte werden später auf die des jeweiligen Benutzers geän-		*/
		/* dert, zum Start sind aber Rootrechte nötig.							*/

	if (getuid() != 0)
	{
		fprintf(stderr, "\n%s: error: need root privilegs to start!\n\n", progbasename);

		quit_program(100);
	}

		/* Jetzt wird der Log geöffnet. Der Name des aktuellen Devices	*/
		/* wird an das Ende angehängt.											*/

	printstring(temppathname, "%s/vboxgetty-%s.log", LOGDIR, isdnttyname);

	log_open(temppathname);

		/* Tcl-Interpreter starten. Für die momentanen Funktionen wird	*/
		/* Version 8 oder höher benötigt.										*/

	if (scr_create_interpreter() == -1)
	{
		log_line(LOG_E, "Can't create/initialize the tcl interpreter!\n");
		
		quit_program(100);
	}

	log_line(LOG_I, "Running vbox version %s (with tcl version %s).\n", VERSION, scr_tcl_version());

		/* Konfiguration des getty's abarbeiten. Zuerst wird die globale,	*/
		/* dann die des jeweiligen tty's eingelesen.								*/

	if (vboxgettyrc_parse(isdnttyname) == -1)
	{
		log_line(LOG_E, "Unable to read/parse configuration!\n");
	
		quit_program(100);
	}

		/* Modem Device öffnen und die interne Initialisierung	*/
		/* ausführen (nicht der normale Modeminit).					*/

	printstring(temppathname, "/dev/%s", isdnttyname);

	log_line(LOG_D, "Opening modem device \"%s\" (38400, CTS/RTS)...\n", temppathname);

	if (vboxmodem_open(&vboxmodem, temppathname) == -1)
	{
		log_line(LOG_E, "Can't open/setup modem device (%s).\n", vboxmodem_error());

		quit_program(100);
	}

		/* Lock- und PID-Datei für den getty und das entsprechende	*/
		/* Device erzeugen.														*/

	printstring(temppathname, "%s/LCK..%s", LOCKDIR, isdnttyname);
	
	if (lock_create(temppathname) == -1) quit_program(100);

	printstring(temppathname, "%s/vboxgetty-%s.pid", PIDDIR, isdnttyname);

	pid_create(temppathname);

		/* Signalhändler installieren. Alle möglichen Signale werden	*/
		/* auf quit_program() umgelenkt.											*/

	signal(SIGINT , quit_program);
	signal(SIGTERM, quit_program);
	signal(SIGHUP , quit_program);

		/* Hauptloop: Der Loop wird nur verlassen, wenn während der	*/
		/* Abarbeitung ein Fehler aufgetreten ist. Das Programm be-	*/
		/* endet sich danach!													*/
	
	modemstate = VBOXMODEM_STAT_INIT;
	modeminits = 0;
	
	while (modemstate != VBOXMODEM_STAT_EXIT)
	{
		switch (modemstate)
		{
			case VBOXMODEM_STAT_INIT:

				if (run_modem_init() == -1)
				{
					if ((i = (int)xstrtol(rc_get_entry(rc_getty_c, "badinitsexit"), 10)) > 0)
					{
						modeminits++;
						
						if (modeminits >= i)
						{
							modemstate = VBOXMODEM_STAT_EXIT;
							modeminits = 0;
							
							log_line(LOG_E, "Exit program while bad init limit are reached.\n");
						}
						else log_line(LOG_W, "Bad initialization - Program will exist on %d trys!\n", (i - modeminits));
					}
				}
				else
				{
					modemstate = VBOXMODEM_STAT_WAIT;
					modeminits = 0;
				}
				break;

			case VBOXMODEM_STAT_WAIT:
				
				modem_flush(&vboxmodem, 0);

				if (modem_wait(&vboxmodem) == 0)
				{
					modemstate = VBOXMODEM_STAT_RING;
					modeminits = 0;
				}
				else modemstate = VBOXMODEM_STAT_TEST;
				
				break;

			case VBOXMODEM_STAT_TEST:
			
				log_line(LOG_D, "Checking if modem is still alive...\n");
				
				if (modem_command(&vboxmodem, "AT", "OK") > 0)
				{
					modemstate = VBOXMODEM_STAT_WAIT;
					modeminits = 0;
				}
				else modemstate = VBOXMODEM_STAT_INIT;
				
				break;
				
			case VBOXMODEM_STAT_RING:
			
				modem_set_nocarrier(&vboxmodem, 0);
				process_incoming_call();
				modem_hangup(&vboxmodem);

				if (set_process_permissions(0, 0, xstrtoo(VBOX_ROOT_UMASK, 0)) != 0)
					modemstate = VBOXMODEM_STAT_EXIT;
				else
 					modemstate = VBOXMODEM_STAT_INIT;
				
				break;

			default:

				log_line(LOG_E, "Unknown modem status %d!\n", modemstate);
				
				modemstate = VBOXMODEM_STAT_INIT;
				
				break;
		}
	}

	quit_program(0);
}
Exemple #6
0
int voice_get_message(char *name, char *timestr, int save)
{
	vaheader_t	header;
	char			line_i[MODEM_BUFFER_LEN + 1];
	char			line_o[MODEM_BUFFER_LEN + 1];
	int			byte_i;
	int			byte_o;
	int			result;
	int			havedle;
	int			savetimeout;
	int			fd;

	savetimeout = xstrtol(timestr, 90);

	if (save)
		log(L_INFO, "Recording \"%s\" (%d secs)...\n", name, savetimeout);
	else
		log(L_INFO, "Waiting %d secs for input...\n", savetimeout);

	if (!voice_set_compression(setup.modem.compression))
	{
		log(L_ERROR, "Can't set voice audio compressen.\n");

		return(VOICE_ACTION_ERROR);
	}

	if (save)
	{
		if ((fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IWGRP|S_IWOTH)) == -1)
	   {
	   	log(L_ERROR, "Can't create \"%s\".\n", name);

			return(VOICE_ACTION_ERROR);
		}

		truncate(name, 0);

		voice_set_header(&header);

		if (!header_put(fd, &header))
		{
	      log(L_ERROR, "Can't write vbox audio header.\n");
      
			voice_close_or_unlink(fd, name);

			return(VOICE_ACTION_ERROR);
		}
	}
	else fd = -1;

	if (modem_get_nocarrier_state())
	{
		if (save) voice_close_or_unlink(fd, name);

		return(VOICE_ACTION_LOCALHANGUP);
	}

	if (modem_command("AT+VRX", "CONNECT") == 0)
	{
		log(L_ERROR, "Can't start record mode.\n");

		if (save) voice_close_or_unlink(fd, name);

		return(VOICE_ACTION_ERROR);
	}

	sequencestatus	= ST_NO_INPUT;
	voicestatus		= VOICE_ACTION_OK;
	havedle			= FALSE;

	modem_set_timeout(savetimeout);

	while (voicestatus == VOICE_ACTION_OK)
	{
		byte_o = 0;
		byte_i = 0;
		result = 0;

		while ((byte_o < MODEM_BUFFER_LEN) && (voicestatus == VOICE_ACTION_OK))
		{
			if ((result = modem_raw_read(line_i, 1)) == 1)
			{
				byte_i++;

				if (havedle)
				{
					switch (*line_i)
					{
						case DLE:
							line_o[byte_o++] = DLE;
							break;

						case ETX:
							log(L_DEBUG, "Found sequence \"<DLE><ETX>\" (remote hangup)...\n");
							voicestatus = VOICE_ACTION_REMOTEHANGUP;
							break;

						default:
							voice_handle_touchtone_dle(*line_i);
							break;
					}

					havedle = FALSE;
				}
				else
				{
					if (*line_i != DLE)
					{
						line_o[byte_o++] = *line_i;
					}
					else havedle = TRUE;
				}
			}
			else break;
		}

		if (byte_o > 0)
		{
			if (save)
			{
				log(L_JUNK, "Record: <DATA %d incoming; %d outgoing>\n", byte_i, byte_o);
                         
				write(fd, line_o, byte_o);
			}
			else log(L_JUNK, "Wait: <DATA %d incoming>\n", byte_i);
		}

		if ((result != 1) || (modem_get_timeout()))
		{
			if (!modem_get_timeout())
			{
				log(L_ERROR, "Can't read incoming data (%s).\n", strerror(errno));
				
				voicestatus = VOICE_ACTION_ERROR;
			}
			else voicestatus = VOICE_ACTION_TIMEOUT;
		}

		if ((result == 1) && (ctrl_ishere(setup.spool, CTRL_NAME_SUSPEND))) {   
			log(L_INFO, "Control file \"%s\" exists - suspending call...\n", CTRL_NAME_SUSPEND);
			if (!ctrl_remove(setup.spool, CTRL_NAME_SUSPEND)) {
				log(L_WARN, "Can't remove control file \"%s\"!\n", CTRL_NAME_SUSPEND);
			}
			log(L_JUNK, "Sending \"<DLE><DC4>\"...\n");
			printstring(line_o, "%c%c", DLE, DC4);
			printstring(line_i, "%c%c", DLE, ETX);
			modem_raw_write(line_o, strlen(line_o));
			modem_wait_sequence(line_i);
			if (modem_command("", "VCON")>0) {
#ifdef VBOX_SUSPEND_VALUE
				printstring(line_o, "AT+S%d", VBOX_SUSPEND_VALUE);
#else
				printstring(line_o, "AT+S");
#endif
				if (modem_command(line_o, "OK") <= 0) {
					log(L_WARN, "Can't suspend call\n");
				} else {
					log(L_INFO, "Call suspended\n");
					voicestatus = VOICE_ACTION_REMOTEHANGUP;
				}
			}
		}

		if ((voicestatus == VOICE_ACTION_OK) || (voicestatus == VOICE_ACTION_TIMEOUT))
		{
			if ((index(touchtones, '#')) && (index(touchtones, '*')))
			{
				log(L_DEBUG, "Touchtone sequence \"%s\" found.\n", touchtones);

				if (breaklist_search(touchtones))
				{
					log(L_INFO, "Sequence \"%s\" found in breaklist...\n", touchtones);

					voicestatus = VOICE_ACTION_TOUCHTONES;
				}
				else
				{
					log(L_DEBUG, "Sequence \"%s\" not in breaklist (ignored)...\n", touchtones);

					*touchtones = '\0';
				}
			}
		}
	}

	modem_set_timeout(0);

	if (save)
	{
		voice_close_or_unlink(fd, NULL);

		permissions_set(name, setup.users.uid, setup.users.gid, S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH, setup.users.umask);
	}

	if ((voicestatus == VOICE_ACTION_REMOTEHANGUP) || (modem_get_nocarrier_state()))
	{
			/*
			 * Remote hangup: Modem should response with the sequence
			 * NO CARRIER.
			 */

		modem_command("", "NO CARRIER");
	}
	else
	{
			/*
			 * Local hangup: send <DLE><DC4> to the modem and read the
			 * response <DLE><ETX> and VCON.
			 */

		printstring(line_o, "%c%c", DLE, DC4);
		printstring(line_i, "%c%c", DLE, ETX);

		log(L_JUNK, "Sending \"<DLE><DC4>\"...\n");

		modem_raw_write(line_o, strlen(line_o));

		modem_get_sequence(line_i);

		modem_command("", "VCON");
	}

	if (modem_get_nocarrier_state()) voicestatus = VOICE_ACTION_REMOTEHANGUP;

	return(voicestatus);
}
Exemple #7
0
int voice_put_message(char *message)
{
	vaheader_t header;
	long int   compression;
	char	     line_i[MODEM_BUFFER_LEN + 1];
	char	     line_o[MODEM_BUFFER_LEN + MODEM_BUFFER_LEN + 1];
	int	     fd;
	int	     i;
	int	     byte_i;
	int	     byte_o;
	int	     written;
	int	     havedle;
	time_t     timebeg;
	time_t     timeend;
	int	     bytetotal;
	int	     secstotal;

	log(L_INFO, "Playing \"%s\"...\n", message);

	if ((fd = open(message, O_RDONLY)) == -1)
	{
		log(L_ERROR, "Can't open \"%s\".\n", message);

		return(VOICE_ACTION_ERROR);
	}

	if (!header_get(fd, &header))
	{
		log(L_ERROR, "Can't read vbox audio header from message.\n");

		voice_close_or_unlink(fd, NULL);

		return(VOICE_ACTION_ERROR);
	}

	compression = ntohl(header.compression);

	if (!voice_set_compression(compression))
	{
		log(L_ERROR, "Can't set voice audio compression or line mode.\n");
		
		voice_close_or_unlink(fd, NULL);

		return(VOICE_ACTION_ERROR);
	}

	if (modem_get_nocarrier_state())
	{
		voice_close_or_unlink(fd, NULL);

		return(VOICE_ACTION_REMOTEHANGUP);
	}

	if (modem_command("AT+VTX", "CONNECT") == 0)
	{
		log(L_ERROR, "Can't start voice play mode.\n");
		
		voice_close_or_unlink(fd, NULL);

		return(VOICE_ACTION_ERROR);
	}

	voicestatus		= VOICE_ACTION_OK;
	sequencestatus	= ST_NO_INPUT;
	havedle			= FALSE;
	bytetotal		= 0;

	timebeg = time(NULL);

	while (voicestatus == VOICE_ACTION_OK)
	{
		if ((byte_i = read(fd, line_i, MODEM_BUFFER_LEN)) <= 0)
		{
			if (byte_i == 0)
                            log(L_DEBUG, "End of audio data\n");
                        else
                            log(L_DEBUG, "End of audio data with error (%s)\n", strerror(errno));

			break;
		}

		byte_o = 0;

		for (i = 0; i < byte_i; i++)
		{
			line_o[byte_o] = line_i[i];

			if (line_o[byte_o++] == DLE) line_o[byte_o++] = DLE;
		}

		bytetotal += byte_o;

		log(L_JUNK, "Play: <DATA %d incoming; %d outgoing>\n", byte_i, byte_o);

		if (!modem_get_nocarrier_state())
		{
			written	= 0;
			errno		= 0;

			while (written != byte_o)
			{
				written += modem_raw_write(&line_o[written], (byte_o - written));

				if (errno != 0) break;
			}

			if ((written != byte_o) || (errno != 0))
			{
				log(L_ERROR, "Could only write %d of %d bytes (%s).\n", written, byte_o, strerror(errno));

				voicestatus = VOICE_ACTION_ERROR;
			}
		}
		else voicestatus = VOICE_ACTION_REMOTEHANGUP;

		while ((modem_check_input()) && (voicestatus == VOICE_ACTION_OK))
		{
			log(L_JUNK, "Have input...\n");

			if (modem_raw_read(line_i, 1) == 1)
			{
				if (havedle)
				{
					switch (*line_i)
					{
						case ETX:
						case 'b':
						case 'c':
						case 'e':
						case 'd':
						case 'q':
						case 's':
							log_line(L_DEBUG, "Found sequence \"<DLE>");
							log_char(L_DEBUG, *line_i);
							log_text(L_DEBUG, "\" (ignored)...\n");
							break;

						case DC4:
							log(L_DEBUG, "Found sequence \"<DLE><DC4>\" (remote hangup)...\n");
							voicestatus = VOICE_ACTION_REMOTEHANGUP;
							break;
							
						default:
							voice_handle_touchtone_dle(*line_i);
							break;
					}

					havedle = FALSE;
				}
				else
				{
					if (*line_i != DLE)
					{
						log_line(L_DEBUG, "Got unneeded character \"");
						log_char(L_DEBUG, *line_i);
						log_text(L_DEBUG, "\" (need a \"<DLE>\").\n");
					}
					else havedle = TRUE;
				}

				if (voicestatus == VOICE_ACTION_OK)
				{
					if ((index(touchtones, '#')) && (index(touchtones, '*')))
					{
						log(L_DEBUG, "Touchtone sequence \"%s\" found.\n", touchtones);

						if (breaklist_search(touchtones))
						{
							log(L_INFO, "Sequence \"%s\" found in breaklist...\n", touchtones);

							voicestatus = VOICE_ACTION_TOUCHTONES;
						}
						else
						{
							log(L_DEBUG, "Sequence \"%s\" not in breaklist (ignored)...\n", touchtones);

							*touchtones = '\0';
						}
					}
				}
			}
			else log(L_ERROR, "Can't read input from modem.\n");
		}
		if (ctrl_ishere(setup.spool, CTRL_NAME_SUSPEND)) {   
			log(L_INFO, "Control file \"%s\" exists - suspending call...\n", CTRL_NAME_SUSPEND);
			if (!ctrl_remove(setup.spool, CTRL_NAME_SUSPEND)) {
				log(L_WARN, "Can't remove control file \"%s\"!\n", CTRL_NAME_SUSPEND);
			}
			log(L_JUNK, "Sending \"<DLE><ETX>\"...\n");
			printstring(line_o, "%c%c", DLE, ETX);
			modem_raw_write(line_o, strlen(line_o));
			if (modem_command("", "VCON")>0) {
#ifdef VBOX_SUSPEND_VALUE
				printstring(line_o, "AT+S%d", VBOX_SUSPEND_VALUE);
#else
				printstring(line_o, "AT+S");
#endif
				if (modem_command(line_o, "OK") <= 0) {
					log(L_WARN, "Can't suspend call\n");
				} else {
					log(L_INFO, "Call suspended\n");
					voicestatus = VOICE_ACTION_REMOTEHANGUP;
				}
			}
		}
	}

	timeend = time(NULL);

	if (timeend >= timebeg)
	{
		secstotal = (timeend - timebeg);
		bytetotal = get_message_ptime(compression, bytetotal);

		log(L_JUNK, "Function play %d secs (kernel needs %d secs)...\n", secstotal, bytetotal);

		if (secstotal < bytetotal)
		{
			log(L_JUNK, "Waiting %d secs to complete playing...\n", (bytetotal - secstotal));

			xpause((bytetotal - secstotal) * 1000);
		}
	}
	else log(L_WARN, "Oops - can't calculate time to wait!\n");

	voice_close_or_unlink(fd, NULL);

	if ((voicestatus == VOICE_ACTION_REMOTEHANGUP) || (modem_get_nocarrier_state()))
	{
			/*
			 * Remote hangup: We have got the sequence <DLE><DC4> in the
			 * modem stream...
			 */

		modem_command("", "NO CARRIER");
	}
	else
	{
			/*
			 * Local hangup: Send <DLE><ETX> to the modem and wait for the
			 * result VCON...
			 */

		log(L_JUNK, "Sending \"<DLE><ETX>\"...\n");
		printstring(line_o, "%c%c", DLE, ETX);
		modem_raw_write(line_o, strlen(line_o));
		modem_command("", "VCON");
	}

	if (modem_get_nocarrier_state()) voicestatus = VOICE_ACTION_REMOTEHANGUP;

	return(voicestatus);
}