Code Samples: Python
IMPORTANT! C# is our official client and the only code that we support. This Python code has been provided by another customer; and we encourage you to let us know if you find any problems, so that we can update accordingly.
Sendfax Method
#CORE PYTHON IMPORTS import logging, sys, time, urllib, base64, urllib2 import simplejson as json from xml.dom.minidom import parseString #SRC IMPORTS import webservice from pkcs7 import PKCS7Encoder #DEPENDENCY IMPORTS -- PyCrypto (https://www.dlitz.net/software/pycrypto/ OR <a href="http://pypi.python.org/pypi/pycrypto/2.5">http://pypi.python.org/pypi/pycrypto/2.5</a>) from Crypto.Cipher import AES USERNAME = "" Enter a valid Username APIKEY = "" Enter a valid ApiKey ENCRYPTIONKEY = "" Enter a valid EncryptionKey VECTOR = "" Enter a valid Vector URL = "https://api.sfaxme.com" DOWNLOAD_DIR = "C:\\Temp\\faxes\\" def getToken():#Generating token print ("sfaxWS.py -> getToken") try: timestr = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) raw = "Username="+USERNAME+"&ApiKey="+APIKEY+"&GenDT="+timestr+"&" mode = AES.MODE_CBC encoder = PKCS7Encoder() encryptor = AES.new(ENCRYPTIONKEY, mode, VECTOR.encode("ascii")) pad_text = encoder.encode(raw) cipher = encryptor.encrypt(pad_text) enc_cipher = base64.b64encode(cipher) return urllib.quote_plus(enc_cipher) except: print ("Error getting token " + str(sys.exc_info()[0]) + " " + str(sys.exc_info()[1])) return """ RETURN THE SENDFAXQUEUEID OF THE OUTGOING FAX, OTHERWISE RETURN NONE IF FAILED TO SEND """ def sendFax(fax): print ("sfaxWS.py -> sendFax") tid = None XwsSuccess = "true" try: path = "/api/sendfax?token="+getToken()+"&ApiKey="+APIKEY+"&RecipientName=Gene&RecipientFax="+ str(fax)+"&OptionalParams=&" response = webservice.post(URL2, path) if XwsSuccess == "true": print ("Fax successfully submitted to sfax for delivery to " + str(fax)) result = json.load(urllib2.urlopen(response)) tid = result['SendFaxQueueId'] print tid else: err = "Error submitting fax for send to " + str(fax) err += " ResultCode=" + str(response.getheader("XwsFaxResultCode")) + " ResultInfo=" + str(response.getheader("XwsResultInfo")) err += " ErrorCode=" + str(response.getheader("XwsFaxErrorCode")) + " ErrorInfo=" + str(response.getheader("XwsErrorInfo")) print (err) except: print ("Error transmitting data to sfax " + str(sys.exc_info()[0]) + " " + str(sys.exc_info()[1])) return tid
SendfaxStatus Method
""" RETURN THE STATUS OF AN OUTGOING FAX """ def getStatus(tid): XwsSuccess = "true" print ("sfaxWS.py -> getStatus") print ("Checking status on " + tid) ret = (True) path = "/api/sendfaxstatus?token="+getToken()+"&ApiKey="+APIKEY+"&SendFaxQueueId="+ str(tid) response = webservice.get(URL, path) if XwsSuccess == "true": #sFax is no longer trying to send this fax. Find out what the result was... SendResponse = urllib2.urlopen(response).read() result = json.load(urllib2.urlopen(response)) status = result['message'] print status else: err = "Error checking fax status for tid " + tid err += " ResultCode=" + response.getheader("XwsFaxResultCode") + " ResultInfo=" + response.getheader("XwsResultInfo") err += " ErrorCode=" + response.getheader("XwsFaxErrorCode") + " ErrorInfo=" + response.getheader("XwsErrorInfo") """log.warn(err)""" print (err) return ret # USAGE #********************************************************* tid = sendFax("C:\\Temp\\test2.pdf", "15123668506") getStatus(tid) complete, success, faxAttempt = getStatus(tid) print (complete,success,int(faxAttempt)) while True: getStatus(tid) complete, success, faxAttempt = getStatus(tid) print (complete,success,int(faxAttempt)) tids = inboundFaxRetrieveSet() for t in tids: inboundFaxDownload(t) time.sleep(60) print "************************* DONE *************************"
webservice.py
import httplib from poster.encode import multipart_encode from poster.streaminghttp import register_openers import urllib2 def post(URL, path, file_to_upload ): # Register the streaming http handlers with urllib2 register_openers() # Start the multipart/form-data encoding of the file "DSC0001.jpg" # "image1" is the name of the parameter, which is normally set # via the "name" parameter of the HTML <input> tag. # headers contains the necessary Content-Type and Content-Length # datagen is a generator object that yields the encoded parameters datagen, headers = multipart_encode({"file.pdf": open("C:\\temp\\test2.pdf", "rb")}) # Create the Request object response = urllib2.Request(URL + path, datagen, headers) # Actually do the request, and get the response print urllib2.urlopen(response).read() #print urllib2.urlopen(response).info().items() return response def get(URL, path): register_openers() response = urllib2.Request(URL + path) print urllib2.urlopen(response).read() return response
pkcs7.py
import binascii import StringIO class PKCS7Encoder(object): ''' RFC 2315: PKCS#7 page 21 Some content-encryption algorithms assume the input length is a multiple of k octets, where k > 1, and let the application define a method for handling inputs whose lengths are not a multiple of k octets. For such algorithms, the method shall be to pad the input at the trailing end with k - (l mod k) octets all having value k - (l mod k), where l is the length of the input. In other words, the input is padded at the trailing end with one of the following strings: 01 -- if l mod k = k-1 02 02 -- if l mod k = k-2 . . . k k ... k k -- if l mod k = 0 The padding can be removed unambiguously since all input is padded and no padding string is a suffix of another. This padding method is well-defined if and only if k < 256; methods for larger k are an open issue for further study. ''' def __init__(self, k=16): self.k = k ## @param text The padded text for which the padding is to be removed. # @exception ValueError Raised when the input padding is missing or corrupt. def decode(self, text): ''' Remove the PKCS#7 padding from a text string ''' nl = len(text) val = int(binascii.hexlify(text[-1]), 16) if val > self.k: raise ValueError('Input is not padded or padding is corrupt') l = nl - val return text[:l] ## @param text The text to encode. def encode(self, text): ''' Pad an input string according to PKCS#7 ''' l = len(text) output = StringIO.StringIO() val = self.k - (l % self.k) for _ in xrange(val): output.write('%02x' % val) return text + binascii.unhexlify(output.getvalue())
ReceiveInboundFax Sample
"" CHECK TO SEE IF THERE ARE INBOUND FAXES TO DOWNLOAD """ def inboundFaxRetrieveSet(): XwsSuccess = "true" faxid = None """log = logging.getLogger("sfaxWS.py -> inboundFaxRetrieveSet")""" print ("sfaxWS.py -> inboundFaxRetrieveSet") """log.info(".")""" #print (".") tid = [] fids = [] path = "/api/receiveinboundfax?token="+getToken()+"&ApiKey="+APIKEY response = webservice.get(URL2, path,) GetResponse = urllib2.urlopen(response).read() print GetResponse result = json.loads(GetResponse) print result faxid = result for x in faxid['InboundFaxItems']: print "FaxId:", x['FaxId'] fids = x['FaxId'] return tid
DownloadInboundFaxasPdf Sample
DOWNLOAD AN INBOUND FAX as PDF """ def inboundFaxDownload(FaxId):#Enter a valid FaxId XwsSuccess = "true" print ("sfaxWS.py -> inboundFaxDownload") print ("downloading " + FaxId) path = "/api/downloadinboundfaxaspdf?token="+getToken()+"&ApiKey="+APIKEY+"&FaxId="+FaxId response = webservice.get(URL2 , path) if XwsSuccess == "true": GetResponse = urllib2.urlopen(response).read() filename = FaxId data = GetResponse with open(DOWNLOAD_DIR+filename+".pdf", "wb") as f: f.write(data)
DownloadInboundFaxAsTif – Sample
DOWNLOAD AN INBOUND FAX as TIF """ def inboundFaxDownload(FaxId):#Enter a valid FaxId XwsSuccess = "true" print ("sfaxWS.py -> inboundFaxDownload") print ("downloading " + '2121018144829980894') path = "/api/downloadinboundfaxastif?token="+getToken()+"&ApiKey="+APIKEY+"&FaxId="+FaxId response = webservice.get(URL2 , path) if XwsSuccess == "true": GetResponse = urllib2.urlopen(response).read() filename = FaxId data = GetResponse with open(DOWNLOAD_DIR+filename+".tif", "wb") as f: f.write(data)
Notes
- There are 3 external dependencies on PyCrypto, simplejson and poster. Python core does not natively support AES. PyCrypto, simplejson and poster are all python endorsed third party lib.
- Neither PyCrypto nor Python natively support PKCS7, so included is some commonly used code for that function.
- Not all available functions are represented here at the moment only the sending of a fax and checking the initial status of the fax are represented here.
- You may need to initialize python logging to use these files out of the box with log.xxx, or you can use print statements as represented.