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(); } }
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); }
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(); }
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; }
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); }
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); }
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); }