/* psfax2.c */ /*---------------------------------------------------------------------------*/ /* This file is part of PSFax/2. */ /* */ /* Written By: Gary L. Hennigan */ /* */ /* This code can modified as much as you like provided you follow the */ /* guidelines as described in the file install.doc which you should have */ /* received with this file. If you did not please notify the author for a */ /* copy of this file via Internet email. The address is: */ /* ghenniga@NMSU.Edu */ /*---------------------------------------------------------------------------*/ #include #include #include #include #include "psfax2.h" /**Global variable(s). **/ char cGlobResp[MAXRESPLEN]; int main(int argc, char **argv) { /**Local functions. **/ void vMemCheck( void * ); void vCleanExit( char *, char *, int, int ); int iPageCount( char * ); ULONG ulOpenPort(char *, HFILE *); ULONG ulClosePort( HFILE ); int iPortGetSet( HFILE, DCBINFO * ); int iPortInit( HFILE, DCBINFO * ); int iModemInit( HFILE, DCBINFO * ); int iModemDial( HFILE, char *, DCBINFO *, int ); int iFaxInit( HFILE , DCBINFO *, int, int, int, int ); int iFaxSendPage( HFILE, DCBINFO *, FILE *, int ); int iFaxInterrupt( HFILE, DCBINFO * ); /**Local variables. **/ FILE *fp; int i1, iTemp, iPageCnt, iPageStat; char *cTemp, *cRecipPhone, *cSendPhone, *cRecipName, *cSendName; char *cPSFileName[MAXPSFILES], *cTempDir, *cFaxDir, *cFaxCnfFile; char cBuff[CCHMAXPATH], cBuff2[2*CCHMAXPATH], cCoverName[CCHMAXPATH]; char cPortID[6]; HFILE hTTY; DCBINFO dcbCom; /**Initialized local variables. **/ BOOL bRecipPhone=FALSE, bCover=FALSE, bSendPhone=FALSE; BOOL bRecipName=FALSE, bSendName=FALSE, bCQuote=FALSE; int iNumPSFiles=0, iWait=60, iRedial=5; /*-------------------------------End Declarations---------------------------*/ /**If no arguments were given print out help information. **/ if( argc <= 1 ) { printf("usage: psfax2 -p -c -s -S -r "); printf("[psfile]\n"); printf("where:\n(required)\n"); printf("\trnum - fax phone number of recipient\n"); printf("(optional cover sheet)\n"); printf("\t-c - use the predefined cover sheet\n"); printf("\tsnam - the sender's name\n"); printf("\tsnum - the sender's return fax phone number\n"); printf("\trname - the recipient's name\n"); printf("\t[psfile1] - the name of the postscript file "); printf("to send\n\n"); printf("example:\n psfax2 -p1-505-555-1234 -c -s \"jay "); printf("doe\" -S1-202-555-4321 -r \"jan doe\" psout.ps\n"); exit(0); } /**Determine the location of the configuration file. **/ cTemp = getenv("FAXPATH"); if(!cTemp) { printf("You must set the environment variable FAXPATH to point to"); printf(" the directory\nwhich contains the file psfax2.cnf\n"); exit(-1); } cFaxDir = (char *)malloc((strlen(cTemp)+2)*sizeof(char)); vMemCheck(cFaxDir); strcpy(cFaxDir,cTemp); if(cFaxDir[strlen(cTemp)] != '\\') { cFaxDir[strlen(cTemp)] = '\\'; cFaxDir[strlen(cTemp)+1] = '\000'; } cFaxCnfFile = (char *)malloc((strlen(cFaxDir)+12)*sizeof(char)); vMemCheck(cFaxCnfFile); strcpy(cFaxCnfFile,cFaxDir); strcat(cFaxCnfFile,"psfax2.cnf"); /**If it exists, open the configuration file. **/ fp=fopen(cFaxCnfFile,"r"); if(!fp) { printf("The configuration file \"%s\" could not be found!\n", cFaxCnfFile); exit(-1); } fscanf(fp, "%s", cPortID); strcpy(cCoverName,cFaxDir); fscanf(fp, "%s", &cCoverName[strlen(cCoverName)]); fscanf(fp, "%d", &iWait); fscanf(fp, "%d", &iRedial); fclose(fp); free(cFaxCnfFile); free(cFaxDir); /**Parse the command line. **/ for( i1=1; i1 < argc; i1++ ) { cTemp = strchr(argv[i1],'-'); if( cTemp ) { switch(cTemp[1]) { /** Recipient's phone number. **/ case 'p': if(cTemp[2]) { cRecipPhone = (char *)malloc((strlen(&cTemp[2])+1)* sizeof(char)); vMemCheck(cRecipPhone); strcpy(cRecipPhone,&cTemp[2]); } else { cRecipPhone = (char *)malloc((strlen(argv[i1+1])+1)* sizeof(char)); vMemCheck(cRecipPhone); strcpy(cRecipPhone,argv[i1+1]); i1++; } bRecipPhone=TRUE; break; /** Cover page flag. **/ case 'c': bCover = TRUE; break; /** Sender's phone number. **/ case 'S': if(cTemp[2]) { cSendPhone = (char *)malloc((strlen(&cTemp[2])+1)* sizeof(char)); vMemCheck(cSendPhone); strcpy(cSendPhone,&cTemp[2]); } else { cSendPhone = (char *)malloc((strlen(argv[i1+1])+1)* sizeof(char)); vMemCheck(cSendPhone); strcpy(cSendPhone,argv[i1+1]); i1++; } bSendPhone=TRUE; break; /** Recipient's name. **/ case 'r': if(cTemp[2]) { /** Multiple word and/or quoted name. **/ if(cTemp[2] == '\"'|| cTemp[2] == '\'') { iTemp = strlen(&cTemp[3]); if(cTemp[iTemp+2] == '\"' || cTemp[iTemp+2] == '\'') { cTemp[iTemp+2] = 0x00; iTemp--; bCQuote = TRUE; } cRecipName = (char *)malloc((iTemp+1)* sizeof(char)); vMemCheck(cRecipName); strcpy(cRecipName,&cTemp[3]); while(bCQuote == FALSE) { i1++; iTemp = strlen(argv[i1]); if(argv[i1][iTemp-1] == '\"' || argv[i1][iTemp-1] == '\'') { argv[i1][iTemp-1] = 0x00; bCQuote = TRUE; iTemp--; } cRecipName = (char *)realloc(cRecipName, (strlen(cRecipName)+ iTemp+2)* sizeof(char)); vMemCheck(cRecipName); strcat(cRecipName," "); strcat(cRecipName,argv[i1]); } } /** Single word name, no quotes. **/ else { cRecipName = (char *)malloc((strlen(&cTemp[2])+1)* sizeof(char)); vMemCheck(cRecipName); strcpy(cRecipName,&cTemp[2]); } } /** Space between paramater and argument. **/ else { /** Multiple word name. **/ if(argv[i1+1][0] == '\"' || argv[i1+1][0] == '\'') { cTemp = &argv[i1+1][1]; iTemp = strlen(cTemp); if(cTemp[iTemp-1] == '\"' || cTemp[iTemp-1] == '\'') { cTemp[iTemp-1] = 0x00; iTemp--; bCQuote = TRUE; } cRecipName = (char *)malloc((iTemp+1)* sizeof(char)); vMemCheck(cRecipName); strcpy(cRecipName,cTemp); while(bCQuote == FALSE) { i1++; iTemp = strlen(argv[i1+1]); if(argv[i1+1][iTemp-1] == '\"' || argv[i1+1][iTemp-1] == '\'') { argv[i1+1][iTemp-1] = 0x00; bCQuote = TRUE; iTemp--; } cRecipName = (char *)realloc(cRecipName, (strlen(cRecipName)+ iTemp+2)* sizeof(char)); vMemCheck(cRecipName); strcat(cRecipName," "); strcat(cRecipName,argv[i1+1]); } i1++; } /** Single word name. **/ else { i1++; cRecipName = (char *)malloc((strlen(argv[i1])+1)* sizeof(char)); vMemCheck(cRecipName); strcpy(cRecipName,argv[i1]); } } bCQuote=FALSE; bRecipName=TRUE; break; /* Recipient's Name */ /** Sender's name. **/ case 's': if(cTemp[2]) { /** Multiple word and/or quoted name. **/ if(cTemp[2] == '\"'|| cTemp[2] == '\'') { iTemp = strlen(&cTemp[3]); if(cTemp[iTemp+2] == '\"' || cTemp[iTemp+2] == '\'') { cTemp[iTemp+2] = 0x00; iTemp--; bCQuote = TRUE; } cSendName = (char *)malloc((iTemp+1)* sizeof(char)); vMemCheck(cSendName); strcpy(cSendName,&cTemp[3]); while(bCQuote == FALSE) { i1++; iTemp = strlen(argv[i1]); if(argv[i1][iTemp-1] == '\"' || argv[i1][iTemp-1] == '\'') { argv[i1][iTemp-1] = 0x00; bCQuote = TRUE; iTemp--; } cSendName = (char *)realloc(cSendName, (strlen(cSendName)+ iTemp+2)* sizeof(char)); vMemCheck(cSendName); strcat(cSendName," "); strcat(cSendName,argv[i1]); } } /** Single word name, no quotes. **/ else { cSendName = (char *)malloc((strlen(&cTemp[2])+1)* sizeof(char)); vMemCheck(cSendName); strcpy(cSendName,&cTemp[2]); } } /** Space between paramater and argument. **/ else { /** Multiple word name. **/ if(argv[i1+1][0] == '\"' || argv[i1+1][0] == '\'') { cTemp = &argv[i1+1][1]; iTemp = strlen(cTemp); if(cTemp[iTemp-1] == '\"' || cTemp[iTemp-1] == '\'') { cTemp[iTemp-1] = 0x00; iTemp--; bCQuote = TRUE; } cSendName = (char *)malloc((iTemp+1)* sizeof(char)); vMemCheck(cSendName); strcpy(cSendName,cTemp); while(bCQuote == FALSE) { i1++; iTemp = strlen(argv[i1+1]); if(argv[i1+1][iTemp-1] == '\"' || argv[i1+1][iTemp-1] == '\'') { argv[i1+1][iTemp-1] = 0x00; bCQuote = TRUE; iTemp--; } cSendName = (char *)realloc(cSendName, (strlen(cSendName)+ iTemp+2)* sizeof(char)); vMemCheck(cSendName); strcat(cSendName," "); strcat(cSendName,argv[i1+1]); } i1++; } /** Single word name. **/ else { i1++; cSendName = (char *)malloc((strlen(argv[i1])+1)* sizeof(char)); vMemCheck(cSendName); strcpy(cSendName,argv[i1]); } } bCQuote=FALSE; bSendName=TRUE; break; /* Sender Name */ default: printf("Unknown option %s!\n", argv[i1]); break; } /* end switch cTemp[1] */ } /* endif cTemp */ /** Anything without a "-" is considered a postscript file name. **/ else { if(iNumPSFiles < MAXPSFILES) { cPSFileName[iNumPSFiles] = (char *)malloc((strlen(argv[i1])+1)* sizeof(char)); strcpy(cPSFileName[iNumPSFiles],argv[i1]); } else { printf("Too many files! Maximum is %d\n", MAXPSFILES); exit(0); } iNumPSFiles++; } } /* end i1 for loop, command line parser */ /**Check that at least one file was specified. **/ if( iNumPSFiles <= 0 ) { puts("No files specified!"); exit(-1); } /**Check if the specified files exist. **/ i1 = 0; do { fp = fopen(cPSFileName[i1++],"r"); if( !fp ) { printf("The file specified, \"%s\", does not exist!\n", cPSFileName[i1-1]); exit(-1); } fclose(fp); } while(i1 < iNumPSFiles); /**Locate the TMP directory. **/ cTemp = getenv("TMP"); if(cTemp) { cTempDir = (char *)malloc((strlen(cTemp)+2)*sizeof(char)); vMemCheck(cTempDir); strcpy(cTempDir,cTemp); if(cTempDir[strlen(cTempDir)-1] != '\\') strcat(cTempDir,"\\"); /** Translate to lower case. For some reason the DosDelete function **/ /** doesn't like uppercase? **/ for(i1=0; i1 < strlen(cTempDir); i1++) { if(!islower(cTempDir[i1])) cTempDir[i1] = tolower(cTempDir[i1]); } } else { cTempDir = (char *)malloc(3*sizeof(char)); vMemCheck(cTempDir); strcpy(cTempDir,"\\"); } /**Clean out any old fax files. **/ puts("Cleaning out old files..."); strcpy(cBuff,cTempDir); strcat(cBuff,"g3cfax.1"); DosDelete(cBuff); strcpy(cBuff,cTempDir); strcat(cBuff,"g3fax.1"); i1 = 2; while(DosDelete(cBuff) == 0) { sprintf(cBuff,"%sg3fax.%d",cTempDir,i1); i1++; } /**Convert the PostScript documents to G3 fax files. **/ puts("Converting documents..."); strcpy(cBuff,cTempDir); strcat(cBuff,"g3fax.%%d"); sprintf(cBuff2, "gs.exe -dNOPAUSE -sDEVICE=dfaxhigh -q -sOutputFile=%s ", cBuff); for(i1=0; i1 < iNumPSFiles; i1++ ) { strcat(cBuff2,cPSFileName[i1]); fp = popen(cBuff2, "w"); fprintf(fp, "quit\n"); pclose(fp); } /**Get a page count. **/ iPageCnt = iPageCount(cTempDir); /**If it was specified, generate a coverpage. **/ if( bCover == TRUE ) { fp = fopen("mcover.ps","w"); fprintf(fp, "/recipnum (%s) def\n", cRecipPhone); if(bRecipName == TRUE) fprintf(fp, "/recipient (%s) def\n", cRecipName); if(bSendName == TRUE) fprintf(fp, "/sender (%s) def\n", cSendName); if(bSendPhone == TRUE) fprintf(fp, "/returnfaxnum (%s) def\n", cSendPhone); fprintf(fp, "/pages (%d) def\n", iPageCnt+1); fprintf(fp,"("); for(i1=0; i1 < strlen(cCoverName); i1++) { if(cCoverName[i1] == '\\') { fprintf(fp, "\\"); } fprintf(fp, "%c", cCoverName[i1]); } fprintf(fp, ")"); fprintf(fp, " run\n"); fclose(fp); /** Create the Group 3 coverpage. **/ strcpy(cBuff,cTempDir); strcat(cBuff,"g3cfax.%%d"); sprintf(cBuff2, "gs.exe -dNOPAUSE -sDEVICE=dfaxhigh -q -sOutputFile=%s mcover.ps", cBuff); fp = popen(cBuff2,"w"); fprintf(fp, "quit\n"); pclose(fp); DosDelete("mcover.ps"); } printf("\n"); /* To make room on the screen. */ /**Open the port. **/ puts("Initializing port and modem..."); while(ulOpenPort(cPortID, &hTTY) != 0) { printf("Port %s is invalid or being used by another process\n", cPortID); printf("Enter 'e' to exit or 'r' to retry: "); scanf("%s",cBuff); if(cBuff[0] == 'e' || cBuff[0] == 'E') vCleanExit(cTempDir,cBuff,iPageCnt,-1); } /**Get the current port characteristics. **/ if(iPortGetSet(hTTY, &dcbCom) != 0) { puts("Could not get port settings!"); vCleanExit(cTempDir,cBuff,iPageCnt,-1); } /**Initialize the port. **/ if(iPortInit(hTTY, &dcbCom) != 0) { puts("Setting port characteristics failed!"); vCleanExit(cTempDir,cBuff,iPageCnt,-1); } /**Initialize the modem. **/ if(iModemInit(hTTY, &dcbCom) != 0) { puts("Modem initialization timed out!"); vCleanExit(cTempDir,cBuff,iPageCnt,-1); } /**Dial the modem. **/ printf("Dialing %s...\n", cRecipPhone); do { iTemp = iModemDial(hTTY, cRecipPhone, &dcbCom, iWait); switch(iTemp) { case DIAL_BUSY: puts("Phone busy!"); break; case DIAL_NOANSWER: printf("No answer from remote! "); printf("Enter 'r' to retry, 'e' to exit: "); scanf("%s",cBuff); if(cBuff[0] == 'e' || cBuff[0] == 'E') vCleanExit(cTempDir,cBuff,iPageCnt,-1); break; case DIAL_NOCARRIER: printf("Could not detect carrier!"); printf(" Enter 'r' to retry, 'e' to exit: "); scanf("%s",cBuff); if(cBuff[0] == 'e' || cBuff[0] == 'E') vCleanExit(cTempDir,cBuff,iPageCnt,-1); break; case DIAL_NODIALTONE: printf("No dial tone! Enter 'r' to retry, 'e' to exit: "); scanf("%s",cBuff); if(cBuff[0] == 'e' || cBuff[0] == 'E') vCleanExit(cTempDir,cBuff,iPageCnt,-1); break; case DIAL_UNKNOWN: printf("Unexpected or unknown response! "); printf("Enter 'r' to retry, 'e' to exit: "); scanf("%s",cBuff); if(cBuff[0] == 'e' || cBuff[0] == 'E') vCleanExit(cTempDir,cBuff,iPageCnt,-1); break; } if( iTemp != 0 ) { printf("Waiting %d seconds to redial...",iRedial); sleep(iRedial); printf("\n"); } } while(iTemp != 0); /**Initiate fax connection. */ if(iFaxInit(hTTY, &dcbCom, DF_1DHUFFMAN, VR_FINE, WD_1728, LN_UNLIMITED) != 0) { puts("Could not init fax data transmission for the page!"); vCleanExit(cTempDir, cBuff, iPageCnt, -1); } /**Begin sending the document(s). **/ iTemp = PEND_ANOTHER; if(bCover == TRUE) { puts("Sending cover page..."); if(iPageCnt <= 0) iTemp = PEND_ENDTRAN; strcpy(cBuff,cTempDir); strcat(cBuff,"g3cfax.1"); fp = fopen(cBuff,"r"); if(!fp) { puts("G3 cover page could not be found..."); vCleanExit(cTempDir, cBuff, iPageCnt, -1); } do { iPageStat = iFaxSendPage(hTTY, &dcbCom, fp, iTemp); switch( iPageStat ) { case PPR_PPR: printf("There were partial page errors during the cover page"); printf(" transmission! Continuing...\n"); iPageStat = 0; break; case PPR_MCF: iPageStat = 0; break; case PPR_RTN: printf("Remote requested retransmission! Retransmitting...\n"); rewind(fp); iPageStat = 1; break; case PPR_RTP: printf("Page good but remote wants a retransmission? "); printf("Retransmitting...\n"); rewind(fp); iPageStat = 1; break; case PPR_PIN: printf("Page bad and remote requests an interrupt!\n"); iPageStat = -1; break; case PPR_PIP: printf("Page good but remote requests an interrupt!\n"); iFaxInterrupt(hTTY, &dcbCom); vCleanExit(cTempDir, cBuff, iPageCnt, -1); break; default: puts("Cancelling transmission!"); iFaxInterrupt(hTTY, &dcbCom); vCleanExit(cTempDir, cBuff, iPageCnt, -1); break; } } while(iPageStat == 1); fclose(fp); } /**Send the pages of the document. **/ for(i1=0; i1 < iPageCnt; i1++) { /** Send the page. **/ printf("Sending page %d...\n",i1+1); if(i1 == iPageCnt-1) iTemp = PEND_ENDTRAN; sprintf(cBuff, "%sg3fax.%d", cTempDir, i1+1); fp = fopen(cBuff,"r"); if(!fp) { printf("G3 page %d could not be opened!\n", i1); vCleanExit(cTempDir, cBuff, iPageCnt, -1); } do { iPageStat = iFaxSendPage(hTTY, &dcbCom, fp, iTemp); switch( iPageStat ) { case PPR_PPR: printf("There were partial page errors during the page"); printf(" transmission! Continuing...\n"); iPageStat = 0; break; case PPR_MCF: iPageStat = 0; break; case PPR_RTN: printf("Remote requested retransmission! Retransmitting...\n"); rewind(fp); iPageStat = 1; break; case PPR_RTP: printf("Page good but remote wants a retransmission? "); printf("Retransmitting...\n"); rewind(fp); iPageStat = 1; break; case PPR_PIN: printf("Page bad and remote requests an interrupt!\n"); iPageStat = -1; break; case PPR_PIP: printf("Page good but remote requests an interrupt!\n"); iPageStat = -1; break; default: puts("Cancelling transmission!"); iPageStat = -1; break; } } while(iPageStat == 1); fclose(fp); /** If an interrupt was requested, Grant It. **/ if(iPageStat == -1) { iFaxInterrupt(hTTY, &dcbCom); vCleanExit(cTempDir, cBuff, iPageCnt, -1); } } /**Close the port, clean up and exit. **/ ulClosePort(hTTY); vCleanExit(cTempDir, cBuff, iPageCnt, 0); return 0; } /****************************************************************************/ /************************Memory check function*******************************/ /****************************************************************************/ void vMemCheck( void *ptr ) { if( !ptr ) { puts("Not enough memory!"); exit(-1); } } /****************************************************************************/ /*************************Count the number of********************************/ /*****************************pages to fax***********************************/ /****************************************************************************/ int iPageCount(CHAR *cTempDir) { FILE *fp; char cBuff[CCHMAXPATH]; int iCnt=0; /*-----------------------------End Declarations----------------------------*/ sprintf(cBuff, "%sg3fax.1", cTempDir); fp = fopen(cBuff,"r"); while( fp ) { iCnt++; fclose(fp); sprintf(cBuff,"%sg3fax.%d", cTempDir, iCnt+1); fp = fopen(cBuff,"r"); } return iCnt; } /****************************************************************************/ /**************************Clean up any files********************************/ /****************************and exit PSFax2*********************************/ /****************************************************************************/ void vCleanExit(char *cTempDir, char *cBuff, int iPageCnt, int iError) { int i1; /*-----------------------------End Declarations----------------------------*/ /**Clean out the fax files. **/ if(iError != 0) printf("Cleaning up and exiting on error condition %d\n", iError); else puts("Cleaning up and exiting..."); strcpy(cBuff,cTempDir); strcat(cBuff,"g3cfax.1"); DosDelete(cBuff); strcpy(cBuff,cTempDir); strcat(cBuff,"g3fax.1"); for(i1=1; i1 <= iPageCnt; i1++) { sprintf(cBuff,"%sg3fax.%d",cTempDir,i1); DosDelete(cBuff); } exit(iError); }