home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / fax-3.2.1 / lib / libfax / send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-31  |  10.5 KB  |  444 lines

  1. /*
  2.   This file is part of the NetFax system.
  3.  
  4.   (c) Copyright 1989 by David M. Siegel and Sundar Narasimhan.
  5.       All rights reserved.
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation.
  10.  
  11.     This program is distributed in the hope that it will be useful, 
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <termios.h>
  23. #include <fcntl.h>
  24.  
  25. #include "log.h"
  26. #include "c2proto.h"
  27. #include "response.h"
  28. #include "swap.h"
  29. #include "read.h"
  30. #include "write.h"
  31. #include "tty.h"
  32. #include "send.h"
  33.  
  34. /*
  35.   Maximum amount of data to send to the modem in one write call:
  36. */
  37. #define SEND_CHUNK 1024
  38.  
  39. /*
  40.  * Dial a number: ATDT
  41.  *
  42.  * Return codes:
  43.  *     0    ok, number has been dialed.
  44.  *    -1    dial failed.
  45.  */
  46. static int dial(f, phonenum)
  47.      FaxModem *f;
  48.      char *phonenum;
  49.     log(L_NOTICE, "dialing: %s", phonenum);
  50.  
  51.     init_modem_response(f);
  52.  
  53.     if (fdprintf(f->fd, "ATDT%s\r", phonenum) < 0)
  54.       return (-1);
  55.  
  56.     if (get_modem_response(f, TIMEOUT_CONNECT) < 0)
  57.       return (-1);
  58.  
  59.     /*
  60.      * Save away the last numeric result as the result of this
  61.      * dial operation.  This makes it handy to check what
  62.      * happened on the last dial.
  63.      */
  64.     f->dialer_code = f->result;
  65.  
  66.     return (0);
  67. }
  68.  
  69. /*
  70.  * Sync and dial to a remote fax machine.
  71.  *
  72.  * Return codes:
  73.  *     0    connection to remote modem has been established.
  74.  *    -1    connection failed.
  75.  */
  76. int faxmodem_initiate_call(f, dialstring)
  77.      FaxModem *f;
  78.      char *dialstring;
  79. {
  80.     if (faxmodem_sync(f, 10) < 0)
  81.       return (-1);
  82.  
  83.     /* 
  84.      * Set phase C data bit order.
  85.      *
  86.      * The interfax firmware has a bug with received data in
  87.      * bitreverse=1 mode, so I will leave it in bor=0, and fudge the
  88.      * data in software.
  89.      */
  90.     if (faxmodem_bit_reverse(f, 0) < 0) {
  91.     log(L_NOTICE, "setting modem to bit reverse failed");
  92.     return (-1);
  93.     }
  94.  
  95.     /*
  96.      * Initiate the call to the remote modem.
  97.      */
  98.     if (dial(f, dialstring) < 0) {
  99.     log(L_NOTICE, "dial failed");
  100.     return (-1);
  101.     }
  102.  
  103.     return (0);
  104. }
  105.  
  106. /* 
  107.  * Begin or continue sending: +FDT
  108.  *
  109.  * Send the appropriate commands to the fax modem to start transmission
  110.  * of a page.  After sending the start commands, the modem will respond
  111.  * with a message that ends with CONNECT.  For now, we don't parse any
  112.  * of this message, we just look for the CONNECT.  In addition, the
  113.  * modem will signal to us that we should start sending G3 data by
  114.  * issuing an XON.  Thus, we force an XOFF.  THe subsequent writes
  115.  * to the modem will not start to drain until the XON occurs.  Note
  116.  * that this part of the protocol may change, according to the most
  117.  * recent documention.
  118.  *
  119.  * Set desired transmission params with +FDT=DF,VR,WD,LN
  120.  *   DF = Data Format :     0  [1-d huffman]
  121.  *   VR = Vertical Res :     1  [196 dpi (fine)]
  122.  *   WD = width :         0  [ 1728 pixels]
  123.  *   LN = page length :        2  [ Unlimited ]
  124.  *
  125.  * Return codes:
  126.  *     0    ok, proceed with sending data
  127.  *    -1    setup failed, not ready to send.
  128.  */
  129. static int start_xmit(f, df, vr, wd, ln)
  130.      FaxModem *f;
  131.      int df, vr, wd, ln;
  132. {
  133.     log(L_NOTICE, "setting xmit params: %d %d %d %d", df, vr, wd, ln);
  134.  
  135.     if (fdprintf(f->fd, "AT+FDT=%d,%d,%d,%d\r", df, vr, wd, ln) < 0)
  136.       return (-1);
  137.  
  138.     /*
  139.      * Wait for the output to the modem to complete, and then stop
  140.      * all further output (via an XOFF).  The modem will eventually
  141.      * respond with an XON, allowing the data transmission to begin.
  142.      */
  143.     tcdrain(f->fd);
  144.     ioctl(f->fd, TCXONC, TCOOFF);
  145.  
  146.     /*
  147.      * Make sure that we get the CONNECT message from the modem.
  148.      */
  149.     return (get_modem_response(f, 120));
  150. }
  151.  
  152. /*
  153.  * end of page, another page from same document is coming: +FET=0
  154.  * 
  155.  * This transmit page punctuation command is issued after a +FDT has
  156.  * been issued, and indicates that the current page has completed,
  157.  * and another page from the same document is about to be sent.
  158.  *
  159.  * Return codes:
  160.  *     0    all ok
  161.  *    -1    modem response error
  162.  */
  163. static int end_page(f)
  164.      FaxModem *f;
  165. {
  166.     log(L_NOTICE, "end of current page, another page will be sent");
  167.  
  168.     if (fdprintf(f->fd, "AT+FET=0\r") < 0)
  169.       return (-1);
  170.  
  171.     return (get_modem_response(f, TIMEOUT_END_PAGE));
  172. }
  173.  
  174. /*
  175.  * End of page and end of document: +FET=2
  176.  *
  177.  * This transmit page punctuation command is issued after a +FDT has
  178.  * been issued, and incates that the current page has completed,
  179.  * and the document is complete as well.
  180.  *
  181.  * Return codes:
  182.  *     0    all ok
  183.  *    -1    modem response error
  184.  */
  185. static int end_xmit(f)
  186.      FaxModem *f;
  187.     log(L_NOTICE, "end of current page, document is now complete");
  188.  
  189.     if (fdprintf(f->fd, "AT+FET=2\r") < 0)
  190.       return (-1);
  191.  
  192.     return (get_modem_response(f, TIMEOUT_END_XMIT));
  193. }
  194.  
  195. /*
  196.  * When sending data, it is possible to get a CAN message from
  197.  * the remote fax.  This message indicates that the send should
  198.  * be aborted.  The DLE ETX sequence should be sent to the DCE
  199.  * to ack the abort.
  200.  *
  201.  * Return codes:
  202.  *    0    all ok, proceed with sending
  203.  *     -1    send failed, check modem flags for more details
  204.  */
  205. static int process_send_response(f)
  206.      FaxModem *f;
  207. {
  208.     char resp[128];
  209.     int resp_len;
  210.     int i;
  211.  
  212.     /*
  213.      * We poll the fd for any input.  If none is available, all
  214.      * is fine.  If we get any input at all, it should be a CAN
  215.      * command, as that is all that the protocol allows.  However,
  216.      * to be safe we toss out any other junk that may come in.
  217.      */
  218.     switch (resp_len = pread(f->fd, resp, sizeof(resp))) {
  219.       case -1:
  220.     log(L_ERR, "send_page: poll failed: %m");
  221.     f->status = MODEM_STATUS_FAILED;
  222.     return (-1);
  223.       case 0:
  224.     return (0);
  225.       default:
  226.     log(L_INFO, "process_send_response: got \"%.*s\"", resp_len, resp);
  227.     for (i = 0; i < resp_len; i++) {
  228.         if ((resp[i] & 0x7f) == CAN) {
  229.         log(L_NOTICE, "remote fax has canceled transmission");
  230.         fdprintf(f->fd, "%c%c", DLE, ETX);
  231.         f->flags |= FAX_F_CANCELED;
  232.         return (-1);
  233.         }
  234.     }
  235.     return (0);
  236.     }
  237. }
  238.  
  239. /*
  240.  * Actually send a page.  We assume that we have dialed and connected
  241.  * to the remote fax machine, and that all is ready for starting
  242.  * the actually transmission.
  243.  *
  244.  * Return codes:
  245.  *     0    page has been succesfully sent
  246.  *    -1    send of page failed.
  247.  */
  248. static int send_page(f, fd, last_page)
  249.      FaxModem *f;
  250.      int fd;
  251.      int last_page;
  252. {
  253.     log(L_INFO, "sending g3 file");
  254.  
  255.     /*
  256.      * Setup things for transmission.
  257.      */
  258.     if (start_xmit(f, DF_1DHUFFMAN, VR_FINE, WD_1728, LN_UNLIMITED) < 0)
  259.       return (-1);
  260.  
  261.     /*
  262.      * Allow modem to send ^S to us.  Don't use flow control in the
  263.      * other direction, since we need to pass 8 bits.
  264.      */
  265.     tty_fc(f->fd, FC_OUTPUT_ON);
  266.  
  267.     /*
  268.      * Now send the page.
  269.      */
  270.     for (;;) {
  271.     unsigned char buf[SEND_CHUNK];
  272.     unsigned char buf_copy[SEND_CHUNK*2];
  273.     int nchars, ochars;
  274.     int i;
  275.  
  276.     /*
  277.      * Read in a hunk of data.
  278.      */
  279.     if ((nchars = read(fd, buf, sizeof(buf))) < 0) {
  280.         log(L_ERR, "send_page: read failed: %m");
  281.         tty_fc(f->fd, FC_BOTH_ON);
  282.         return (-1);
  283.     }
  284.     if (nchars == 0)
  285.       break;
  286.  
  287.     /*
  288.      * Reverse and stuff buffer characters:
  289.      */
  290.     ochars = 0;
  291.     for (i = 0; i < nchars; i++) {
  292.         buf_copy[ochars] = swap_bits(buf[i]);
  293.         if (buf_copy[ochars++] == DLE)
  294.           buf_copy[ochars++] = DLE;
  295.     }
  296.  
  297.     /*
  298.      * Write out the buffer to the modem.
  299.      */
  300.     if (nwrite(f->fd, (char *)buf_copy, ochars) != ochars) {
  301.         log(L_ERR, "send_page: write to modem failed: %m");
  302.         tty_fc(f->fd, FC_BOTH_ON);
  303.         return (-1);
  304.  
  305.     }
  306.  
  307.     /*
  308.      * Check for any response from the modem.
  309.      */
  310.     if (process_send_response(f) < 0) {
  311.         tty_fc(f->fd, FC_BOTH_ON);
  312.         return (-1);
  313.     }
  314.     }
  315.  
  316.     fdprintf(f->fd, "%c%c", DLE, ETX);
  317.  
  318.     tty_fc(f->fd, FC_BOTH_ON);
  319.  
  320.     if (get_modem_response(f, TIMEOUT_SEND_PAGE) < 0) {
  321.     log(L_NOTICE, "an error sending the file has occured");
  322.     return (-1);
  323.     } else
  324.       log(L_INFO, "send of file has completed");
  325.  
  326.     if (last_page)
  327.       return (end_xmit(f));
  328.     else
  329.       return (end_page(f));
  330. }
  331.  
  332. /*
  333.  * Send off a page.  If a retransmit is requested, try up to tries number
  334.  * of times.  If this is the last page of the transmission, set last_page
  335.  * to be true.  The G3 file to send is opened on the given fd.
  336.  *
  337.  * Return codes:
  338.  *    0    the page was successfully sent
  339.  *     -1    the send failed, see the modem flags for more details
  340.  */
  341. int faxmodem_send_page(f, fd, last_page, tries)
  342.      FaxModem *f;
  343.      int fd;
  344.      int last_page;
  345.      int tries;
  346. {
  347.     int i;
  348.  
  349.     for (i = 0; i < tries; i++) {
  350.     if (send_page(f, fd, last_page) < 0)
  351.       return (-1);
  352.  
  353.     /*
  354.      * If hangup was detected and not last page, then return
  355.      * with an error condition.
  356.      */
  357.     if (last_page) {
  358.         if (FAX_ISSET(f, FAX_F_FHNG) && (f->hangup_code != 0)) {
  359.         log(L_NOTICE, "hangup on last page: %d", f->hangup_code);
  360.         return (-1);
  361.         }
  362.     } else {
  363.         if (FAX_ISSET(f, FAX_F_FHNG)) {
  364.         log(L_NOTICE, "hangup code received while sending pages");
  365.         return (-1);
  366.         }
  367.     }
  368.  
  369.     /*
  370.      * Make sure we got a post page response.
  371.      */
  372.     if (!FAX_ISSET(f, FAX_F_FPTS)) {
  373.         log(L_NOTICE, "didn't receive post page response");
  374.         return (-1);
  375.     }
  376.  
  377.     switch (f->ppr_code) {
  378.       case PPR_MCF:
  379.         /* page good */
  380.         return (0);
  381.  
  382.       case PPR_RTN:
  383.       case PPR_RTP:
  384.         /* retrans requested for both these cases */
  385.         break;
  386.  
  387.       case PPR_PIN:
  388.       case PPR_PIP:
  389.         /* interrupt requested, what do we do here? assume failure */
  390.         return (-1);
  391.  
  392.       default:
  393.         log(L_ERR, "unknown ppr code received");
  394.         return (-1);
  395.     }
  396.     }
  397.     
  398.     f->flags |= FAX_F_RETRIES;
  399.  
  400.     log(L_NOTICE, "failed to successfully send page");
  401.  
  402.     return (-1);
  403. }
  404.  
  405. #ifdef DEBUG
  406. FaxModem fm;
  407.  
  408. int send_test(phone)
  409.      char *phone;
  410. {
  411.     int fd;
  412.  
  413.     log_set_level(LOG_INFO);
  414.     
  415.     if (faxmodem_open(&fm, "/dev/ttyb") < 0) {
  416.     fprintf(stderr, "open failed\n");
  417.     return (-1);
  418.     }
  419.  
  420.     if (faxmodem_initiate_call(&fm, phone) < 0 || !FAX_CONNECTED(&fm)) {
  421.     fprintf(stderr, "connection failed\n");
  422.     return (-1);
  423.     }
  424.  
  425.     if ((fd = open("test.g3.0", O_RDONLY)) < 0) {
  426.     fprintf(stderr, "can't open test file\n");
  427.     faxmodem_close(&fm);
  428.     return (-1);
  429.     }
  430.  
  431.     if (faxmodem_send_page(&fm, fd, TRUE, 3) < 0)
  432.       fprintf(stderr, "send failed\n");
  433.     else
  434.       fprintf(stderr, "send was successful\n");
  435.  
  436.     faxmodem_hangup(&fm);
  437.     faxmodem_close(&fm);
  438.  
  439.     return (0);
  440. }
  441. #endif DEBUG
  442.