/* A Linux-based Telephone Answering Machine * Copyright: Bob Smith, 2005 * Warranty: No warranty expressed or implied. USE AT YOUR OWN RISK! * License: GNU General Public License, version 2 * See http://www.gnu.org/copyleft/gpl.html for full text * Documentation: http://www.linuxtoys.org/answer/answering_machine.html * Version: 1.0.0 2005-Sep-20, Initial release * REQUIREMENTS: * - Intel 537 based softmodem * - A PCI slot that does not share interrupts * - Linux 2.6 with gcc and sox installed * INSTALLATION: * 1) Install the zaptel drivers from Asterisk * 2) Install the Zapata library from Asterisk * 3) Record a greeting asking the caller to press 1 to * leave a message. Convert the WAV file to mu-law using: * sox leave_a_msg.wav leave_a_msg.ul * 4) Compile the program using: * gcc -lzap -o answering_machine answering_machine.c * USAGE: * There are no command line options. Invoke the program with: * ./answering_machine * Voice mail files can be heard using the 'play' utility from * the sox package. For example: * play 2005_09_22_14_37_03.ul * By-the-way: * The zap_xxx() calls in this program are well documented in * zap.c in the Zapata source directory. */ #include #include #include #include /* The number of rings to wait before answering */ #define RINGS (4) /* DTMF digit you ask the caller to press to leave a msg */ #define PLEASE_ENTER '1' /* The time (ms) to wait for a "1" from the caller */ #define TM_OUT (9000) /* The maximum size of a string in this program */ #define STRMX (65) /* A generic error collection subroutine */ void err_if(int, char, int, int); /* The handle to the open telephone interface */ ZAP *zp; main() { int result; /* return code from Zapata call */ char *pDigits; /* points to entered DTMF digits */ char cidnumber[STRMX]; /* Caller-ID phone number */ char cidname[STRMX]; /* Caller-ID name */ char date_time[STRMX]; /* date and time from strftime() */ struct tm *ptm; /* date and time in tm structure */ time_t now; /* Current time in seconds */ zp = zap_open("/dev/zap/1", 0); if (!zp) { printf("Unable to open /dev/zap/1. Please verify that the\n"); printf("zaptel and wcfxo modules are installed, and that your\n"); printf("hardware is installed and working correctly.\n"); exit(1); } while (1) { /* Wait for a ring and get caller ID info */ result = zap_clid(zp, cidnumber, cidname); err_if(result, '=', -1, __LINE__); /* error if -1 */ if (result == -2) { /* internal error getting CLID */ cidnumber[0] = (char) 0; /* happens on quick user pick-up */ strncpy(cidname, "(invalid caller ID)", STRMX-1); } /* Print date, time, and caller ID info */ date_time[0] = (char) 0; now = time((time_t *) 0); ptm = localtime(&now); err_if((int)ptm, '=', 0, __LINE__); /* error if zero */ (void) strftime(date_time, 63, "%T", ptm); printf("%s %s %s ", date_time, cidnumber, cidname); fflush(stdout); /* Wait for an additional RINGS-1 rings before answering */ result = zap_waitcall(zp, (RINGS - 1), ZAP_OFFHOOK, (TM_OUT/1000)); if (result == -1 && errno == EINTR) { printf("\n"); /* local user picked-up */ continue; } err_if(result, '!', 0, __LINE__); /* error if not zero */ /* Init the digit buffer and tell Zapata that we want DTMF digits */ (void) zap_clrdtmfn(zp); result = zap_digitmode(zp, ZAP_DTMF) && zap_clrdtmf(zp); err_if(result, '!', 0, __LINE__); /* error if not zero */ /* Play our outgoing message. Abort on DTMF or hang-up. */ result = zap_playf(zp, "leave_a_msg.ul", ZAP_DTMFINT | ZAP_HOOKEXIT); err_if(result, '=', -1, __LINE__); /* error if -1 */ if (result == -2) { /* == -2 on caller hang-up */ printf("\n"); zap_sethook(zp, ZAP_ONHOOK); continue; } /* Wait up to TM_OUT ms for the caller to enter a DTMF digit */ result = zap_getdtmf(zp, 1, (char *)0, 0, 0, TM_OUT, ZAP_HOOKEXIT); err_if(result, '=', -1, __LINE__); /* error if -1 */ /* Hang-up if time-out and no DTMF digit. (Bulk dialer?) */ if (result != 1) { printf("\n"); zap_sethook(zp, ZAP_ONHOOK); err_if(result, '=', -1, __LINE__); /* error if -1 */ continue; } /* Get the DTMF digit the caller entered. Hang-up if wrong digit */ pDigits = zap_dtmfbuf(zp); if ((!pDigits) || (*pDigits != PLEASE_ENTER)) { printf("\n"); zap_sethook(zp, ZAP_ONHOOK); err_if(result, '=', -1, __LINE__); /* error if -1 */ continue; } printf("************\n"); /* Tell local user of voice mail */ /* Create voice mail file: YYYY_MM_DD_HH_mm_SS.ul */ (void) strftime(date_time, 63, "%G_%m_%d_%H_%M_%S.ul", ptm); result = zap_recf(zp, date_time, 0, ZAP_BEEPTONE | ZAP_HOOKEXIT | ZAP_SILENCEINT); err_if(result, '=', -1, __LINE__); /* error if -1 */ /* Done with message. Hang-up and wait for next call. */ result = zap_sethook(zp, ZAP_ONHOOK); err_if(result, '=', -1, __LINE__); /* error if -1 */ } exit(0); /* not reached */ } /* err_if() -- Exit the program if the result is not correct. * Inputs are the result, the comparison operator, the value * to match, and the line number */ void err_if(int result, char operator, int errval, int linenum) { if (((operator == '=') && (result == errval)) || ((operator == '!') && (result != errval))) { printf("Error code %d at line = %d, with errno = %d. Bye...\n", result, linenum, errno); (void) zap_sethook(zp, ZAP_ONHOOK); exit(1); } }