/******************************************************************************* * rfaxprogram.cpp * RightFax program base class. * * Compile: * CL -I -c rfaxprogram.obj * where * '' is the directory containing "rfapi.h". * *------------------------------------------------------------------------------ * @version $Revision: 1.2 $ $Date: 2008/03/28 23:59:24 $ * @since 2008-03-27 * @author David R. Tribble (david@tribble.com) * * Copyright ©2008 by David R. Tribble, all rights reserved. * Permission is granted to any person or entity except those designated * by the United States Department of State as a terrorist, or terrorist * government or agency, to use and distribute this source code provided * that the original copyright notice remains present and unaltered. */ // Identification static char REV[] = "@(#)drt/rightfax/src/rfaxprogram.hpp $Revision: 1.2 $ $Date: 2008/03/28 23:59:24 $"; static char COPYRIGHT[] = "@(#)Copyright ©2008 by David R. Tribble, all rights reserved."; // System includes #ifndef _WIN32 #error This only compiles on Win32 (MS/Windows) systems #endif #include #include #include #include #include #include #include #define WIN32 #define WIN32_LEAN_AND_MEAN 1 #include #include // Local includes #define rfaxprogram_cpp 1 #include "rfaxprogram.hpp" //============================================================================== // Local constants //============================================================================== static const int REQ_RF_VERS = 0x0520; // RightFax 5.2+ req'd //============================================================================== // Class constants //============================================================================== /*static*/ const int RFaxProgram::VS = // Class version RFaxProgram_VS; //============================================================================== // Static class functions //============================================================================== /*------------------------------------------------------------------------------ * RFaxProgram::matchesPattern() * Compare a name to a wildcard (filename) pattern. * * @param name * A name to compare. * * @param pat * Name pattern containing wildcards, which are: * ? - matches a single character * * - matches zero or more characters * Note that alphabetic character comparisons are case-insensitive (e.g., * "abc" * matches "abc", "Abc", and "ABC"). * * @return * True if 'name' matches 'pat', otherwise false. * If either 'name' or 'pat' is null, false is returned. * * @since 1.1, 2008-03-27 */ /*static*/ bool RFaxProgram::matchesPattern(const char *name, const char *pat) { #if RFaxProgram_VS/100 != 1 #error class RFaxProgram has changed #endif int i; // Sanity check if (name == NULL) return false; if (pat == NULL) return false; // Compare the name to the pattern switch (pat[0]) { case '\0': // End of string return (name[0] == '\0'); case '?': // Match any single character if (name[0] == '\0') return false; return matchesPattern(name+1, pat+1); case '*': // Match zero or more characters for (i = 0; name[i] != '\0'; i++) continue; do { if (matchesPattern(name+i, pat+1)) return true; } while (--i >= 0); return false; default: // Compare single characters, case-insensitive if (tolower(pat[0]) == tolower(name[0])) return matchesPattern(name+1, pat+1); else return false; } } /*------------------------------------------------------------------------------ * RFaxProgram::cvtStatus() * Convert a RightFax Fax status code into its corresponding textual * representation. * * @param status * A RightFax status code for a Fax document. * * @return * Pointer to a static string buffer. * * @since 1.2, 2008-03-28 */ /*static*/ const char * RFaxProgram::cvtStatus(int status) { #if RFaxProgram_VS/100 != 1 #error class RFaxProgram has changed #endif static char buf[20+1]; // Examine the RightFax status code switch (status) { case FAXSTAT_DONE_OK: return "Okay"; case FAXSTAT_ERROR: return "Error"; case FAXSTAT_UNBORN: return "Unborn"; case FAXSTAT_NEEDS_FCS: return "Needs FCS"; case FAXSTAT_NEEDS_CONVERSION: return "Needs conversion"; case FAXSTAT_NEEDS_TOBESENT: return "Needs to be sent"; case FAXSTAT_IN_CONVERSION: return "In conversion"; case FAXSTAT_IN_SEND: return "In send"; case FAXSTAT_MANUALFCS: return "Manual FCS"; case FAXSTAT_IN_SCHEDULE: return "In schedule"; case FAXSTAT_DONE_ERROR: return "Done error"; case FAXSTAT_DUPLICATE: return "Duplicate"; case FAXSTAT_ATTN: return "Attention"; case FAXSTAT_NEEDS_ATTACH: return "Needs attachment"; case FAXSTAT_HELD: return "Held"; case FAXSTAT_INOCR: return "In OCR"; case FAXSTAT_INPRINT: return "In print"; case FAXSTAT_QUEPRINT: return "Queued for print"; case FAXSTAT_QUEOCR: return "Queued for OCR"; case FAXSTAT_IN_VALIDATE: return "In validate"; case FAXSTAT_IN_APPROVAL: return "In approval"; default: // Unknown status code ::sprintf(buf, "%d", status); return buf; } } //============================================================================== // Class member functions //============================================================================== /*------------------------------------------------------------------------------ * RFaxProgram::~RFaxProgram() * Destructor. * * @since 1.1, 2008-03-27 */ /*virtual*/ /*void*/ RFaxProgram::~RFaxProgram() { #if RFaxProgram_VS != 100 #error class RFaxProgram has changed #endif // Disconnect from server if (m_hdl != NULL) disconnect(); // Deallocate members delete[] const_cast(m_server); m_server = NULL; delete[] const_cast(m_serverIP); m_serverIP = NULL; delete[] const_cast(m_user); m_user = NULL; delete[] const_cast(m_uname); m_uname = NULL; delete[] const_cast(m_group); m_group = NULL; delete m_info; m_info = NULL; m_hdl = NULL; m_msg[0] = '\0'; // De-initialize m_magic = ~RFaxProgram_MAGIC; } /*------------------------------------------------------------------------------ * RFaxProgram::RFaxProgram() * Default constructor. * * @since 1.1, 2008-03-27 */ /*void*/ RFaxProgram::RFaxProgram(): m_magic(RFaxProgram_MAGIC), m_vers(RFaxProgram_VS), m_apiVers(0), m_server(NULL), m_serverIP(NULL), m_hdl(NULL), m_info(NULL), m_error(0), m_time(0), m_tz(0), m_user(NULL), m_uname(NULL), m_group(NULL) { #if RFaxProgram_VS != 100 #error class RFaxProgram has changed #endif struct tm ts; char tbuf[80+1]; // Initialize m_apiVers = ::RFaxGetAPIVersion(); // Determine the RightFax API (library) version ts = *::gmtime(&m_apiVers); ::strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%SZ", &ts); ::printf("RightFax API version: %s\n", tbuf); m_info = new SERVERINFO2(); ::memset(m_info, 0, sizeof(*m_info)); m_msg[0] = '\0'; } /*------------------------------------------------------------------------------ * RFaxProgram::connect() * Connect to a RightFax server. * * @param host * RightFax server name or IP address. * * @since 1.1, 2008-03-27 */ bool RFaxProgram::connect(const char *host) { #if RFaxProgram_VS/100 != 1 #error class RFaxProgram has changed #endif const int MAX_TRIES = 5; int tries; DWORD err; // Connect to the RightFax server ::printf("Connecting to RightFax server: %s\n", host); ::fflush(stdout); for (tries = 1; ; tries++) { RFAXSERVERHANDLE hdl; // Check for too many failed attempts if (tries > MAX_TRIES) { // Too many failed attempts to connect ::printf("Can't connect to RightFax server after %d tries: %s\n", tries-1, host); ::fflush(stdout); return false; } // Attempt to connect to the RightFax server ::printf("Connect(%d) to RightFax server: %s\n", tries, host); ::fflush(stdout); hdl = ::RFaxCreateServerHandle(host, COMMPROTOCOL_TCPIP, &err); ::time(&m_time); if (hdl != NULL) { // Connection made successfully ::printf("Connected to RightFax server: %s\n", host); ::fflush(stdout); m_error = 0; m_hdl = hdl; delete[] const_cast(m_serverIP); m_serverIP = ::strdup(host); delete[] const_cast(m_server); m_server = NULL; // Success break; } else { // Connection failed m_error = err; ::printf("Connect failed to RightFax server: %s, error %d: %s\n", host, m_error, getErrorMessage()); ::fflush(stdout); // Pause and try again (10 sec) ::Sleep(10*1000); } } // Validate server version compatibility { RFAXSERVERHANDLE hdl; // Check the server release number hdl = (RFAXSERVERHANDLE) m_hdl; err = ::RFaxVersionCheck(hdl, REQ_RF_VERS, 0); if (err != RFAX_SUCCESS) { // Incompatible RightFax server version ::printf("Incompatible RightFax server release, need %X.%02X\n", REQ_RF_VERS/0x100, REQ_RF_VERS%0x100); ::fflush(stdout); return false; } } // Retrieve information about the RightFax server getServerInfo(); // Success return true; } /*------------------------------------------------------------------------------ * RFaxProgram::disconnect() * Disconnect from a RightFax server. * * @since 1.1, 2008-03-27 */ void RFaxProgram::disconnect() { #if RFaxProgram_VS/100 != 1 #error class RFaxProgram has changed #endif RFAXSERVERHANDLE hdl; // Sanity check if (m_hdl == NULL) return; // Disconnect from the RightFax server ::printf("Disconnect from RightFax server: %s, %s\n", m_serverIP, (m_server != m_server ? m_server : "-")); ::fflush(stdout); hdl = (RFAXSERVERHANDLE) m_hdl; ::RFaxCloseServerHandle(hdl); m_hdl = NULL; ::time(&m_time); ::printf("Disconnected\n"); ::fflush(stdout); } /*------------------------------------------------------------------------------ * RFaxProgram::getServerInfo() * Retrieve information about the fax server. * * @return * True if the server information was retrieved successfully, otherwise false. * * @since 1.1, 2008-03-27 */ bool RFaxProgram::getServerInfo() { #if RFaxProgram_VS/100 != 1 #error class RFaxProgram has changed #endif RFAXSERVERHANDLE hdl; SERVERINFO2 * info; DWORD err; // Attempt to retrieve server info from the fax server info = m_info; hdl = (RFAXSERVERHANDLE) m_hdl; err = ::RFaxGetServerInfo2(hdl, info); ::time(&m_time); if (err == RFAX_SUCCESS) { int tzOff; // Success m_error = 0; delete const_cast(m_server); m_server = ::strdup(info->szImageLocServer); // Get the timezone adjustment for the server switch (info->fTimeZoneInfoValid) { case 2: // Standard time (not DST) tzOff = info->TimeZoneInfo.Bias + info->TimeZoneInfo.StandardBias; tzOff *= 60; break; case 3: // Daylight time (DST) tzOff = info->TimeZoneInfo.Bias + info->TimeZoneInfo.DaylightBias; tzOff *= 60; break; default: // Unknown or no offset tzOff = 0; break; } m_tz = tzOff; // Success return true; } else { // Failed m_error = err; return false; } } /*------------------------------------------------------------------------------ * RFaxProgram::getUserInfo() * Retrieve information about a RightFax user. * * @param name * User-ID (in-box name) to retrieve. * * @return * True if the user information was retrieved successfully, otherwise false. * * @since 1.1, 2008-03-27 */ bool RFaxProgram::getUserInfo(const char *name) { #if RFaxProgram_VS/100 != 1 #error class RFaxProgram has changed #endif RFAXSERVERHANDLE hdl; USERINFO_11 uInfo; int rc; // Retrieve info for the specified user-ID from the fax server hdl = (RFAXSERVERHANDLE) m_hdl; ::memset(&uInfo, 0, sizeof(uInfo)); #if use_old_struct // For API prior to 7.x+ rc = ::RFaxLoadUser(hdl, 0L, name, "", "", (USERINFO_10 *) &uInfo); #else rc = ::RFaxLoadUser3(hdl, 1, NULL, name, NULL, NULL, 0L, 0L, 11, &uInfo); #endif m_error = rc; ::time(&m_time); if (rc != RFAX_SUCCESS) return false; // Save the user info m_user = ::strdup(uInfo.userid); m_group = ::strdup(uInfo.groupid); m_uname = ::strdup(uInfo.username); return true; } /*------------------------------------------------------------------------------ * RFaxProgram::getErrorMessage() * Retrieve the text message for the last error. * * @return * Pointer to a string containing the text of the last error that occurred. * Note that this string should not be deleted or freed. * * @since 1.1, 2008-03-27 */ const char * RFaxProgram::getErrorMessage() { #if RFaxProgram_VS/100 != 1 #error class RFaxProgram has changed #endif // Format the error message ::RFaxStringRFaxErr(m_error, m_msg, sizeof(m_msg)); m_msg[sizeof(m_msg)-1] = '\0'; return m_msg; } // End rfaxprogram.cpp