From 7c4423720a9a92c5e1d4333bf21842ad12d47fd2 Mon Sep 17 00:00:00 2001 From: gernot Date: Sun, 25 May 2003 13:38:30 +0000 Subject: [PATCH] - support reception of color fax documents git-svn-id: https://svn.ibp.de/svn/capisuite/trunk/capisuite@120 4ebea2bb-67d4-0310-8558-a5799e421b66 --- docs/manual-de.docbook | 43 +++++++++++++++++++++++++---- docs/manual.docbook | 29 ++++++++++++++++++- scripts/cs_helpers.pyin | 35 ++++++++++++++++++++--- scripts/incoming.py | 27 +++++++++++------- src/application/capisuitemodule.cpp | 41 ++++++++++++++++++++------- src/backend/connection.cpp | 13 +++++---- src/backend/connection.h | 7 +++-- 7 files changed, 157 insertions(+), 38 deletions(-) diff --git a/docs/manual-de.docbook b/docs/manual-de.docbook index e5db850..7012e62 100644 --- a/docs/manual-de.docbook +++ b/docs/manual-de.docbook @@ -230,13 +230,25 @@ aktueller Ghostscript mit cfax-Patch Aktuelle Ghostscript-Versionen enthalten ein Device, um die - oben erwähnten SFF-Dateien zu erstellen. Wenn Sie eine ältere Version haben, - brauchen Sie den Patch von - . Um zu - prüfen, ob Ihre GhostScript-Version diesen Patch bereits hat, rufen Sie bitte - gs --help auf und sehen nach, ob Sie das Device + oben erwähnten SFF-Dateien zu erstellen. Wenn Sie eine ältere Version haben, + brauchen Sie den Patch von + . Um zu + prüfen, ob Ihre GhostScript-Version diesen Patch bereits hat, rufen Sie bitte + auf und sehen nach, ob Sie das Device cfax in der langen Liste der unterstützten Devices - finden können. + finden können. + + + + jpeg2ps + Das jpeg2ps-Kommando wird zur Konvertierung von Farbfaxen in + das PostScript-Format für die Mailzustellung benötigt. Sie brauchen es nicht, wenn Sie keine + Farbfaxe empfangen wollen. Unglücklicherweise gibt es wegen eines Treiberfehlers momentan keine + Möglichkeit, den Empfang von Faxdokumenten bei AVM-ISDN-Karten komplett zu deaktivieren. Wenn Ihnen + also jemand ein Farbfax schicken sollte (was nach meiner Erfahrung nur sehr selten vorkommt), dann + bekommen Sie eine Fehlermeldung per Mail, wenn Sie dieses Programm nicht installiert haben. + Wenn Ihre Linux-Distribution dieses Paket nicht enthält, können Sie es von + herunterladen. @@ -1660,6 +1672,9 @@ is not present, current time as returned by localtime() is used. einige kleine Tools gefunden, die Peter Schäfer geschrieben hat und die wir hier verwenden werden. + CapiSuite kann auch Farbfaxe empfangen, welche in einem speziellen Dateiformat abgelegt + werden, das ich CFF genannt habe. + Erzeugen eines SFF In aktuellen Ghostscript-Versionen gibt es einen Patch von Peter, um SF-Dateien zu erstellen. Um zu prüfen, ob Ihr Ghostscript das schon unterstützt, @@ -1697,7 +1712,23 @@ is not present, current time as returned by localtime() is used. konvertieren können. + Farbfaxe - das CFF-Format + Es gibt eine Erweiterung zum Fax-Standard, die die Übertragung von farbigen + Dokumenten erlaubt. Sie wird nur selten benutzt, aber da einige User sie trotzdem + benötigten, habe ich den Empfang solcher Dokumente mittlerweile in CapiSuite realisiert. + + Das CFF-Format (ich weiß nicht sicher, ob das ein offizieller Name für das Format ist) + scheint eine JPEG-Datei mit spezieller Kodierung zu sein. Die meisten Programme, die + JPEG-Dateien unterstützen, sollten CFF-Dateien ebenfalls öffnen können. Eventuell müssen + Sie die Datei von .cff in .jpg umbenennen, bevor + Sie sie öffnen können. + + Leider kenne ich momentan keinen Weg, dieses Format manuell zu erzeugen. + Daher unterstützt CapiSuite bis jetzt nur den Empfang solcher Dokumente. Wenn Sie + mehr darüber wissen sollten oder den JPEG-Standard gut kennen, dann kontaktieren + Sie mich bitte! + diff --git a/docs/manual.docbook b/docs/manual.docbook index 996309b..cd8ea1f 100644 --- a/docs/manual.docbook +++ b/docs/manual.docbook @@ -20,7 +20,7 @@ Introduction Welcome to &cs; - Welcome to &cs;, a Python-scriptable ISDN telecommunication suite. + Welcome to &cs;, a Python-scriptable ISDN telecommunication suite. It uses the new CAPI interface for accessing your ISDN-hardware - so you'll need a card for which a CAPI compatible driver is available. Currently these are all cards manufactured by AVM @@ -214,6 +214,17 @@ find the device cfax in the long list of supported devices. + + jpeg2ps + The jpeg2ps command is used to convert color fax files to the + PostScript format for mail delivery. It's not so important, unless you want to be able to receive + color faxes. Unfortunately, there's currently no way to disable the reception of color faxes with + AVM cards due to a bug in the AVM CAPI driver. So if someone sends you a color fax (which seems to + be a very rare case), you'll need this package - unless you'll get a mail stating this error. + If your distribution doesn't have this packages, you can download it from + . + + @@ -1491,6 +1502,9 @@ is not present, current time as returned by localtime() is used. Finally I found some small tools written by Peter Schäfer, which we can use here. + CapiSuite is also able to receive color fax files which will be stored in + a special file format I called CFF. + Creating a SFF In current Ghostscript releases, a patch from Peter has been included to produce SF files. To see if your Ghostscript already @@ -1526,7 +1540,20 @@ is not present, current time as returned by localtime() is used. any other useful format with the TIFF tools, for example tiff2ps. + Color faxes - the CFF format + There exists an enhancement to the fax standard which allows to transfer + documents in color. It's not very widely used, but as some people wanted it for CapiSuite, + I added support for receiving this faxes with CapiSuite. + The CFF format (I don't know if this is an official name for the format) seems + to be some sort of JPEG file with a special encoding. Most programs who can handle + JPEG files should be able to open it. Perhaps you must rename it from + .cff to .jpg first, before it will be recognized. + + Currently, I don't know a nice way to create this format manually. Therefore, + CapiSuite currently only supports the reception of these files. If someone knows + more about it or knows the JPEG standards well, please contace me! + diff --git a/scripts/cs_helpers.pyin b/scripts/cs_helpers.pyin index 0298bbf..b86a341 100644 --- a/scripts/cs_helpers.pyin +++ b/scripts/cs_helpers.pyin @@ -2,7 +2,7 @@ # ----------------------------------------------------------- # copyright : (C) 2002 by Gernot Hillier # email : gernot@hillier.de -# version : $Revision: 1.9 $ +# version : $Revision: 1.10 $ # # 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 @@ -161,7 +161,7 @@ def sendMIMEMail(mail_from,mail_to,mail_subject,mail_type,text,attachment): basename=attachment[:attachment.rindex('.')+1] try: - if (mail_type=="sff"): + if (mail_type=="sff"): # normal fax file # sff -> tif ret=os.spawnlp(os.P_WAIT,"sfftobmp","sfftobmp","-tif",attachment,basename+"tif") if (ret or not os.access(basename+"tif",os.F_OK)): @@ -173,7 +173,7 @@ def sendMIMEMail(mail_from,mail_to,mail_subject,mail_type,text,attachment): command="tiff2ps -a "+escape(basename+"tif")+" | ps2pdf - -" tiff2pdf=popen2.Popen3(command) if (tiff2pdf.poll()!=-1): - raise "conv-error","Error while calling tiff2pdf or ps2pdf. Not installed?" + raise "conv-error","Error while calling tiff2ps or ps2pdf. Not installed?" tiff2pdf.tochild.close() # we don't need the input pipe # create attachment with pdf stream filepart = email.MIMEBase.MIMEBase("application","pdf",name=os.path.basename(basename)+"pdf") @@ -185,7 +185,31 @@ def sendMIMEMail(mail_from,mail_to,mail_subject,mail_type,text,attachment): raise "conv-error","Error "+str(ret)+" occured during tiff2ps or ps2pdf" os.unlink(basename+"tif") email.Encoders.encode_base64(filepart) - elif (mail_type=="la"): + elif (mail_type=="cff"): # color fax file + # cff -> ps + ret=os.spawnlp(os.P_WAIT,"jpeg2ps","jpeg2ps",attachment,"-o",basename+"ps") + if (ret or not os.access(basename+"ps",os.F_OK)): + raise "conv-error","Can't convert cff to ps. jpeg2ps not installed?" + # tif -> ps -> pdf + # the first pipe must be handled by the shell so that the output of + # of ps2pdf can be read immediately. Handling this shell in Python + # leads to an overflow of the ps2pdf output pipe... + command="ps2pdf "+escape(basename+"ps")+" -" + ps2pdf=popen2.Popen3(command) + if (ps2pdf.poll()!=-1): + raise "conv-error","Error while calling ps2pdf. Not installed?" + ps2pdf.tochild.close() # we don't need the input pipe + # create attachment with pdf stream + filepart = email.MIMEBase.MIMEBase("application","pdf",name=os.path.basename(basename)+"pdf") + filepart.add_header('Content-Disposition','attachment',filename=os.path.basename(basename)+"pdf") + filepart.set_payload(ps2pdf.fromchild.read()) + ps2pdf.fromchild.close() + ret=ps2pdf.wait() + if (ret!=0): + raise "conv-error","Error "+str(ret)+" occured during ps2pdf" + os.unlink(basename+"ps") + email.Encoders.encode_base64(filepart) + elif (mail_type=="la"): # voice file # la -> wav # don't use stdout as sox needs a file to be able to seek in it otherwise the header will be incomplete ret = os.spawnlp(os.P_WAIT,"sox","sox",attachment,basename+"wav") @@ -317,6 +341,9 @@ def sayNumber(call,number,curr_user,config): capisuite.audio_send(call,getAudio(config,curr_user,i+".la"),1) # $Log: cs_helpers.pyin,v $ +# Revision 1.10 2003/05/25 13:38:30 gernot +# - support reception of color fax documents +# # Revision 1.9 2003/04/24 21:04:20 gernot # - replace functions deprecated in Python 2.2.2 (mainly related to the email # module) diff --git a/scripts/incoming.py b/scripts/incoming.py index 8ac1ccd..6baca28 100644 --- a/scripts/incoming.py +++ b/scripts/incoming.py @@ -2,7 +2,7 @@ # ---------------------------------------------------- # copyright : (C) 2002 by Gernot Hillier # email : gernot@hillier.de -# version : $Revision: 1.6 $ +# version : $Revision: 1.7 $ # # 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 @@ -73,13 +73,6 @@ def callIncoming(call,service,call_from,call_to): capisuite.connect_voice(call,int(delay)) voiceIncoming(call,call_from,call_to,curr_user,config) elif (curr_service==capisuite.SERVICE_FAXG3): - stationID=cs_helpers.getOption(config,curr_user,"fax_stationID") - if (stationID==None): - capisuite.error("Warning: fax_stationID not found for user "+curr_user+" -> using empty string") - stationID="" - headline=cs_helpers.getOption(config,curr_user,"fax_headline","") # empty string is no problem here - capisuite.log("call from "+call_from+" to "+call_to+" for "+curr_user+" connecting with fax",1,call) - capisuite.connect_faxG3(call,stationID,headline,0) faxIncoming(call,call_from,call_to,curr_user,config) except capisuite.CallGoneError: # catch exceptions from connect_* (cause,causeB3)=capisuite.disconnect(call) @@ -112,8 +105,19 @@ def faxIncoming(call,call_from,call_to,curr_user,config): capisuite.error("user "+curr_user+" is not a valid system user. Disconnecting",call) capisuite.reject(call,0x34A9) return - filename=cs_helpers.uniqueName(udir+"received/","fax","sff") try: + stationID=cs_helpers.getOption(config,curr_user,"fax_stationID") + if (stationID==None): + capisuite.error("Warning: fax_stationID not found for user "+curr_user+" -> using empty string") + stationID="" + headline=cs_helpers.getOption(config,curr_user,"fax_headline","") # empty string is no problem here + capisuite.log("call from "+call_from+" to "+call_to+" for "+curr_user+" connecting with fax",1,call) + faxInfo=capisuite.connect_faxG3(call,stationID,headline,0) + if (faxInfo!=None and faxInfo[3]==1): + faxFormat="cff" # color fax + else: + faxFormat="sff" # normal b&w fax + filename=cs_helpers.uniqueName(udir+"received/","fax",faxFormat) capisuite.fax_receive(call,filename) (cause,causeB3)=capisuite.disconnect(call) capisuite.log("connection finished with cause 0x%x,0x%x" % (cause,causeB3),1,call) @@ -140,7 +144,7 @@ def faxIncoming(call,call_from,call_to,curr_user,config): capisuite.error("Warning: No valid fax_action definition found for user "+curr_user+" -> assuming SaveOnly") action="saveonly" if (action=="mailandsave"): - cs_helpers.sendMIMEMail(curr_user, mailaddress, "Fax received from "+call_from+" to "+call_to, "sff", + cs_helpers.sendMIMEMail(curr_user, mailaddress, "Fax received from "+call_from+" to "+call_to, faxFormat, "You got a fax from "+call_from+" to "+call_to+"\nDate: "+time.ctime()+"\n\n" +"See attached file.\nThe original file was saved to file://"+filename+"\n\n", filename) @@ -402,6 +406,9 @@ def newAnnouncement(call,userdir,curr_user,config): # History: # # $Log: incoming.py,v $ +# Revision 1.7 2003/05/25 13:38:30 gernot +# - support reception of color fax documents +# # Revision 1.6 2003/04/10 21:29:51 gernot # - support empty destination number for incoming calls correctly (austrian # telecom does this (sic)) diff --git a/src/application/capisuitemodule.cpp b/src/application/capisuitemodule.cpp index ee2fbc0..ab48249 100644 --- a/src/application/capisuitemodule.cpp +++ b/src/application/capisuitemodule.cpp @@ -2,7 +2,7 @@ @brief Contains the Python module and integration routines @author Gernot Hillier - $Revision: 1.3 $ + $Revision: 1.4 $ */ /*************************************************************************** @@ -496,8 +496,9 @@ capisuite_reject(PyObject *, PyObject *args) @param service with which service we should connect @param faxStationID only used for fax connections @param faxHeadline only used for fax connections + @return false if exception was rased -> calling function must return NULL then */ -static PyObject* +bool capisuite_connect(Connection *conn, int delay, Connection::service_t service, string faxStationID, string faxHeadline) { PyThreadState *_save; @@ -514,20 +515,19 @@ capisuite_connect(Connection *conn, int delay, Connection::service_t service, st catch (CapiMsgError e) { Py_BLOCK_THREADS PyErr_SetString(BackendError,(e.message()).c_str()); - return NULL; + return false; } catch (CapiWrongState e) { Py_BLOCK_THREADS PyErr_SetString(CallGoneError,"Call was finished from partner."); - return NULL; + return false; } catch (CapiExternalError e) { Py_BLOCK_THREADS PyErr_SetString(BackendError,(e.message()).c_str()); - return NULL; + return false; } - Py_XINCREF(Py_None); - return (Py_None); + return true; } /** @brief Accept an incoming call and connect with voice service. @@ -554,7 +554,11 @@ capisuite_connect_voice(PyObject *, PyObject *args) if (!PyArg_ParseTuple(args,"O&|i:connect_voice",convertConnRef,&conn,&delay)) return NULL; - return capisuite_connect(conn,delay,Connection::VOICE,"",""); + if (capisuite_connect(conn,delay,Connection::VOICE,"","")) { + Py_XINCREF(Py_None); + return (Py_None); + } else + return NULL; } /** @brief Accept an incoming call and connect with fax (analog, group 3) service. @@ -571,7 +575,11 @@ capisuite_connect_voice(PyObject *, PyObject *args) - faxStationID (string) the station ID to use - faxHeadline (string) the fax headline to use - delay (integer, optional) delay in seconds _before_ connection will be established (default: 0=immediate connect) - @return None + @return None or a tuple (stationID,rate,hiRes,format) containing the values: + - fax station ID from the calling party (String) + - bit rate which was used for connecting + - high (1) or low (0) resolution + - transmit format: 0=SFF,black&white, 1=ColorJPEG */ static PyObject* capisuite_connect_faxG3(PyObject *, PyObject *args) @@ -583,7 +591,17 @@ capisuite_connect_faxG3(PyObject *, PyObject *args) if (!PyArg_ParseTuple(args,"O&ss|i:connect_faxG3",convertConnRef,&conn,&faxStationID,&faxHeadline,&delay)) return NULL; - return capisuite_connect(conn,delay,Connection::FAXG3,faxStationID,faxHeadline); + if (capisuite_connect(conn,delay,Connection::FAXG3,faxStationID,faxHeadline)) { + Connection::fax_info_t* fax_info = conn->getFaxInfo(); + if (fax_info) { + PyObject *r=Py_BuildValue("siii",fax_info->stationID.c_str(),fax_info->rate,fax_info->hiRes,fax_info->format); + return (r); + } else { + Py_XINCREF(Py_None); + return (Py_None); + } + } else + return NULL; } /** @brief helper function for capisuite_call_voice() and capisuite_call_faxG3() @@ -937,6 +955,9 @@ capisuitemodule_init () throw (ApplicationError) /* History $Log: capisuitemodule.cpp,v $ +Revision 1.4 2003/05/25 13:38:30 gernot +- support reception of color fax documents + Revision 1.3 2003/04/17 10:53:54 gernot - update documentation of capisuite_call_* to the new behaviour (timeout for outgoing calls starts when other party gets signalled), moved error code diff --git a/src/backend/connection.cpp b/src/backend/connection.cpp index ebc8443..8bfcb4a 100644 --- a/src/backend/connection.cpp +++ b/src/backend/connection.cpp @@ -2,7 +2,7 @@ @brief Contains Connection - Encapsulates a CAPI connection with all its states and methods. @author Gernot Hillier - $Revision: 1.8 $ + $Revision: 1.9 $ */ /*************************************************************************** @@ -415,12 +415,12 @@ Connection::connect_b3_active_ind(_cmsg& message) throw (CapiWrongState, CapiExt fax_info=new fax_info_t; fax_info->rate=ncpi[1]+(ncpi[2]<<8); fax_info->hiRes=((ncpi[3] & 0x01) == 0x01); - fax_info->colorJPEG=((ncpi[4] & 0x04) == 0x04); + fax_info->format=((ncpi[4] & 0x04) == 0x04); fax_info->pages=ncpi[7]+(ncpi[8]<<8); fax_info->stationID.assign(reinterpret_cast(&ncpi[10]),static_cast(ncpi[9])); // indx 9 helds the length, string starts at 10 if (debug_level >= 2) { debug << prefix() << "fax connected with rate " << dec << fax_info->rate - << (fax_info->hiRes ? ", hiRes" : ", lowRes") << (fax_info->colorJPEG ? ", JPEG" : "") + << (fax_info->hiRes ? ", hiRes" : ", lowRes") << (fax_info->format ? ", JPEG" : "") << ", ID: " << fax_info->stationID << endl; } } @@ -449,12 +449,12 @@ Connection::disconnect_b3_ind(_cmsg& message) throw (CapiWrongState) fax_info=new fax_info_t; fax_info->rate=ncpi[1]+(ncpi[2]<<8); fax_info->hiRes=((ncpi[3] & 0x01) == 0x01); - fax_info->colorJPEG=((ncpi[4] & 0x04) == 0x04); + fax_info->format=((ncpi[4] & 0x04) == 0x04); fax_info->pages=ncpi[7]+(ncpi[8]<<8); fax_info->stationID.assign(reinterpret_cast(&ncpi[10]),static_cast(ncpi[9])); // indx 9 helds the length, string starts at 10 if (debug_level >= 2) { debug << prefix() << "fax finished with rate " << dec << fax_info->rate - << (fax_info->hiRes ? ", hiRes" : ", lowRes") << (fax_info->colorJPEG ? ", JPEG" : "") + << (fax_info->hiRes ? ", hiRes" : ", lowRes") << (fax_info->format ? ", JPEG" : "") << ", ID: " << fax_info->stationID << ", " << fax_info->pages << " pages" << endl; } } @@ -1040,6 +1040,9 @@ Connection::buildBconfiguration(_cdword controller, service_t service, string fa /* History $Log: connection.cpp,v $ +Revision 1.9 2003/05/25 13:38:30 gernot +- support reception of color fax documents + Revision 1.8 2003/05/24 13:48:54 gernot - get fax details (calling station ID, transfer format, ...), handle PLCI diff --git a/src/backend/connection.h b/src/backend/connection.h index 953c89a..ee33c75 100644 --- a/src/backend/connection.h +++ b/src/backend/connection.h @@ -2,7 +2,7 @@ @brief Contains Connection - Encapsulates a CAPI connection with all its states and methods. @author Gernot Hillier - $Revision: 1.4 $ + $Revision: 1.5 $ */ /*************************************************************************** @@ -316,7 +316,7 @@ class Connection struct fax_info_t { int rate; ///< bit rate used at connect or at disconnect (depends when you ask for it) bool hiRes; ///< fax is transferred in high resolution - bool colorJPEG; ///< color fax transmitted as JPEG file + unsigned short format; ///< 0=SFF,black&white, 1=colorJPEG int pages; ///< number of transmitted pages (only available after disconnection!) std::string stationID; ///< ID of the sending station }; @@ -657,6 +657,9 @@ class Connection /* History $Log: connection.h,v $ +Revision 1.5 2003/05/25 13:38:30 gernot +- support reception of color fax documents + Revision 1.4 2003/05/24 13:48:54 gernot - get fax details (calling station ID, transfer format, ...), handle PLCI