Advertisement
Guest User

jcblockAT

a guest
Dec 9th, 2016
222
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 39.79 KB | None | 0 0
  1. /*
  2. * Program name: jcblockAT
  3. *
  4. * File name: jcblockAT.c
  5. *
  6. * Note: this file contains a version of the jcblock program designed
  7. * specifically for the ATian voice/FAX modem. This modem provides
  8. * all hardware features necessary to support all program operations.
  9. *
  10. * Copyright: Copyright 2015 Walter S. Heath
  11. *
  12. * Copy permission:
  13. * This program is free software: you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation, either version 3 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You may view a copy of the GNU General Public License at:
  24. * <http://www.gnu.org/licenses/>.
  25. *
  26. * Description:
  27. * A program to block telemarketing (junk) calls.
  28. * This program connects to a modem and listens for the caller ID
  29. * string that is sent between the first and second rings. It records
  30. * the string in file callerID.dat. It then reads strings from file
  31. * whitelist.dat and scans them against the caller ID string for a
  32. * match. If it finds a match it accepts the call. If a match is not
  33. * found, it reads strings from file blacklist.dat and scans them
  34. * against the caller ID string for a match. If it finds a match to
  35. * a string in the blacklist, it sends modem commands that terminate
  36. * the call.
  37. *
  38. * For more details, see the README2, README and UPDATES files.
  39. */
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <pthread.h>
  43. #include <stdlib.h>
  44. #include <unistd.h>
  45. #include <fcntl.h>
  46. #include <errno.h>
  47. #include <termios.h>
  48. #include <time.h>
  49. #include <signal.h>
  50.  
  51. #include "common.h"
  52.  
  53. #define DEBUG
  54.  
  55. #define DLE 0x10 // Data Link Escape to alternate functions
  56.  
  57. // Comment out the following define if you don't have an answering
  58. // machine attached to the same telephone line.
  59. #define ANS_MACHINE
  60.  
  61. // Comment out the following define if you don't want truncation of
  62. // records older than nine months from files blacklist.dat and
  63. // callerID.dat. Then remove truncate.c from the gcc compile command.
  64. #define DO_TRUNCATE
  65.  
  66. // Comment out the following define if the ATian modem does not
  67. // need a country code to operate with your country's phone system.
  68. // The ATian modem does not need a country code for the US phone
  69. // system. Therefore the following define is commented out by
  70. // default. If you are located in a country with non-US compatible
  71. // phone system, see the README files for country code details.
  72. //#define DO_COUNTRY_CODE
  73.  
  74. // The program optionally supports sending received call records as
  75. // network UDP datagrams to listening client programs. Uncomment the
  76. // following define to activate this feature and include radio.c
  77. // on the gcc compile line.
  78. //#define SEND_ON_NETWORK
  79.  
  80. #ifdef SEND_ON_NETWORK
  81. #include "radio.h"
  82. #endif
  83.  
  84. #define OPEN_PORT_BLOCKED 1
  85. #define OPEN_PORT_POLLED 0
  86.  
  87. // Default serial port specifier.
  88. char *serialPort = "/dev/ttyACM0";
  89. int fd; // the serial port
  90.  
  91. FILE *fpWh; // whitelist.dat file
  92. static struct termios options;
  93. static time_t pollTime, pollStartTime;
  94. static bool modemInitialized = FALSE;
  95. static bool inBlockedReadCall = FALSE;
  96. static int numRings = 0;
  97. pthread_t threadId;
  98. bool gotStarKey = FALSE;
  99.  
  100. static void cleanup( int signo );
  101.  
  102. // Prototypes
  103. int wait_for_response(int fd);
  104. int send_modem_command(int fd, char *command );
  105. int send_timed_modem_command(int fd, char *command, int numSecs );
  106. static bool check_blacklist( char *callstr );
  107. static bool write_blacklist( char *callstr );
  108. static bool check_whitelist( char * callstr );
  109. static void open_port( int mode );
  110. int init_modem(int fd);
  111. int tag_and_write_callerID_record( char *buffer, char tagChar);
  112. void* blockForStarKey(void *arg);
  113.  
  114. static char *copyright = "\n"
  115. "jcblock Copyright (C) 2015 Walter S. Heath\n"
  116. "This program comes with absolutely no warranty.\n"
  117. "This is free software, distributed under terms\n"
  118. "of the GNU Public License described at:\n"
  119. "<http://www.gnu.org/licenses/>.\n\n";
  120.  
  121. // Main function
  122. int main(int argc, char **argv)
  123. {
  124. int optChar;
  125.  
  126. // Set Ctrl-C and kill terminator signal catchers
  127. signal( SIGINT, cleanup );
  128. signal( SIGKILL, cleanup );
  129.  
  130. // See if a modem port argument was specified
  131. if( argc > 1 )
  132. {
  133. while( ( optChar = getopt( argc, argv, "p:h" ) ) != EOF )
  134. {
  135. switch( optChar )
  136. {
  137. case 'p':
  138. serialPort = optarg;
  139. break;
  140.  
  141. case 'h':
  142. default:
  143. fprintf( stderr, "Usage: jcblock [-p /dev/<portID>]\n" );
  144. fprintf( stderr, "Default modem port is: /dev/ttyACM0.\n" );
  145. fprintf( stderr, "For another port, use the -p option.\n" );
  146. _exit(-1);
  147. }
  148. }
  149. }
  150.  
  151. // Display copyright notice
  152. printf( "%s", copyright );
  153.  
  154. // Open or create a file to append caller ID strings to
  155. if( (fpCa = fopen( "./callerID.dat", "a+" ) ) == NULL )
  156. {
  157. printf("fopen() of callerID.dat failed\n");
  158. return(-1);
  159. }
  160.  
  161. // Open the whitelist file (for reading & writing)
  162. if( (fpWh = fopen( "./whitelist.dat", "r+" ) ) == NULL )
  163. {
  164. printf("fopen() of whitelist.dat failed. A whitelist is not required.\n" );
  165. }
  166.  
  167. // Open the blacklist file (for reading & writing)
  168. if( (fpBl = fopen( "./blacklist.dat", "r+" ) ) == NULL )
  169. {
  170. printf("fopen() of blacklist.dat failed. A blacklist must exist.\n" );
  171. return(-1);
  172. }
  173. // Open the modem port
  174. open_port( OPEN_PORT_BLOCKED );
  175.  
  176. // Initialize the modem
  177. if( init_modem(fd) != 0 )
  178. {
  179. printf("init_modem() failed\n");
  180. close(fd);
  181. fclose(fpCa);
  182. fclose(fpBl);
  183. fclose(fpWh);
  184. fflush(stdout);
  185. sync();
  186. return(0);
  187. }
  188.  
  189. modemInitialized = TRUE;
  190.  
  191. printf("Waiting for a call...\n");
  192.  
  193. // Wait for calls to come in...
  194. wait_for_response(fd);
  195.  
  196. close( fd );
  197. fclose(fpCa);
  198. fclose(fpBl);
  199. fclose(fpWh);
  200. fflush(stdout);
  201. sync();
  202. return(0);
  203. }
  204.  
  205. //
  206. // Initialize the modem.
  207. //
  208. int init_modem(int fd )
  209. {
  210. // Reset the modem
  211. #ifdef DEBUG
  212. printf("sending ATZ command...\n");
  213. #endif
  214. if( send_modem_command(fd, "ATZ\r") != 0 )
  215. {
  216. return(-1);
  217. }
  218.  
  219. sleep(1); // needed
  220.  
  221. #ifdef DO_COUNTRY_CODE
  222. // If operating in a non-US telephone system region,
  223. // insert an appropriate "AT+GCI=XX\r" modem command here.
  224. // See the README2 file for details (the code for the US
  225. // is B5).
  226. #ifdef DEBUG
  227. printf("sending country code command...\n");
  228. #endif
  229. if( send_modem_command(fd, "AT+GCI=B5\r") != 0 )
  230. {
  231. return(-1);
  232. }
  233. #endif
  234.  
  235. // Tell the modem to return caller ID.
  236. #ifdef DEBUG
  237. printf("sending caller ID command...\n");
  238. #endif
  239. if( send_modem_command(fd, "AT+VCID=1\r") != 0 )
  240. {
  241. return(-1);
  242. }
  243.  
  244. // Put modem in FAX service class mode
  245. #ifdef DEBUG
  246. printf("sending FAX mode command...\n");
  247. #endif
  248. send_modem_command(fd,"AT+FCLASS=2\r");
  249. return(0);
  250. }
  251.  
  252. //
  253. // Send command string to the modem
  254. //
  255. int send_modem_command(int fd, char *command )
  256. {
  257. char buffer[255]; // Input buffer
  258. char *bufptr; // Current char in buffer
  259. int nbytes; // Number of bytes read
  260. int tries; // Number of tries so far
  261.  
  262. // Send an AT command followed by a CR
  263. if( write(fd, command, strlen(command) ) != strlen(command) )
  264. {
  265. printf("send_modem_command: write() failed\n" );
  266. }
  267.  
  268. for( tries = 0; tries < 20; tries++ )
  269. {
  270. // Read characters into our string buffer until we get a CR or NL
  271. bufptr = buffer;
  272. inBlockedReadCall = TRUE;
  273. while( (nbytes = read(fd, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0 )
  274. {
  275. bufptr += nbytes;
  276. if( bufptr[-1] == '\n' || bufptr[-1] == '\r' )
  277. break;
  278. }
  279. inBlockedReadCall = FALSE;
  280.  
  281. // Null terminate the string and see if we got an OK response
  282. *bufptr = '\0';
  283.  
  284. // Scan for string "OK"
  285. if( strstr( buffer, "OK" ) != NULL )
  286. {
  287. #ifdef DEBUG
  288. printf("got command OK\n");
  289. #endif
  290. return( 0 );
  291. }
  292. }
  293. #ifdef DEBUG
  294. printf("did not get command OK\n");
  295. #endif
  296. return( -1 );
  297. }
  298.  
  299. //
  300. // Send command string to the modem. Wait 'numSecs' seconds
  301. // and return -- don't wait for a reply.
  302. //
  303. int send_timed_modem_command(int fd, char *command, int numSecs )
  304. {
  305. // Send an AT command ending with a CR
  306. if( write(fd, command, strlen(command) ) != strlen(command) )
  307. {
  308. printf("send_timed_modem_command: write() failed\n" );
  309. }
  310.  
  311. sleep(numSecs);
  312.  
  313. return(0);
  314. }
  315.  
  316. //
  317. // Wait (forever!) for calls...
  318. //
  319. int wait_for_response(fd)
  320. {
  321. char buffer[255]; // Input buffers
  322. char buffer2[255];
  323. char bufRing[10]; // RING input buffer
  324. int nbytes; // Number of bytes read
  325. int i, j, k;
  326. struct tm *tmPtr;
  327. time_t currentTime;
  328. int currentYear;
  329. char curYear[4];
  330. int err;
  331.  
  332. // Get a string of characters from the modem
  333. while(1)
  334. {
  335. // After a call, sleep a bit before commanding the modem
  336. usleep( 250000 );
  337. // Make sure the modem is on hook
  338. send_modem_command(fd, "ATH0\r"); // on hook
  339.  
  340. #ifdef DEBUG
  341. // Flush anything in stdout (needed if stdout is redirected to
  342. // a disk file).
  343. fflush(stdout); // flush C library buffers to kernel buffers
  344. sync(); // flush kernel buffers to disk
  345. #endif
  346.  
  347. // Block until at least one character is available.
  348. // After first character is received, continue reading
  349. // characters until inter-character timeout (VTIME)
  350. // occurs (or VMIN characters are received, which
  351. // shouldn't happen, since VMIN is set larger than
  352. // the longest string expected).
  353.  
  354. inBlockedReadCall = TRUE;
  355. nbytes = read( fd, buffer, 250 );
  356. inBlockedReadCall = FALSE;
  357.  
  358. // Occasionally a call comes in that has a caller ID
  359. // field that is too long! Example:
  360. // V4231749020000150314
  361. // Truncate it to the standard length (15 chars):
  362. // V42317490200001
  363. if( nbytes > 71 )
  364. {
  365. nbytes = 71;
  366. buffer[69] = '\r';
  367. buffer[70] = '\n';
  368. buffer[71] = 0;
  369. }
  370.  
  371.  
  372. // Replace '\n' and '\r' characters with '-' characters
  373. for( i = 0; i < nbytes; i++ )
  374. {
  375. if( ( buffer[i] == '\n' ) || ( buffer[i] == '\r' ) )
  376. {
  377. buffer[i] = '-';
  378. }
  379. }
  380.  
  381.  
  382.  
  383. if (strstr( buffer, "DATE" ) != NULL )
  384. {
  385. buffer[nbytes] = 0;
  386.  
  387. }
  388. else{
  389. // Put a '\n' at its end and null-terminate it
  390. buffer[nbytes] = '\n';
  391. buffer[nbytes + 1] = 0;
  392. }
  393.  
  394. // A string was received.
  395. // If its a 'RING' string, just count it.
  396. if( strstr( buffer, "RING" ) != NULL )
  397. {
  398. // On US-compatible phone systems caller ID data is
  399. // received after the first ring. In England caller ID
  400. // comes in BEFORE the first ring. Make code adjustments
  401. // as necessary for your phone system.
  402. numRings = 1; // count the ring
  403. continue;
  404. }
  405.  
  406. // Ignore any received string that isn't a caller ID string.
  407. // Caller ID strings always contain a 'DATE' field.
  408. if( strstr( buffer, "DATE" ) == NULL )
  409. {
  410. continue; // If 'DATE' is not present...
  411. }
  412.  
  413. // A caller ID string was constructed.
  414.  
  415. // The DATE field does not contain the year. Compute the year
  416. // and insert it.
  417. if( time( &currentTime ) == -1 )
  418. {
  419. printf("time() failed\n" );
  420. return -1;
  421. }
  422.  
  423. tmPtr = localtime( &currentTime );
  424. currentYear = tmPtr->tm_year -100; // years since 2000
  425.  
  426. if( sprintf( curYear, "%02d", currentYear ) != 2 )
  427. {
  428. printf( "sprintf() failed\n" );
  429. return -1;
  430. }
  431.  
  432. // Zero a new buffer with room for the year.
  433. for( i = 0; i < 100; i++ )
  434. {
  435. buffer2[i] = 0;
  436. }
  437.  
  438. // Fill it but leave room for the year
  439. for( i = 0; i < 13; i++ )
  440. {
  441. buffer2[i] = buffer[i];
  442. }
  443. for( i = 13; i < nbytes + 1; i++ )
  444. {
  445. buffer2[i + 2] = buffer[i];
  446. }
  447.  
  448. // Insert the year characters.
  449. buffer2[13] = curYear[0];
  450. buffer2[14] = curYear[1];
  451.  
  452. // If a whitelist.dat file was present, compare the
  453. // caller ID string to entries in the whitelist. If a match
  454. // is found, accept the call and bypass the blacklist check.
  455. if( fpWh != NULL )
  456. {
  457. if( check_whitelist( buffer2 ) == TRUE )
  458. {
  459. // Caller ID match was found so accept the call
  460.  
  461. // Tag and write the call record to the callerID.dat file.
  462. tag_and_write_callerID_record( buffer2, 'W');
  463. continue;
  464. }
  465. }
  466.  
  467. // Compare the caller ID string to entries in the blacklist. If
  468. // a match is found, answer (i.e., terminate) the call.
  469. if( check_blacklist( buffer2 ) == TRUE )
  470. {
  471. // Blacklist entry was found.
  472. //
  473. #ifdef DO_TRUNCATE
  474. // The following function truncates (removes old) entries
  475. // in data files -- if thirty days have elapsed since the
  476. // last time it truncated. Entries in callerID.dat are removed
  477. // if they are older than nine months. Entries in blacklist.dat
  478. // are removed if they have not been used to terminate a call
  479. // within the last nine months.
  480. // Note: it is not necessary for this function to run for the
  481. // main program to operate normally. You may remove it if you
  482. // don't want automatic file truncation. All of its code is in
  483. // truncate.c.
  484. truncate_records();
  485. #endif // end DO_TRUNCATE
  486.  
  487. // Tag and write the call record to the callerID.dat file.
  488. tag_and_write_callerID_record( buffer2, 'B');
  489. continue;
  490. }
  491. else // start of *-key check
  492. {
  493. // At this point the phone will ring until the call has been
  494. // answered or the caller hangs up (RING strings stop arriving).
  495. // Listen for a star key (*-key) press. If a press is detected
  496. // (within a timed window), build and add an entry to the
  497. // blacklist for this call.
  498.  
  499. // Get current time (seconds since Unix Epoch)
  500. if( (pollStartTime = time( NULL ) ) == -1 )
  501. {
  502. printf("time() failed(1)\n");
  503. continue;
  504. }
  505.  
  506. // Reinitialize the serial port for polling
  507. close(fd);
  508. usleep( 250000 ); // quarter second
  509. open_port( OPEN_PORT_POLLED );
  510.  
  511. // Now poll until 'RING' strings stop arriving.
  512. // Note: seven seconds is just longer than the
  513. // inter-ring time (six seconds).
  514. while( (pollTime = time( NULL )) < pollStartTime + 7 )
  515. {
  516. if( ( nbytes = read( fd, bufRing, 1 ) ) > 0 )
  517. {
  518. if(bufRing[0] == 'R')
  519. {
  520. pollStartTime = time( NULL );
  521. numRings++; // count the ring
  522. }
  523. }
  524. usleep( 100000 ); // 100 msec
  525. }
  526.  
  527. // Reinitialize the serial port blocked
  528. close(fd);
  529. usleep( 250000 ); // quarter second
  530. open_port( OPEN_PORT_BLOCKED );
  531. usleep( 250000 ); // quarter second
  532.  
  533. #ifdef ANS_MACHINE
  534. // If the call is answered before four rings, block for a
  535. // touchtone star (*) key press. Note that if an answering
  536. // machine is connected to the line, the *-key feature is only
  537. // available if the call is answered before the fourth ring.
  538. // This is necessary to avoid conflict with answering machines.
  539. // The answering machine *must be* set to answer on the fourth
  540. // or later ring. See the README and UPDATES files for further
  541. // details.
  542. if( numRings < 4 )
  543. {
  544. #else
  545. // If no answering machine is connected to the same telephone
  546. // line, the *-key feature is available for all calls answered
  547. // after one or more rings.
  548. if( TRUE)
  549. {
  550. #endif
  551. // The following modem commands will cause "clicks"
  552. // to be heard on the phone. They signal the listener
  553. // that the *-key detection window is open. The listner
  554. // may then press the *-key to have an entry for the
  555. // call automatically added to the blacklist. The
  556. // listener has ten (10) seconds to enter the *-key.
  557. // If the key is not pressed, some more "clicks" will
  558. // be heard indicating that the window has closed.
  559.  
  560. // Initialize the modem for Voice Mode operation
  561. #ifdef DEBUG
  562. printf("sending ATZ command...\n");
  563. #endif
  564. send_modem_command(fd, "ATZ\r");
  565. usleep( 250000 );
  566. #ifdef DEBUG
  567. printf("sending AT+FCLASS=8 command...\n");
  568. #endif
  569. send_modem_command(fd, "AT+FCLASS=8\r");
  570. usleep( 250000 );
  571.  
  572. // Initialize all voice parameters to their defult values
  573. #ifdef DEBUG
  574. printf("sending AT+VIP command...\n");
  575. #endif
  576. send_modem_command(fd, "AT+VIP\r");
  577. usleep( 250000 );
  578.  
  579. // Select the analog source mode that allows
  580. // touch-tone keys (e.g., the *-key) to be detected.
  581. #ifdef DEBUG
  582. printf("sending AT+VLS=1 command...\n");
  583. #endif
  584. send_modem_command(fd, "AT+VLS=1\r");
  585. usleep( 250000 );
  586.  
  587. // Get current time (seconds since Unix Epoch)
  588. if( (pollStartTime = time( NULL ) ) == -1 )
  589. {
  590. printf("time() failed(2)\n");
  591. continue;
  592. }
  593.  
  594. // For the modem to return a *-key detection, a blocked
  595. // read must be performed (don't know why!). Since we want
  596. // to time the wait period, we will perform the blocked
  597. // read in a thread. The main program (thread) may then
  598. // continue to time the detection window and cancel the
  599. // blocked read thread if no *-key is entered.
  600.  
  601. // Create a thread to block for a *-key press
  602. err = pthread_create(&(threadId), NULL,
  603. &blockForStarKey, NULL);
  604. if(err != 0) {
  605. printf("Can't create thread: %s", strerror(err));
  606. continue;
  607. }
  608.  
  609. // Wait for thread to signal *-key entered or timeout
  610. while( (pollTime = time( NULL )) < pollStartTime + 10 )
  611. {
  612. if( gotStarKey == TRUE ) {
  613. break; // break if *-key was detected
  614. }
  615.  
  616. sleep(1);
  617. }
  618.  
  619. // Cancel the thread
  620. err = pthread_cancel(threadId );
  621. if(err != 0) {
  622. printf("Can't cancel thread: %s", strerror(err));
  623. continue;
  624. }
  625.  
  626. // If *-key window poll time expired...
  627. if(pollTime >= pollStartTime + 10 )
  628. {
  629. // Tag and write the call record to the callerID.dat file.
  630. // (tag '-' just overwrites the existing same char).
  631. tag_and_write_callerID_record( buffer2, '-');
  632. }
  633.  
  634. // If a *-key entry was detected...
  635. else if(gotStarKey)
  636. {
  637. gotStarKey = FALSE;
  638. // Write a caller ID entry to the blacklist.dat.
  639. if( write_blacklist( buffer2 ) == TRUE)
  640. {
  641. // Tag and write call record to callerID.dat file.
  642. tag_and_write_callerID_record( buffer2, '*');
  643. }
  644. }
  645.  
  646. // Reinitialize the modem for caller ID operation
  647. init_modem( fd );
  648.  
  649. // Send on/off/on hook commands to terminate call
  650. // and send some "clicks" to the listener to indicate
  651. // that the *-key window has closed.
  652. usleep( 250000 ); // quarter second
  653. send_modem_command(fd, "ATH0\r"); // on hook
  654. usleep( 250000 ); // quarter second
  655. // Note: the off/on hook commands were removed to
  656. // solve the "off-hook-hang" bug (hopefully!)
  657. // (January 10, 2016, W. S. Heath).
  658. }
  659. } // end of *-key check
  660. } // end of while(1) loop
  661. }
  662.  
  663. //
  664. // Tag and write the call record to the callerID.dat file.
  665. // The first character in the record is used for the tag.
  666. // The tag indicates if the call record matched an entry in
  667. // the blacklist (tag 'B'), the whitelist (tag 'W'), was
  668. // put on the blacklist by pressing the star (*) key
  669. // (tag *) or was accepted (leaves the tag character as it
  670. // was: '-').
  671. //
  672. int tag_and_write_callerID_record( char *buffer, char tagChar)
  673. {
  674. // Overwrite the first character in the buffer with the tag.
  675. buffer[0] = tagChar;
  676.  
  677. #ifdef SEND_ON_NETWORK
  678. // Socket broadcast the buffer's contents.
  679. broadcast(buffer);
  680. #endif
  681.  
  682. char addStr[12] = "NAME = O--\n\0";
  683. strcat(buffer, addStr);
  684.  
  685.  
  686. // Close and re-open file 'callerID.dat' (in case it was
  687. // edited while the program was running!).
  688. fclose(fpCa);
  689. if( (fpCa = fopen( "./callerID.dat", "a+" ) ) == NULL )
  690. {
  691. printf("re-fopen() of callerID.dat failed\n");
  692. return(-1);
  693. }
  694. // Write the record to the file
  695. if( fputs( (const char *)buffer, fpCa ) == EOF )
  696. {
  697. printf("fputs( (const char *)buffer, fpCa ) failed\n");
  698. return(-1);
  699. }
  700.  
  701. // Flush the record to the file
  702. if( fflush(fpCa) == EOF )
  703. {
  704. printf("fflush(fpCa) failed\n");
  705. return(-1);
  706. }
  707. return(0);
  708. }
  709.  
  710. //
  711. // Compare strings in the 'whitelist.dat' file to fields in the
  712. // received caller ID string. If a whitelist string is present
  713. // (or an error occurred), return TRUE; otherwise return FALSE.
  714. //
  715. static bool check_whitelist( char *callstr )
  716. {
  717. char whitebuf[100];
  718. char whitebufsave[100];
  719. char *whitebufptr;
  720. char call_date[10];
  721. char *dateptr;
  722. char *strptr;
  723. long file_pos_last, file_pos_next;
  724.  
  725. // Close and re-open the whitelist.dat file. Note: this
  726. // seems to be necessary to be able to write records
  727. // back into the file. The write works the first time
  728. // after the file is opened but not subsequently! :-(
  729. // This also allows whitelist changes made while the
  730. // program is running to be recognized.
  731. //
  732. fclose( fpWh );
  733. // Re-open for reading and writing
  734. if( (fpWh = fopen( "./whitelist.dat", "r+" ) ) == NULL )
  735. {
  736. printf("Re-open of whitelist.dat file failed\n" );
  737. return(TRUE); // accept the call
  738. }
  739.  
  740. // Disable buffering for whitelist.dat writes
  741. setbuf( fpWh, NULL );
  742.  
  743. // Seek to beginning of list
  744. fseek( fpWh, 0, SEEK_SET );
  745.  
  746. // Save the file's current access location
  747. if( (file_pos_next = ftell( fpWh )) == -1L )
  748. {
  749. printf("ftell(fpWh) failed\n");
  750. return(TRUE); // accept the call
  751. }
  752.  
  753. // Read and process records from the file
  754. while( fgets( whitebuf, sizeof( whitebuf ), fpWh ) != NULL )
  755. {
  756. // Save the start location of the string just read and get
  757. // the location of the start of the next string in the file.
  758. file_pos_last = file_pos_next;
  759. file_pos_next = ftell( fpWh );
  760.  
  761. // Ignore lines that start with a '#' character (comment lines)
  762. if( whitebuf[0] == '#' )
  763. continue;
  764.  
  765. // Ignore lines containing just a '\n'
  766. if( whitebuf[0] == '\n' )
  767. {
  768. continue;
  769. }
  770.  
  771. // Ignore records that are too short (don't have room for the date)
  772. if( strlen( whitebuf ) < 26 )
  773. {
  774. printf("ERROR: whitelist.dat record is too short to hold date field.\n");
  775. printf(" record: %s", whitebuf);
  776. printf(" record is ignored (edit file and fix it).\n");
  777. continue;
  778. }
  779.  
  780. // Save the string (for writing back to the file later)
  781. strcpy( whitebufsave, whitebuf );
  782.  
  783. // Make sure a '?' char is present in the string
  784. if( ( strptr = strstr( whitebuf, "?" ) ) == NULL )
  785. {
  786. printf("ERROR: all whitelist.dat entry first fields *must be*\n");
  787. printf(" terminated with a \'?\' character!! Entry is:\n");
  788. printf(" %s", whitebuf);
  789. printf(" Entry was ignored!\n");
  790. continue;
  791. }
  792.  
  793. // Make sure the '?' character is within the first twenty characters
  794. if( (int)( strptr - whitebuf ) > 18 )
  795. {
  796. printf("ERROR: terminator '?' is not within first 20 characters\n" );
  797. printf(" %s", whitebuf);
  798. printf(" Entry was ignored!\n");
  799. continue;
  800. }
  801.  
  802. // Get a pointer to the search token in the string
  803. if( ( whitebufptr = strtok( whitebuf, "?" ) ) == NULL )
  804. {
  805. printf("whitebuf strtok() failed\n");
  806. return(TRUE); // accept the call
  807. }
  808.  
  809. // Scan the call string for the whitelist entry
  810. if( strstr( callstr, whitebufptr ) != NULL )
  811. {
  812. #ifdef DEBUG
  813. printf("whitelist entry matches: %s\n", whitebuf );
  814. #endif
  815. // Make sure the 'DATE = ' field is present
  816. if( (dateptr = strstr( callstr, "DATE = " ) ) == NULL )
  817. {
  818. printf( "DATE field not found in caller ID!\n" );
  819. return(TRUE); // accept the call
  820. }
  821.  
  822. // Get the current date from the caller ID string
  823. strncpy( call_date, &dateptr[7], 6 );
  824.  
  825. // Terminate the string
  826. call_date[6] = 0;
  827.  
  828. // Update the date in the whitebufsave record
  829. strncpy( &whitebufsave[19], call_date, 6 );
  830.  
  831. // Write the record back to the whitelist.dat file
  832. fseek( fpWh, file_pos_last, SEEK_SET );
  833. if( fputs( whitebufsave, fpWh ) == EOF )
  834. {
  835. printf("fputs(whitebufsave, fpWh) failed\n" );
  836. return(TRUE); // accept the call
  837. }
  838.  
  839. // Flush the string to the file
  840. if( fflush(fpWh) == EOF )
  841. {
  842. printf("fflush(fpWh) failed\n");
  843. return(TRUE); // accept the call
  844. }
  845.  
  846. // Force kernel file buffers to the disk
  847. // (probably not necessary)
  848. sync();
  849.  
  850. // A whitelist.dat entry matched, so return TRUE
  851. return(TRUE); // accept the call
  852. }
  853. } // end of while()
  854.  
  855. // No whitelist.dat entry matched, so return FALSE.
  856. return(FALSE);
  857. }
  858.  
  859. //
  860. // Compare strings in the 'blacklist.dat' file to fields in the
  861. // received caller ID string. If a blacklist string is present,
  862. // send commands to the modem to that will terminate the call...
  863. //
  864. static bool check_blacklist( char *callstr )
  865. {
  866. char blackbuf[100];
  867. char blackbufsave[100];
  868. char *blackbufptr;
  869. char call_date[10];
  870. char *dateptr;
  871. char *strptr;
  872. long file_pos_last, file_pos_next;
  873.  
  874. // Close and re-open the blacklist.dat file. Note: this
  875. // seems to be necessary to be able to write records
  876. // back into the file. The write works the first time
  877. // after the file is opened but not subsequently! :-(
  878. // This also allows blacklist changes made while the
  879. // program is running to be recognized.
  880. //
  881. fclose( fpBl );
  882. // Re-open for reading and writing
  883. if( (fpBl = fopen( "./blacklist.dat", "r+" ) ) == NULL )
  884. {
  885. printf("re-open fopen( blacklist) failed\n" );
  886. return(FALSE);
  887. }
  888.  
  889. // Disable buffering for blacklist.dat writes
  890. setbuf( fpBl, NULL );
  891.  
  892. // Seek to beginning of list
  893. fseek( fpBl, 0, SEEK_SET );
  894.  
  895. // Save the file's current access location
  896. if( (file_pos_next = ftell( fpBl )) == -1L )
  897. {
  898. printf("ftell(fpBl) failed\n");
  899. return(FALSE);
  900. }
  901.  
  902. // Read and process records from the file
  903. while( fgets( blackbuf, sizeof( blackbuf ), fpBl ) != NULL )
  904. {
  905. // Save the start location of the string just read and get
  906. // the location of the start of the next string in the file.
  907. file_pos_last = file_pos_next;
  908. file_pos_next = ftell( fpBl );
  909.  
  910. // Ignore lines that start with a '#' character (comment lines)
  911. if( blackbuf[0] == '#' )
  912. continue;
  913.  
  914. // Ignore lines containing just a '\n'
  915. if( blackbuf[0] == '\n' )
  916. {
  917. continue;
  918. }
  919.  
  920. // Ignore records that are too short (don't have room for the date)
  921. if( strlen( blackbuf ) < 26 )
  922. {
  923. printf("ERROR: blacklist.dat record is too short to hold date field.\n");
  924. printf(" record: %s", blackbuf );
  925. printf(" record is ignored (edit file and fix it).\n");
  926. continue;
  927. }
  928.  
  929. // Save the string (for writing back to the file later)
  930. strcpy( blackbufsave, blackbuf );
  931.  
  932. // Make sure a '?' char is present in the string
  933. if( ( strptr = strstr( blackbuf, "?" ) ) == NULL )
  934. {
  935. printf("ERROR: all blacklist.dat entry first fields *must be*\n");
  936. printf(" terminated with a \'?\' character!! Entry is:\n");
  937. printf(" %s", blackbuf);
  938. printf(" Entry was ignored!\n");
  939. continue;
  940. }
  941.  
  942. // Make sure the '?' character is within the first twenty characters
  943. // (could not be if the previous record was only partially written).
  944. if( (int)( strptr - blackbuf ) > 18 )
  945. {
  946. printf("ERROR: terminator '?' is not within first 20 characters\n" );
  947. printf(" %s", blackbuf);
  948. printf(" Entry was ignored!\n");
  949. continue;
  950. }
  951.  
  952. // Get a pointer to the search token in the string
  953. if( ( blackbufptr = strtok( blackbuf, "?" ) ) == NULL )
  954. {
  955. printf("blackbuf strtok() failed\n");
  956. return(FALSE);
  957. }
  958.  
  959. // Scan the call string for the blacklist entry
  960. if( strstr( callstr, blackbufptr ) != NULL )
  961. {
  962. #ifdef DEBUG
  963. printf("blacklist entry matches: %s\n", blackbuf );
  964. #endif
  965. sleep(1);
  966.  
  967. // Take the modem off hook
  968. send_modem_command(fd, "ATH1\r");
  969. usleep( 250000 );
  970.  
  971. // Send an ATA command. Don't wait for a response.
  972. // Wait five seconds and return. This command starts
  973. // with a CED tone (see UPDATES file for CED
  974. // definition). This simulates a FAX initial response.
  975. #ifdef DEBUG
  976. printf("sending CED tone ATA command\n");
  977. #endif
  978. send_timed_modem_command(fd, "ATA\r", 5);
  979.  
  980. usleep( 250000 ); // quarter second
  981. #ifdef DEBUG
  982. printf("sending on-hook command...\n");
  983. #endif
  984. send_modem_command(fd, "ATH0\r"); // on hook
  985. usleep( 250000 ); // quarter second
  986. init_modem(fd);
  987.  
  988. // Make sure the 'DATE = ' field is present
  989. if( (dateptr = strstr( callstr, "DATE = " ) ) == NULL )
  990. {
  991. printf( "DATE field not found in caller ID!\n" );
  992. return(FALSE);
  993. }
  994.  
  995. // Check the date field in blackbufsave. If it is not
  996. // '++++++' (not a permanent record), change it.
  997. if( strncmp( &blackbufsave[19], "++++++", 6 ) != 0 )
  998. {
  999. // Get the current date from the caller ID string
  1000. strncpy( call_date, &dateptr[7], 6 );
  1001.  
  1002. // Terminate the string
  1003. call_date[6] = 0;
  1004.  
  1005. // Update the date in the blackbufsave record
  1006. strncpy( &blackbufsave[19], call_date, 6 );
  1007.  
  1008. // Write the record back to the blacklist.dat file
  1009. fseek( fpBl, file_pos_last, SEEK_SET );
  1010. if( fputs( blackbufsave, fpBl ) == EOF )
  1011. {
  1012. printf("fputs(blackbufsave, fpBl) failed\n" );
  1013. return(FALSE);
  1014. }
  1015.  
  1016. // Flush the string to the file
  1017. if( fflush(fpBl) == EOF )
  1018. {
  1019. printf("fflush(fpBl) failed\n");
  1020. return(FALSE);
  1021. }
  1022.  
  1023. // Force kernel file buffers to the disk
  1024. // (probably not necessary)
  1025. sync();
  1026. }
  1027.  
  1028. // A blacklist.dat entry matched, so return TRUE
  1029. return(TRUE);
  1030. }
  1031. } // end of while()
  1032.  
  1033. /* A blacklist.dat entry was not matched, so return FALSE */
  1034. return(FALSE);
  1035. }
  1036.  
  1037. //
  1038. // Add a record to the blacklist.dat file.
  1039. // Extract the NAME or NMBR field from the callerID record and use it to
  1040. // construct a blacklist.dat entry. Then append it to the blacklist.dat file.
  1041. // Return TRUE if an entry was made; FALSE on an error.
  1042. // Note:
  1043. // If you enter blacklist.dat records manually with some editors (e.g., vi
  1044. // or gedit), the editor adds a '\n' character at the end of the file when
  1045. // the file is closed if you didn't! Some editors don't do this (e.g., emacs).
  1046. // The '\n' character can be in the last or second to last location since the
  1047. // stored length is always even.
  1048. // This function starts the record it constructs with a '\n'. It checks to see
  1049. // if your editor added a '\n' at the end of the file. If one is present, it
  1050. // writes the first character of the new record over it. If not, it appends
  1051. // the new record to the end of the file.
  1052. //
  1053. bool write_blacklist( char *callstr )
  1054. {
  1055. char blacklistEntry[80];
  1056. char readbuf[10];
  1057. char *srcDesc = "*-KEY ENTRY";
  1058. char *nameStr, *nmbrStr, *nmbrStrEnd;
  1059. int nameStrLength, nmbrStrLength;
  1060. int i;
  1061.  
  1062. // Close and re-open the blacklist.dat file. Note: this
  1063. // seems to be necessary to be able to write records
  1064. // back into the file. The write works the first time
  1065. // after the file is opened but not subsequently! :-(
  1066. // This also allows blacklist changes made while the
  1067. // program is running to be recognized.
  1068. //
  1069. fclose( fpBl );
  1070.  
  1071. // Re-open for reading and writing
  1072. if( (fpBl = fopen( "./blacklist.dat", "r+" ) ) == NULL )
  1073. {
  1074. printf("write_blacklist: re-open fopen() failed\n" );
  1075. return(FALSE);
  1076. }
  1077.  
  1078. // Disable buffering for blacklist.dat writes
  1079. setbuf( fpBl, NULL );
  1080.  
  1081. // Build a blacklist entry from the caller ID string.
  1082. // First fill the build array with ' ' chars.
  1083. for(i = 0; i < 80; i++)
  1084. {
  1085. blacklistEntry[i] = ' ';
  1086. }
  1087.  
  1088. // If the NAME field does not contain "Cell Phone", use it as the
  1089. // match string. If it does, use the call's number instead.
  1090. // Note: Cell phone calls generally contain a "generic" NAME
  1091. // field: "Cell Phone XX", where XX is the state ID (e.g., MI for
  1092. // Michigan). If that field was used in the blacklist record, all
  1093. // cell phone calls from that state would be blocked! So we use the
  1094. // call's number instead in those cases.
  1095. //
  1096. // For some caller ID strings, the NMBR and NAME fields are not the
  1097. // standard lengths (10 and 15, respectively). So we need to calculate
  1098. // their positions and lengths.
  1099. //
  1100. // Find the start of the "NAME = " string.
  1101. if( ( nameStr = strstr( callstr, "NAME = " ) ) == NULL )
  1102. {
  1103. printf( "write_blacklist: strstr(..., \"NAME = \" ) failed\n" );
  1104. return FALSE;
  1105. }
  1106.  
  1107. // Find the start of the "NMBR = " string.
  1108. if( ( nmbrStr = strstr( callstr, "NMBR = " ) ) == NULL )
  1109. {
  1110. printf( "write_blacklist: strstr(..., \"NMBR = \" ) failed\n" );
  1111. return FALSE;
  1112. }
  1113.  
  1114. // While here, find a pointer to the character after the NMBR
  1115. // string field (subtract 2 from nameStr for the "--" separater)
  1116. nmbrStrEnd = nameStr - 2;
  1117.  
  1118. // Find the start of the NAME string field.
  1119. nameStr += strlen( "NAME = " );
  1120.  
  1121. // Find the start of the NMBR string field.
  1122. nmbrStr += strlen( "NMBR = " );
  1123.  
  1124. // Find the length of the NAME string field (subtract 3 for the
  1125. // "--\n" at its end).
  1126. nameStrLength = strlen( nameStr ) - 3;
  1127.  
  1128. // Find the length of the NMBR string field.
  1129. nmbrStrLength = (int)(nmbrStrEnd - nmbrStr);
  1130.  
  1131. // Now build the new blacklist entry.
  1132. // Put a '\n' at the start of the string.
  1133. blacklistEntry[0] = '\n';
  1134.  
  1135. // See if the NAME field starts with "Cell Phone".
  1136. if( strstr( nameStr, "Cell Phone" ) != NULL )
  1137. {
  1138. // If it does, use the NMBR field instead.
  1139. strncpy( &blacklistEntry[1], &callstr[37], nmbrStrLength );
  1140. blacklistEntry[ nmbrStrLength + 1] = '?'; // Add the terminator
  1141. }
  1142. else
  1143. {
  1144. // Get the call NAME field from the caller ID.
  1145. strncpy( &blacklistEntry[1], nameStr, nameStrLength );
  1146. blacklistEntry[nameStrLength + 1] = '?'; // Add the terminator
  1147. }
  1148.  
  1149. // Get the date field from the caller ID.
  1150. strncpy( &blacklistEntry[20], &callstr[9], 6 );
  1151.  
  1152. // Add the source descriptor string ("KEY-* ENTRY").
  1153. strncpy( &blacklistEntry[34], srcDesc, strlen(srcDesc) + 1 );
  1154.  
  1155. // Read the last two characters in the file. If either is a '\n',
  1156. // seek to its position so the following write will overwrite it.
  1157. // If a '\n' is not found, seek to the end of the file.
  1158. fseek( fpBl, -2, SEEK_END );
  1159. if( fread( readbuf, 1, 2, fpBl ) != 2 )
  1160. {
  1161. printf("write_blacklist: fread() failed\n");
  1162. return FALSE;
  1163. }
  1164.  
  1165. if( readbuf[0] == '\n' )
  1166. {
  1167. fseek( fpBl, -2, SEEK_END );
  1168. }
  1169. else if( readbuf[1] == '\n' )
  1170. {
  1171. fseek( fpBl, -1, SEEK_END );
  1172. }
  1173. else
  1174. {
  1175. fseek( fpBl, 0, SEEK_END );
  1176. }
  1177.  
  1178. // Write the new record to the file.
  1179. if( fwrite( blacklistEntry, 1, strlen(blacklistEntry), fpBl ) !=
  1180. strlen( blacklistEntry ) )
  1181. {
  1182. printf("write_blacklist: fwrite() failed\n");
  1183. return FALSE;
  1184. }
  1185. return TRUE;
  1186. }
  1187.  
  1188. //
  1189. // Open the serial port.
  1190. //
  1191. static void open_port(int mode )
  1192. {
  1193. // Open modem device for reading and writing and not as the controlling
  1194. // tty (so the program does not get terminated if line noise sends CTRL-C).
  1195. //
  1196. if( ( fd = open( serialPort, O_RDWR | O_NOCTTY ) ) < 0 )
  1197. {
  1198. perror( serialPort );
  1199. _exit(-1);
  1200. }
  1201. fcntl(fd, F_SETFL, 0);
  1202.  
  1203. // Get the current options
  1204. tcgetattr(fd, &options);
  1205.  
  1206. // Set eight bits, no parity, one stop bit
  1207. options.c_cflag &= ~PARENB;
  1208. options.c_cflag &= ~CSTOPB;
  1209. options.c_cflag &= ~CSIZE;
  1210. options.c_cflag |= CS8;
  1211.  
  1212. // Set hardware flow control
  1213. options.c_cflag |= CRTSCTS;
  1214.  
  1215. // Set raw input
  1216. options.c_cflag |= (CLOCAL | CREAD);
  1217.  
  1218. options.c_lflag &= ~(ICANON | ECHO |ECHOE | ISIG);
  1219. options.c_oflag &=~OPOST;
  1220.  
  1221. if( mode == OPEN_PORT_BLOCKED )
  1222. {
  1223. // Block read until a character is available or inter-character
  1224. // time exceeds 1 unit (in 0.1sec units)
  1225. options.c_cc[VMIN] = 80;
  1226. options.c_cc[VTIME] = 1;
  1227. }
  1228. else // (mode == OPEN_PORT_POLLED)
  1229. {
  1230. // A read returns immediately with up to the number of bytes
  1231. // requested. It returns the number read; zero if none available
  1232. options.c_cc[VMIN] = 0;
  1233. options.c_cc[VTIME] = 0;
  1234. }
  1235.  
  1236. // Set the baud rate (caller ID is sent at 1200 baud)
  1237. cfsetispeed( &options, B1200 );
  1238. cfsetospeed( &options, B1200 );
  1239.  
  1240. // Set options
  1241. tcsetattr(fd, TCSANOW, &options);
  1242. }
  1243.  
  1244. //
  1245. // SIGINT (Ctrl-C) and SIGKILL signal handler
  1246. //
  1247. static void cleanup( int signo )
  1248. {
  1249. #ifdef DEBUG
  1250. printf("\nIn cleanup()...\n");
  1251. #endif
  1252.  
  1253. if( modemInitialized )
  1254. {
  1255. // Reset the modem
  1256. #ifdef DEBUG
  1257. printf("sending ATZ command...\n");
  1258. #endif
  1259. send_modem_command(fd, "ATZ\r");
  1260. }
  1261.  
  1262. // Close everything
  1263. close(fd);
  1264. fclose(fpCa);
  1265. fclose(fpBl);
  1266. fclose(fpWh);
  1267. fflush(stdout); // flush C library buffers to kernel buffers
  1268. sync(); // flush kernel buffers to disk
  1269.  
  1270. // If program is in a blocked read(...) call, use kill() to
  1271. // terminate program (happens when modem is not connected!).
  1272. if( inBlockedReadCall )
  1273. {
  1274. kill( 0, SIGKILL );
  1275. }
  1276.  
  1277. // Otherwise terminate normally
  1278. _exit(0);
  1279. }
  1280.  
  1281. //
  1282. // This is the method that runs in the created thread. It
  1283. // does a blocked read waiting for a touchtone key entry.
  1284. // If the entry is the *-key, it signals the main thread.
  1285. //
  1286. void* blockForStarKey(void *arg)
  1287. {
  1288. char testBuf[80];
  1289. int nbytes;
  1290. int k;
  1291. int err;
  1292. int oldType;
  1293.  
  1294. // The *-key string delivered by the modem:
  1295. static char starStr[] = { DLE, '/', DLE, '*', DLE, '~', '\0' };
  1296.  
  1297. // Set the cancel type
  1298. err = pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldType );
  1299. if( err != 0 ) {
  1300. printf("Can't set cancel type: %s\n", strerror(err));
  1301. }
  1302.  
  1303. while(TRUE)
  1304. {
  1305. if( ( nbytes = read( fd, testBuf, 80 ) ) > 0 )
  1306. {
  1307. #ifdef DEBUG
  1308. // Print the string received
  1309. printf("Got touchtone key string: ");
  1310. for(k = 0; k < nbytes; k++)
  1311. {
  1312. printf("0x%x ", testBuf[k] );
  1313. }
  1314. printf("\n");
  1315. #endif
  1316.  
  1317. // Terminate the string
  1318. testBuf[nbytes] = 0;
  1319.  
  1320. // Test for the *-key string
  1321. if( strstr( testBuf, starStr) != NULL )
  1322. {
  1323. #ifdef DEBUG
  1324. printf("Got *-key\n");
  1325. #endif
  1326. // Signal the main thread
  1327. gotStarKey = TRUE;
  1328. }
  1329. }
  1330. } // end of while(TRUE)
  1331. return NULL;
  1332. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement