/******************************************************************************* * rfaxdelegate.cpp * Manage in-box delegates on a RightFax server. * * Compile: * CL -I "-DVERS=\"R.L\"" rfaxdelegate.cpp rfaxprogram.obj \rfwin32.lib * where * 'R.L' is the program version number; * '' is the directory containing "rfapi.h" and "rfwin32.lib". * *------------------------------------------------------------------------------- * @version $Revision: 1.1 $ $Date: 2008/04/22 23:58:43 $ * @since 2008-04-20 * @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/rfaxdelegate.cpp $Revision: 1.1 $ $Date: 2008/04/22 23:58:43 $"; static char PROG[] = "rfaxdelegate"; static char TITLE[] = "RFaxDelegate - Manage in-box delegates on a RightFax server"; #ifndef VERS #error Please define macro "VERS" as a string in the format "R.L" #endif static char VERSION[] = VERS; static char VERSION_W[] = "@(#)" "Release: " VERS; static char BUILT[] = "@(#)" "Built: " __DATE__; // System includes #ifndef _WIN32 #error Compile this file for Win32 only #endif #include #include #include #include #include #include #include #define WIN32 #define WIN32_LEAN_AND_MEAN 1 #include #include // Local includes #define rfaxprogram_cpp #include "rfaxprogram.hpp" // Local constants #define OUT_FORMAT 1 // Delegate info output format //------------------------------------------------------------------------------ // Local classes //------------------------------------------------------------------------------ /******************************************************************************* * class RFaxDelegateLister * RightFax server proxy. * * @since 1.1, 2008-04-20 */ #define RFaxDelegateLister_VS 100 // Class version, 1.0 class RFaxDelegateLister: public RFaxProgram { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Constants public: // Program exit status enum ExitCode { RC_OKAY = 0, // Success RC_CONNECT = 1, // Can't connect to server RC_INFO = 2, // Can't retrieve server info RC_WRITE = 3, // Can't write to output file RC_READ = 4, // Can't read from input file RC_USAGE = 255, // Improper command usage }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Static functions public: /*************************************************************************** * Manage in-box delegates on a RightFax server. * * Usage * rfaxdelegate [-option...] [-s] serverID [userID...] * rfaxdelegate [-option...] [-s] serverID userID delegateID * *--------------------------------------------------------------------------- * @param argc * Argument count, i.e., the number of elements in 'argv[]'. * * @param argv * Command line arguments. * * @return * Exit status code, which is one of the RC_XXX constants. * * @since 1.1, 2008-04-20 */ static int main(int argc, const char *argv[]); protected: /*************************************************************************** * Compare two delegate list elements. * * @param e1 * A delegate list element (of type DELEGATELISTELEMENT0). * * @param e2 * Another delegate list element (of type DELEGATELISTELEMENT0). * * @return * A signed result x, where * x < 0 if e1 < e2, or * x = 0 if e1 = e2, or * x > 0 if e1 > e2. * * @since 1.1, 2008-04-20 */ static int cmpElems(const void *e1, const void *e2); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Functions public: /*************************************************************************** * Destructor. * * @since 1.1, 2008-04-20 */ virtual ~RFaxDelegateLister(); /*************************************************************************** * Default constructor. * * @since 1.1, 2008-04-20 */ RFaxDelegateLister(); /*************************************************************************** * List the user delegates on the fax server. * * @param names * Array of user-ID patterns, terminated by a null pointer. * * @return * True if successful, otherwise false. * * @since 1.1, 2008-04-20 */ bool listDelegates(const char *const names[]); /*************************************************************************** * Load in-box delegates from a file to the fax server. * * @param names * Array of user-IDs, terminated by a null pointer. * * @return * True if successful, otherwise false. * * @since 1.1, 2008-04-22 */ bool loadDelegates(const char *const names[]); /*************************************************************************** * Delete delegates on the fax server. * * @param inbox * Delegator in-box user-ID name. * * @param delegs * Delegate names (delegatees of the in-box). * * @return * True if successful, otherwise false. * * @since 1.1, 2008-04-22 */ bool deleteDelegates(const char *inbox, const char *delegs[]); /*************************************************************************** * Add new delegates on the fax server. * * @param inbox * Delegator in-box user-ID name. * * @param delegs * Delegate names granted access to the in-box. * * @param perms * Permissions to grant the delegatee. * * @return * True if successful, otherwise false. * * @since 1.1, 2008-04-22 */ bool addDelegates(const char *inbox, const char *delegs[], const char *perms); protected: /*************************************************************************** * Read a text line from the input file. * * @param line * Text line to read into. * * @param max * Maximum number of characters to write into 'line', including the * terminating null character ('\0'). * * @return * Length of the text line read (which may be zero), or -1 if end of file was * reached. * * @since 1.1, 2008-04-22 */ int readInputLine(char *line, size_t max); private: // Not implemented RFaxDelegateLister(const RFaxDelegateLister &o); // Not implemented const RFaxDelegateLister & operator =(const RFaxDelegateLister &o); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Variables protected: FILE * m_out; // Output stream to write to FILE * m_in; // Input stream to load from bool m_longList; // Long (verbose) listing }; //------------------------------------------------------------------------------ // Local constants //------------------------------------------------------------------------------ static const char PERM_NONE[] = "0002 00000000 00000000 00000000 00000000"; static const char PERM_REVIEWER[] = "0002 0FFFFFFF 00000000 00000000 00000000"; static const char PERM_EDITOR[] = "0002 0FFFFFFF 0FFFFFFF 00000000 0FFFFFF9"; static const char PERM_OWNER[] = "0002 0FFFFFFF 0FFFFFFF 0FFFFFFF 0FFFFFFF"; static const char PERM_ALL[] = "0002 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF"; //------------------------------------------------------------------------------ // Static class functions //------------------------------------------------------------------------------ /******************************************************************************* * RFaxDelegateLister::main() * Manage in-box delegates on a RightFax server. * * Usage * rfaxdelegate [-option...] [-s] serverID [userID...] * rfaxdelegate [-option...] [-s] serverID userID delegateID... * * Options * -s host RightFax server host name or IP address. * -aa Add delegates with all permissions. * -ae Add delegates with editor permissions. * -an Add delegates with no permissions. * -ao Add delegates with owner permissions. * -ar Add delegates with reviewer permissions. * -d Delete delegates. * -l Long (verbose) listing. * -i file Input file to load. * -o file Output file (default is standard output), implies '-l'. * * If no delegator user-IDs are specified, a list of all delegates is printed. * User names may contain '?' and '*' wildcard characters. * An input file to load must be the output file from a previous run. * Deleting a delegate ('-d') requires a delegator and a delegate name. * *------------------------------------------------------------------------------- * @param argc * Argument count, i.e., the number of elements in 'argv[]'. * * @param argv * Command line arguments. * * @since 1.1, 2008-04-20 */ /*static*/ int RFaxDelegateLister::main(int argc, const char *argv[]) { int rc = RC_OKAY; RFaxDelegateLister *srv; const char * server = NULL; const char * optInFile = NULL; const char * optOutFile = NULL; const char * optAdd = NULL; bool optLong = false; bool optDelete = false; FILE * in = NULL; FILE * out = stdout; int i; // Display program version info ::printf("%s\n", TITLE); ::printf("Version %s [%s]\n", VERSION, BUILT+4); ::printf("\n"); ::fflush(stdout); // Parse command line options for (i = 1; i < argc and argv[i][0] == '-'; i++) { if (::stricmp(argv[i], "-?") == 0 or ::stricmp(argv[i], "/?") == 0 or ::stricmp(argv[i], "-help") == 0 or ::stricmp(argv[i], "/help") == 0) goto usage; else if (::strcmp(argv[i], "-aa") == 0) optAdd = PERM_ALL; else if (::strcmp(argv[i], "-ae") == 0) optAdd = PERM_EDITOR; else if (::strcmp(argv[i], "-an") == 0) optAdd = PERM_NONE; else if (::strcmp(argv[i], "-ao") == 0) optAdd = PERM_OWNER; else if (::strcmp(argv[i], "-ar") == 0) optAdd = PERM_REVIEWER; else if (::strcmp(argv[i], "-d") == 0) optDelete = true; else if (::strcmp(argv[i], "-i") == 0 and i+1 < argc) optInFile = argv[++i]; else if (::strcmp(argv[i], "-l") == 0) optLong = true; else if (::strcmp(argv[i], "-o") == 0 and i+1 < argc) optOutFile = argv[++i], optLong = true; else if (::strcmp(argv[i], "-s") == 0 and i+1 < argc) server = argv[++i]; else goto usage; } // Parse command line arguments if (server == NULL and i < argc) server = argv[i++]; // Check options if (optAdd != NULL and (optInFile != NULL or optOutFile != NULL or optDelete)) { ::printf("Add (-a) cannot be used with any other option\n"); goto usage2; } if (optAdd != NULL and i+2 > argc) { ::printf("Add option (-a) requires delegator user-ID and one or more " "delegate names.\n"); goto usage2; } if (optDelete and (optInFile != NULL or optOutFile != NULL)) { ::printf("Delete (-d) cannot be used with any other option\n"); goto usage2; } if (optDelete and i+2 > argc) { ::printf("Delete option (-d) requires delegator user-ID and one or " "more delegate names.\n"); goto usage2; } if (optInFile != NULL and optOutFile != NULL) { ::printf("Only one file option (-i or -o) can be specified\n"); goto usage2; } // Check args if (server == NULL) { usage: // Improper command usage ::printf("Manage in-box delegates on a RightFax server.\n"); usage2: ::printf("\n"); ::printf("usage: %s [-option...] [-s] serverID [userID...]\n", PROG); ::printf(" %s [-option...] [-s] serverID userID delegateID...\n", PROG); ::printf("\n"); ::printf("Options:\n"); ::printf(" -s host RightFax server name or IP address.\n"); ::printf(" -aa Add delegates with all permissions.\n"); ::printf(" -ae Add delegates with editor permissions.\n"); ::printf(" -an Add delegates with no permissions.\n"); ::printf(" -ao Add delegates with owner permissions.\n"); ::printf(" -ar Add delegates with reviewer permissions.\n"); ::printf(" -d Delete delegates.\n"); ::printf(" -l Long (verbose) format.\n"); ::printf(" -i file Input file to load.\n"); ::printf(" -o file Output file (default is standard output).\n"); ::printf("\n"); ::printf("If no delegator user-IDs are specified, a list of all " "delegates is printed.\n"); ::printf("User names may contain '?' and '*' wildcard characters.\n"); ::printf("Adding (-a) or deleting (-d) delegates requires both a " "delegator and a\n" "delegatee user-ID.\n"); ::printf("An input file (-i) to load must be the output file (-o) from " "a previous run.\n"); ::fflush(stdout); return RC_USAGE; } // Open the input file if (optInFile != NULL) { // Load definitions from an input file if (::strcmp(optInFile, "-") == 0) { // Load from stdin in = stdin; } else { // Load from a named file in = ::fopen(optInFile, "r"); if (in == NULL) { ::printf("Can't open/read input file: %s: %s\n", optInFile, ::strerror(errno)); ::fflush(stdin); return RC_READ; } } } // Open the output file if (optOutFile == NULL or ::strcmp(optOutFile, "-") == 0) { // Write results to stdout optOutFile = "-"; out = stdout; } else { // Write results to a file out = ::fopen(optOutFile, "w"); if (out == NULL) { ::printf("Can't open/write output file: %s: %s\n", optOutFile, ::strerror(errno)); ::fflush(stdout); return RC_WRITE; } } // Establish a connection to the RightFax server srv = new RFaxDelegateLister(); srv->m_in = in; srv->m_out = out; srv->m_longList = optLong; ::printf("Server: %s\n", server); ::fflush(stdout); if (not srv->connect(server)) { delete srv; return RC_CONNECT; } ::printf("\n"); ::fflush(stdout); // Manage in-box delegates if (optAdd != NULL) srv->addDelegates(argv[i], argv+i+1, optAdd); else if (optDelete) srv->deleteDelegates(argv[i], argv+i+1); else if (in != NULL) srv->loadDelegates(argv+i); else srv->listDelegates(argv+i); // Clean up if (srv->m_in != NULL) { ::fclose(srv->m_in); srv->m_in = NULL; } if (srv->m_out != stdout) { ::fflush(srv->m_out); ::fclose(srv->m_out); srv->m_out = NULL; } ::printf("\n"); ::fflush(stdout); done: // Disconnect from server srv->disconnect(); delete srv; return rc; } /****************************************************************************** * RFaxDelegateLister::cmpElems() * Compare two delegate list elements. * * @param e1 * A delegate list element (of type DELEGATELISTELEMENT0). * * @param e2 * Another delegate list element (of type DELEGATELISTELEMENT0). * * @return * A signed result x, where * x < 0 if e1 < e2, or * x = 0 if e1 = e2, or * x > 0 if e1 > e2. * * @since 1.1, 2008-04-20 */ /*static*/ int RFaxDelegateLister::cmpElems(const void *e1, const void *e2) { #if RFaxDelegateLister_VS/100 != 1 #error class RFaxDelegateLister has changed #endif const DELEGATELISTELEMENT0 * item1; const DELEGATELISTELEMENT0 * item2; int cmp = 0; // Compare the fax list elements item1 = (const DELEGATELISTELEMENT0 *) e1; item2 = (const DELEGATELISTELEMENT0 *) e2; cmp = ::stricmp(item1->delegator_userid, item2->delegator_userid); if (cmp != 0) return cmp; cmp = ::stricmp(item1->delegate_id, item2->delegate_id); return cmp; } //------------------------------------------------------------------------------ // Class functions //------------------------------------------------------------------------------ /******************************************************************************* * RFaxDelegateLister::~RFaxDelegateLister() * Destructor. * * @since 1.1, 2008-04-20 */ RFaxDelegateLister::~RFaxDelegateLister() { #if RFaxDelegateLister_VS != 100 #error class RFaxDelegateLister has changed #endif // Deallocate if (m_in != NULL) ::fclose(m_in); if (m_out != NULL) { ::fflush(m_out); ::fclose(m_out); } } /******************************************************************************* * RFaxDelegateLister::RFaxDelegateLister() * Default constructor. * * @since 1.1, 2008-04-20 */ RFaxDelegateLister::RFaxDelegateLister(): RFaxProgram() { #if RFaxDelegateLister_VS != 100 #error class RFaxDelegateLister has changed #endif // Initialize } /******************************************************************************* * RFaxDelegateLister::listDelegates() * List the in-box delegates on the fax server. * * @param names * Array of user-IDs, terminated by a null pointer. These names may contain * wildcard ('?' and '*') characters. * * @return * True if successful, otherwise false. * * @since 1.1, 2008-04-20 */ bool RFaxDelegateLister::listDelegates(const char *const names[]) { #if RFaxDelegateLister_VS/100 != 1 #error class RFaxDelegateLister has changed #endif RFAXSERVERHANDLE hdl; RFAXLISTHANDLE listHdl; DELEGATELISTELEMENT0 * elem; char prevUser[80+1]; char prevDeleg[80+1]; int uCount; int dCount; int rc; // Retrieve the list of in-box delegates ::printf("Retrieving in-box delegates list...\n"); ::fflush(stdout); hdl = (RFAXSERVERHANDLE) m_hdl; rc = ::RFaxGetDelegateList(hdl, NULL, NULL, 0, false, &listHdl); if (rc != RFAX_SUCCESS) { ::printf("Can't retrieve delegates list: %s\n", m_serverIP); ::fflush(stdout); return false; } // Sort the list by date order ::printf("Sorting delegates list...\n"); ::fflush(stdout); rc = ::RFaxListSort(listHdl, &cmpElems); if (rc != RFAX_SUCCESS) { ::printf("Can't sort delegates list: %s\n", m_serverIP); ::fflush(stdout); return false; } // Display the in-box delegates list prevUser[0] = '\0'; prevDeleg[0] = '\0'; uCount = 0; dCount = 0; rc = ::RFaxListGetFirstElementPtr(listHdl, (void **)&elem); userLoop: while (rc == RFAX_SUCCESS) { bool isDup; // Check the delegator user-ID against the specified user list if (names != NULL and names[0] != NULL) { int u; // Note: Brute-force O(n**2) search algorithm for (u = 0; names[u] != NULL; u++) if (matchesPattern(elem->delegator_userid, names[u])) break; if (names[u] == NULL) goto nextLoop; } // Adjust counters dCount++; isDup = false; if (::stricmp(prevUser, elem->delegator_userid) != 0) { ::strcpy(prevUser, elem->delegator_userid); uCount++; } else if (::stricmp(prevDeleg, elem->delegate_id) == 0) isDup = true; strcpy(prevDeleg, elem->delegate_id); // Print the delegate info if (m_longList) { #if OUT_FORMAT != 1 #error OUT_FORMAT has changed #endif // Print long (verbose) delegate info if (dCount == 1) ::fprintf(m_out, "FORMAT %d\n", OUT_FORMAT); //if (m_out == stdout) // ::fprintf(m_out, "%4d %4d ", uCount, dCount); ::fprintf(m_out, "%04lX ", elem->ulFlags); ::fprintf(m_out, "%08lX ", elem->ulReadPermissions); ::fprintf(m_out, "%08lX ", elem->ulWritePermissions); ::fprintf(m_out, "%08lX ", elem->ulDeletePermissions); ::fprintf(m_out, "%08lX ", elem->ulMiscPermissions); ::fprintf(m_out, "%s %s", elem->delegator_userid, elem->delegate_id); } else { // Print short delegate info if (m_out == stdout) ::fprintf(m_out, "%4d %4d ", uCount, dCount); ::fprintf(m_out, "%s %s", elem->delegator_userid, elem->delegate_id); } // Check for duplicates if (isDup) ::fprintf(m_out, " *"); ::fprintf(m_out, "\n"); ::fflush(m_out); nextLoop: // Retrieve the next delegate in the list (for the next iteration) rc = ::RFaxListGetNextElementPtr(listHdl, (void **)&elem); } ::fflush(m_out); // Close the list handle ::RFaxCloseListHandle(listHdl); listHdl = NULL; // Success ::printf("delegators:%d, delegates:%d\n", uCount, dCount); ::fflush(stdout); return true; } /******************************************************************************* * RFaxDelegateLister::loadDelegates() * Load in-box delegates from a file to the fax server. * * @param names * Array of user-IDs, terminated by a null pointer. These names may contain * wildcard ('?' and '*') characters. * * @return * True if successful, otherwise false. * * @since 1.1, 2008-04-22 */ bool RFaxDelegateLister::loadDelegates(const char *const names[]) { #if RFaxDelegateLister_VS/100 != 1 #error class RFaxDelegateLister has changed #endif #if OUT_FORMAT != 1 #error OUT_FORMAT has changed #endif RFAXSERVERHANDLE hdl; int nlines = 1; int nadds = 0; int nerrs = 0; char line[2*1024+1]; int rc; // Verify the delegate info input file format if (readInputLine(line, sizeof(line)) < 0) return false; if (::sscanf(line, "FORMAT %d", &rc) < 1 or rc < 0 or rc != OUT_FORMAT) { ::printf("Can't load input file, bad format (not %d): '%s'\n", OUT_FORMAT, line); ::fflush(stdout); return false; } // Load delegate info from the input file hdl = (RFAXSERVERHANDLE) m_hdl; addLoop: while (readInputLine(line, sizeof(line)) >= 0) { unsigned flags; unsigned rperm; unsigned wperm; unsigned dperm; unsigned mperm; char inbox[200+1]; char deleg[200+1]; RFAXLISTHANDLE listHdl; DELEGATEINFO_10 info; DELEGATEINFO_10 prev; int i; // Ignore comment and blank lines nlines++; for (i = 0; line[i] == ' '; i++) continue; if (line[i] == '\0' or line[i] == '#' or line[i] == ';') continue /*addLoop*/; // Extract delegate info from the input line rc = ::sscanf(line, "%x %x %x %x %x %80s %80s", &flags, &rperm, &wperm, &dperm, &mperm, inbox, deleg); if (rc < 7) { ::printf("Malformed delegate info: line %d: '%s'\n", nlines, line); ::fflush(stdout); continue /*addLoop*/; } // Check the delegator user-ID against the specified user list if (names != NULL and names[0] != NULL) { int u; // Note: Brute-force O(n**2) search algorithm for (u = 0; names[u] != NULL; u++) if (matchesPattern(inbox, names[u])) break; if (names[u] == NULL) continue /*addLoop*/; } // Set up a new delegate entry ::memset(&info, 0, sizeof(info)); info.handle = NULL; // To create a new delegate info.ulFlags = flags; info.ulReadPermissions = rperm; info.ulWritePermissions = wperm; info.ulDeletePermissions = dperm; info.ulMiscPermissions = mperm; ::strncpy(info.delegator_userid, inbox, sizeof(info.delegator_userid)-1); ::strncpy(info.delegate_id, deleg, sizeof(info.delegate_id)-1); // Check for truncated names if (::strcmp(info.delegator_userid, inbox) != 0) { nerrs++; ::printf("Delegator name is too long: %s / %s\n", inbox, info.delegator_userid); ::fflush(stdout); continue /*addLoop*/; } if (::strcmp(info.delegate_id, deleg) != 0) { nerrs++; ::printf("Delegate name is too long: %s / %s\n", deleg, info.delegate_id); ::fflush(stdout); continue /*addLoop*/; } // Check if the delegate entry already exists rc = ::RFaxGetDelegateList(hdl, deleg, NULL, 0, false, &listHdl); if (rc == RFAX_SUCCESS) { DELEGATELISTELEMENT0 * elem; int ndels = 0; bool skip = false; // Retrieve the delegate entry from the list rc = ::RFaxListGetFirstElementPtr(listHdl, (void **)&elem); while (rc == RFAX_SUCCESS) { // Check if the inbox/delegate pair is already defined if (::stricmp(elem->delegator_userid, inbox) == 0 and ::stricmp(elem->delegate_id, deleg) == 0) { // Delegate entry already exists on the fax server, ::printf("Replace existing delegate: %s <- %s\n", inbox, deleg); ::fflush(stdout); // Remove the existing delegate entry rc = ::RFaxDeleteDelegate(hdl, elem->handle); if (rc != RFAX_SUCCESS) { ::printf("Can't remove delegate (%d): %s <- %s\n", rc, elem->delegator_userid, elem->delegate_id); ::fflush(stdout); skip = true; } else ndels++; } // Get the next delegate item in the list rc = ::RFaxListGetNextElementPtr(listHdl, (void **)&elem); } // Stop searching the list ::RFaxCloseListHandle(listHdl); listHdl = NULL; if (skip and ndels == 0) continue /*addLoop*/; } // Save/create the new delegate entry to the fax server rc = ::RFaxSaveDelegate(hdl, &info); if (rc == RFAX_SUCCESS) { nadds++; ::printf("Delegate loaded: %s <- %s\n", info.delegator_userid, info.delegate_id); ::fflush(stdout); } else { nerrs++; ::printf("Can't load delegate info (%d): %s <- %s\n", rc, info.delegator_userid, info.delegate_id); ::fflush(stdout); } } // Done ::printf("\n"); ::printf("Delegates added:%d, lines:%d errors:%d\n", nadds, nlines, nerrs); ::fflush(stdout); return true; } /******************************************************************************* * RFaxDelegateLister::deleteDelegates() * Delete delegates on the fax server. * * @param inbox * Delegator in-box user-ID name. * * @param delegs * Delegate names (delegatees of the in-box). * * @return * True if successful, otherwise false. * * @since 1.1, 2008-04-22 */ bool RFaxDelegateLister::deleteDelegates(const char *inbox, const char *delegs[]) { #if RFaxDelegateLister_VS/100 != 1 #error class RFaxDelegateLister has changed #endif RFAXSERVERHANDLE hdl; RFAXLISTHANDLE listHdl; DELEGATELISTELEMENT0 * elem; int rc; // Retrieve the delegate entries for the inbox user-ID from the fax server hdl = (RFAXSERVERHANDLE) m_hdl; rc = ::RFaxGetDelegateList(hdl, NULL, NULL, 0, false, &listHdl); if (rc == RFAX_SUCCESS) { int ndels = 0; // Delete all matching delegate entries rc = ::RFaxListGetFirstElementPtr(listHdl, (void **)&elem); while (rc == RFAX_SUCCESS) { // Check for a matching inbox/delegate pair if (matchesPattern(elem->delegator_userid, inbox)) { // Delete all matching delegate pairs for (int di = 0; delegs[di] != NULL; di++) { if (matchesPattern(elem->delegate_id, delegs[di])) { // Found a matching delegate entry, delete it rc = ::RFaxDeleteDelegate(hdl, elem->handle); if (rc == RFAX_SUCCESS) { ::printf("Delegate removed: %s <- %s\n", elem->delegator_userid, elem->delegate_id); ::fflush(stdout); ndels++; } else { ::printf("Can't remove delegate (%d): %s <- %s\n", rc, elem->delegator_userid, elem->delegate_id); ::fflush(stdout); } break /*for*/; } } } // Get the next delegate entry in the list rc = ::RFaxListGetNextElementPtr(listHdl, (void **)&elem); } // Stop searching the list ::RFaxCloseListHandle(listHdl); listHdl = NULL; ::printf("Delegates removed: %d\n", ndels); ::fflush(stdout); return (ndels > 0); } else { // Can't find any delegates for the inbox user-ID ::printf("Can't retrieve delegates for: %s\n", inbox); ::fflush(stdout); return false; } } /******************************************************************************* * RFaxDelegateLister::addDelegates() * Add new delegates on the fax server. * * @param inbox * Delegator in-box user-ID name. * * @param delegs * Delegate names granted access to the in-box. * * @param perms * Permissions to grant the delegatee. * * @return * True if successful, otherwise false. * * @since 1.1, 2008-04-22 */ bool RFaxDelegateLister::addDelegates(const char *inbox, const char *delegs[], const char *perms) { #if RFaxDelegateLister_VS/100 != 1 #error class RFaxDelegateLister has changed #endif RFAXSERVERHANDLE hdl; unsigned flags; unsigned rperm; unsigned wperm; unsigned dperm; unsigned mperm; int nadds = 0; int nerrs = 0; int di; int rc; // Check that the user-IDs do not contain wildcards if (::strchr(inbox, '*') != NULL or ::strchr(inbox, '?') != NULL) { ::printf("Delegator user-ID to add cannot contain wildcards: %s\n", inbox); return false; } // Extract delegate info from the permissions string rc = ::sscanf(perms, "%x %x %x %x %x", &flags, &rperm, &wperm, &dperm, &mperm); if (rc < 5) { ::printf("Malformed delegate info: '%s'\n", perms); ::fflush(stdout); return false; } // Create new delegates hdl = (RFAXSERVERHANDLE) m_hdl; addLoop: for (di = 0; delegs[di] != NULL; di++) { const char * deleg; RFAXLISTHANDLE listHdl; DELEGATEINFO_10 info; // Check that the delegate user-ID does not contain wildcards deleg = delegs[di]; if (::strchr(deleg, '*') != NULL or ::strchr(deleg, '?') != NULL) { ::printf("Delegatee user-ID to add cannot contain wildcards: %s\n", delegs); ::fflush(stdout); continue /*addLoop*/; } // Set up a new delegate entry ::memset(&info, 0, sizeof(info)); info.handle = NULL; // To create a new delegate info.ulFlags = flags; info.ulReadPermissions = rperm; info.ulWritePermissions = wperm; info.ulDeletePermissions = dperm; info.ulMiscPermissions = mperm; ::strncpy(info.delegator_userid, inbox, sizeof(info.delegator_userid)-1); ::strncpy(info.delegate_id, deleg, sizeof(info.delegate_id)-1); // Check for truncated names if (::strcmp(info.delegator_userid, inbox) != 0) { nerrs++; ::printf("Delegator name is too long: %s / %s\n", inbox, info.delegator_userid); ::fflush(stdout); continue /*addLoop*/; } if (::strcmp(info.delegate_id, deleg) != 0) { nerrs++; ::printf("Delegate name is too long: %s / %s\n", deleg, info.delegate_id); ::fflush(stdout); continue /*addLoop*/; } // Check if the delegate entry already exists rc = ::RFaxGetDelegateList(hdl, deleg, NULL, 0, false, &listHdl); if (rc == RFAX_SUCCESS) { DELEGATELISTELEMENT0 * elem; int ndels = 0; bool skip = false; // Retrieve the delegate entry from the list rc = ::RFaxListGetFirstElementPtr(listHdl, (void **)&elem); while (rc == RFAX_SUCCESS) { // Check if the inbox/delegate pair is already defined if (::stricmp(elem->delegator_userid, inbox) == 0 and ::stricmp(elem->delegate_id, deleg) == 0) { // Delegate entry already exists on the fax server, ::printf("Replace existing delegate: %s <- %s\n", inbox, deleg); ::fflush(stdout); // Remove the existing delegate entry rc = ::RFaxDeleteDelegate(hdl, elem->handle); if (rc != RFAX_SUCCESS) { ::printf("Can't remove delegate (%d): %s <- %s\n", rc, elem->delegator_userid, elem->delegate_id); ::fflush(stdout); skip = true; } else ndels++; } // Get the next delegate item in the list rc = ::RFaxListGetNextElementPtr(listHdl, (void **)&elem); } // Stop searching the list ::RFaxCloseListHandle(listHdl); listHdl = NULL; if (skip and ndels == 0) continue /*addLoop*/; } // Save/create the new delegate entry to the fax server rc = ::RFaxSaveDelegate(hdl, &info); if (rc == RFAX_SUCCESS) { nadds++; ::printf("Delegate loaded: %s <- %s\n", info.delegator_userid, info.delegate_id); ::fflush(stdout); } else { nerrs++; ::printf("Can't load delegate info (%d): %s <- %s\n", rc, info.delegator_userid, info.delegate_id); ::fflush(stdout); } } // Done ::printf("\n"); ::printf("Delegates added:%d, errors:%d\n", nadds, nerrs); ::fflush(stdout); return true; } /******************************************************************************* * RFaxDelegateLister::readInputLine() * Read a text line from the input file. * * @param line * Text line to read into. * * @param max * Maximum number of characters to write into 'line', including the terminating * null character ('\0'). * * @return * Length of the text line read (which may be zero), or -1 if end of file was * reached. * * @since 1.1, 2008-04-22 */ int RFaxDelegateLister::readInputLine(char *line, size_t max) { #if RFaxDelegateLister_VS/100 != 1 #error class RFaxDelegateLister has changed #endif int ch; int len; // Read the next text line if (m_in == NULL) return -1; len = 0; line[0] = '\0'; ch = getc(m_in); if (ch == -1) return -1; for (;;) { // Handle newline if (ch == '\r') { ch = getc(m_in); if (ch != '\n') ungetc(ch, m_in); break; } else if (ch == '\n') break; if (len < max) line[len++] = (char) ch; // Read the next text character ch = getc(m_in); if (ch == -1) break; } // Done line[len] = '\0'; return len; } //------------------------------------------------------------------------------ // Public (non-class) functions //------------------------------------------------------------------------------ /******************************************************************************* * ::main() * Manage in-box delegates on a RightFax server. * *------------------------------------------------------------------------------- * @param argc * Argument count, i.e., the number of elements in 'argv[]'. * * @param argv * Command line arguments. * * @since 1.1, 2008-04-20 */ int main(int argc, char *argv[]) { // Execute this program return RFaxDelegateLister::main(argc, (const char **)argv); } // End rfaxdelegate.cpp