/* $Id: capifaxrcvd.c,v 1.2 1998/10/23 12:50:48 fritz Exp $ * * A FAX receive daemon for CAPI. * This stuff is based heavily on AVM's CAPI-adk for linux. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: capifaxrcvd.c,v $ * Revision 1.2 1998/10/23 12:50:48 fritz * Added RCS keywords and GPL notice. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "c20msg.h" #include "capi.h" #include "connect.h" #include "contr.h" #include "data.h" #include "id.h" #include "init.h" #include "fax.h" extern char *stationID; extern char *headLine; static char *CalledPartyNumber = NULL; static char *RcvDir = NULL; static char *notifyCmd = NULL; static char RcvName[1024]; static ConnectionID Slot; #define B1PROTOCOL 4 #define B2PROTOCOL 4 #define B3PROTOCOL 4 #define QueueSize 8 typedef struct __DataElement { char DATA[SendBlockSize]; unsigned short DATA_LENGTH; unsigned SENT; } _DataElement; typedef struct __DataQueue { _DataElement Element[QueueSize]; unsigned Head; unsigned Tail; unsigned Fill; } _DataQueue; _DataQueue Queue; static unsigned FileReceive = FALSE; /* signals if transfer is in progress */ static FILE *f; static int reason; static int reason_b3; static int rres; static int rpages; static char rid[50]; /* * MainDataAvailable: signals received data blocks * This function is called after a DATA_B3_INDication is received. The flag * DiscardData tells CAPI to free the memora area directly after the return * of this function when set to TRUE (1) which is the preset. When the flag * is set to FALSE (0) the data area MUST be freed later with ReleaseData. * The datahandle identifies the memory area. When reaching 7 unconfirmed * blocks, no more incoming data will be signaled until freeing at least * one block. */ static void MainDataAvailable(ConnectionID Connection, void *Data, unsigned short DataLength, unsigned short DataHandle, int *DiscardData) { assert (Connection != INVALID_CONNECTION_ID); if ((FileReceive) && (f != NULL)) fwrite(Data, 1, DataLength, f); *DiscardData = TRUE; } /* * MainStateChange: signals a state change on both B-channels (connected, * disconnected). Whenever a channel changes his state this function is called */ static void MainStateChange(ConnectionID Connection, ConnectionState State) { faxNCPI_t *faxNCPI; assert (Connection != INVALID_CONNECTION_ID); if (State == Disconnected) { unsigned short r3 = GetB3Reason(Connection); unsigned short r = GetReason(Connection); Slot = INVALID_CONNECTION_ID; reason = r; reason_b3 = r3; #if 0 printf("Disconnected.\n"); printf(" Reason : %04x %s\n", r, Decode_Info(r)); printf(" Reason-B3 : %04x %s\n", r3, Decode_Info(r3)); #endif if ((faxNCPI = GetFaxNCPI(Connection))) { strcpy(rid, faxNCPI->id); rres = faxNCPI->resolution; rpages = faxNCPI->pages; #if 0 printf(" Remote Station ID : %s\n", faxNCPI->id); printf(" Transfer-Rate : %d bps\n", faxNCPI->rate); printf(" Resolution : %s\n", faxNCPI->resolution ? "high" : "low"); printf(" Number of Pages : %d\n", faxNCPI->pages); #endif } } } /* * MainIncomingCall: signals an incoming call * This function will be executed if a CONNECT_INDication appears to * inform the user. */ static void MainIncomingCall(ConnectionID Connection, char *CallingPartyNumber) { B3_PROTO_FAXG3 B3conf; assert (Connection != INVALID_CONNECTION_ID); syslog(LOG_INFO, "Incoming Call from %s\n", CallingPartyNumber); SetupB3Config(&B3conf, FAX_SFF_FORMAT); if (CalledPartyNumber && strlen(CalledPartyNumber)) { syslog(LOG_INFO, "Called #: %s\n", GetCalledPartyNumber(Connection)); if (strcmp(GetCalledPartyNumber(Connection), CalledPartyNumber)) { AnswerCall(Connection, IGNORE, 4, 4, 4, (_cstruct)&B3conf); syslog(LOG_INFO, "Call from %s ignored\n", CallingPartyNumber); return; } } if (Slot == INVALID_CONNECTION_ID) { Slot = Connection; sprintf(RcvName, "rc-%s-%08lx", CallingPartyNumber, time(NULL)); f = fopen(RcvName, "wb"); if (f != NULL) { FileReceive = TRUE; syslog(LOG_INFO, "Call from %s accepted\n", CallingPartyNumber); AnswerCall(Connection, ACCEPT, 4, 4, 4, (_cstruct)&B3conf); chmod(RcvName, 0600); return; } } AnswerCall(Connection, REJECT, 4, 4, 4, (_cstruct)&B3conf); syslog(LOG_INFO, "Call from %s rejected\n", CallingPartyNumber); } void InitQueue(void) { unsigned x; for (x=0; x': case '<': case '|': case '?': case '*': case '\'': case '"': case '`': if (newname[l-1] != '-' ) newname[l++] = '-'; break; default: newname[l++] = rid[i]; } } newname[l] = '\0'; rename(RcvName, newname); chmod(newname, 0640); syslog(LOG_INFO, "Received a FAX\n"); if (notifyCmd) { sprintf(RcvName, "%s %s", notifyCmd, newname); system(RcvName); } } else remove(RcvName); return ret; } void usage(void) { fprintf(stderr, "usage: capifaxrcvd [-i stationID] [-h header] [-l listenNumber] [-n notifyCmd] rcvDirectory\n"); exit(1); } int main(int argc, char **argv) { int numController; int BChannels, Contr; int c; while ((c = getopt(argc, argv, "l:i:h:n:")) != EOF) { switch (c) { case 'l': CalledPartyNumber = strdup(optarg); break; case 'i': stationID = strdup(optarg); break; case 'h': headLine = strdup(optarg); break; case 'n': notifyCmd = strdup(optarg); break; case '?': usage(); } } if (argc < optind + 1) usage(); RcvDir = argv[optind]; if (chdir(RcvDir) != 0) { perror(RcvDir); return -1; } Slot = INVALID_CONNECTION_ID; MainStateChange_p = MainStateChange; MainDataAvailable_p = MainDataAvailable; MainIncomingCall_p = MainIncomingCall; if (!RegisterCAPI()) return -1; atexit (ReleaseCAPI); InitConnectionIDHandling(); if (!(numController = GetNumController())) { fprintf(stderr, "No CAPI controllers available\n"); return -2; } BChannels = 0; for (Contr=1; Contr<=numController; Contr++) BChannels += GetNumOfSupportedBChannels(Contr); if (!BChannels) { fprintf(stderr, "No B-Channels available\n"); return -3; } switch (fork()) { case 0: openlog("capifaxrcvd", LOG_PID, LOG_DAEMON); close(0); close(1); close(2); while (1) ReceiveFax(); if ((Slot != INVALID_CONNECTION_ID) && (GetState(Slot) != Disconnected) && (GetState(Slot) != D_DisconnectPending)) Disconnect(Slot); break; case -1: perror("fork"); exit(errno); break; } return 0; }