/*
- * "$Id: usersys.c 5182 2006-02-26 04:10:27Z mike $"
+ * "$Id: usersys.c 8498 2009-04-13 17:03:15Z mike $"
*
- * User, system, and password routines for the Common UNIX Printing
- * System (CUPS).
+ * User, system, and password routines for CUPS.
*
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* This file is subject to the Apple OS-Developed Software exception.
*
* Contents:
*
- * cupsEncryption() - Get the default encryption settings.
+ * cupsEncryption() - Get the current encryption settings.
* cupsGetPassword() - Get a password from the user.
- * cupsServer() - Return the hostname of the default server.
+ * cupsGetPassword2() - Get a password from the user using the advanced
+ * password callback.
+ * cupsServer() - Return the hostname/address of the current
+ * server.
* cupsSetEncryption() - Set the encryption preference.
* cupsSetPasswordCB() - Set the password callback for CUPS.
- * cupsSetServer() - Set the default server name.
+ * cupsSetPasswordCB2() - Set the advanced password callback for CUPS.
+ * cupsSetServer() - Set the default server name and port.
* cupsSetUser() - Set the default user name.
- * cupsUser() - Return the current users name.
+ * cupsUser() - Return the current user's name.
* _cupsGetPassword() - Get a password from the user.
- * cups_open_client_conf() - Open the client.conf file.
+ * _cupsSetDefaults() - Set the default server, port, and encryption.
+ * cups_read_client_conf() - Read a client.conf file.
*/
/*
#include <sys/stat.h>
#ifdef WIN32
# include <windows.h>
+#else
+# include <pwd.h>
#endif /* WIN32 */
+#include "debug.h"
/*
* Local functions...
*/
-static cups_file_t *cups_open_client_conf(void);
+static void cups_read_client_conf(cups_file_t *fp,
+ _cups_globals_t *cg,
+ const char *cups_encryption,
+ const char *cups_server);
/*
- * 'cupsEncryption()' - Get the default encryption settings.
+ * 'cupsEncryption()' - Get the current encryption settings.
*
* The default encryption setting comes from the CUPS_ENCRYPTION
- * environment variable, then the ~/.cupsrc file, and finally the
+ * environment variable, then the ~/.cups/client.conf file, and finally the
* /etc/cups/client.conf file. If not set, the default is
- * HTTP_ENCRYPT_IF_REQUESTED.
+ * @code HTTP_ENCRYPT_IF_REQUESTED@.
+ *
+ * Note: The current encryption setting is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the setting via the
+ * @link cupsSetEncryption@ function need to do so in each thread for the same
+ * setting to be used.
*/
http_encryption_t /* O - Encryption settings */
cupsEncryption(void)
{
- cups_file_t *fp; /* client.conf file */
- char *encryption; /* CUPS_ENCRYPTION variable */
- char line[1024], /* Line from file */
- *value; /* Value on line */
- int linenum; /* Line number */
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- /*
- * First see if we have already set the encryption stuff...
- */
-
if (cg->encryption == (http_encryption_t)-1)
- {
- /*
- * Then see if the CUPS_ENCRYPTION environment variable is set...
- */
-
- if ((encryption = getenv("CUPS_ENCRYPTION")) == NULL)
- {
- /*
- * No, open the client.conf file...
- */
-
- fp = cups_open_client_conf();
- encryption = "IfRequested";
-
- if (fp)
- {
- /*
- * Read the config file and look for an Encryption line...
- */
-
- linenum = 0;
-
- while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum) != NULL)
- if (!strcasecmp(line, "Encryption") && value)
- {
- /*
- * Got it!
- */
-
- encryption = value;
- break;
- }
-
- cupsFileClose(fp);
- }
- }
-
- /*
- * Set the encryption preference...
- */
-
- if (!strcasecmp(encryption, "never"))
- cg->encryption = HTTP_ENCRYPT_NEVER;
- else if (!strcasecmp(encryption, "always"))
- cg->encryption = HTTP_ENCRYPT_ALWAYS;
- else if (!strcasecmp(encryption, "required"))
- cg->encryption = HTTP_ENCRYPT_REQUIRED;
- else
- cg->encryption = HTTP_ENCRYPT_IF_REQUESTED;
- }
+ _cupsSetDefaults();
return (cg->encryption);
}
/*
* 'cupsGetPassword()' - Get a password from the user.
*
- * Uses the current password callback function. Returns NULL if the
+ * Uses the current password callback function. Returns @code NULL@ if the
* user does not provide a password.
+ *
+ * Note: The current password callback function is tracked separately for each
+ * thread in a program. Multi-threaded programs that override the setting via
+ * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
+ * do so in each thread for the same function to be used.
*/
const char * /* O - Password */
cupsGetPassword(const char *prompt) /* I - Prompt string */
{
- return ((*_cupsGlobals()->password_cb)(prompt));
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data));
}
/*
- * 'cupsSetEncryption()' - Set the encryption preference.
+ * 'cupsGetPassword2()' - Get a password from the user using the advanced
+ * password callback.
+ *
+ * Uses the current password callback function. Returns @code NULL@ if the
+ * user does not provide a password.
+ *
+ * Note: The current password callback function is tracked separately for each
+ * thread in a program. Multi-threaded programs that override the setting via
+ * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
+ * do so in each thread for the same function to be used.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
*/
-void
-cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
+const char * /* O - Password */
+cupsGetPassword2(const char *prompt, /* I - Prompt string */
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *method, /* I - Request method ("GET", "POST", "PUT") */
+ const char *resource) /* I - Resource path */
{
- _cupsGlobals()->encryption = e;
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (!http)
+ http = _cupsConnect();
+
+ return ((cg->password_cb)(prompt, http, method, resource, cg->password_data));
}
/*
- * 'cupsServer()' - Return the hostname/address of the default server.
+ * 'cupsServer()' - Return the hostname/address of the current server.
*
- * The returned value can be a fully-qualified hostname, a numeric
- * IPv4 or IPv6 address, or a domain socket pathname.
+ * The default server comes from the CUPS_SERVER environment variable, then the
+ * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
+ * set, the default is the local system - either "localhost" or a domain socket
+ * path.
+ *
+ * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
+ * address, or a domain socket pathname.
+ *
+ * Note: The current server is tracked separately for each thread in a program.
+ * Multi-threaded programs that override the server via the
+ * @link cupsSetServer@ function need to do so in each thread for the same
+ * server to be used.
*/
const char * /* O - Server name */
cupsServer(void)
{
- cups_file_t *fp; /* client.conf file */
- char *server; /* Pointer to server name */
- char *port; /* Port number */
- char line[1024], /* Line from file */
- *value; /* Value on line */
- int linenum; /* Line number in file */
-#ifdef CUPS_DEFAULT_DOMAINSOCKET
- struct stat sockinfo; /* Domain socket information */
-#endif /* CUPS_DEFAULT_DOMAINSOCKET */
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- /*
- * First see if we have already set the server name...
- */
-
if (!cg->server[0])
- {
- /*
- * Then see if the CUPS_SERVER environment variable is set...
- */
+ _cupsSetDefaults();
- if ((server = getenv("CUPS_SERVER")) == NULL)
- {
- /*
- * No environment variable, try the client.conf file...
- */
+ return (cg->server);
+}
- fp = cups_open_client_conf();
-#ifdef CUPS_DEFAULT_DOMAINSOCKET
- /*
- * If we are compiled with domain socket support, only use the
- * domain socket if it exists and has the right permissions...
- */
+/*
+ * 'cupsSetEncryption()' - Set the encryption preference.
+ *
+ * The default encryption setting comes from the CUPS_ENCRYPTION
+ * environment variable, then the ~/.cups/client.conf file, and finally the
+ * /etc/cups/client.conf file. If not set, the default is
+ * @code HTTP_ENCRYPT_IF_REQUESTED@.
+ *
+ * Note: The current encryption setting is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the setting need to do
+ * so in each thread for the same setting to be used.
+ */
- if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) &&
- (sockinfo.st_mode & S_IRWXO) == S_IRWXO)
- server = CUPS_DEFAULT_DOMAINSOCKET;
- else
-#endif /* CUPS_DEFAULT_DOMAINSOCKET */
- server = "localhost";
-
- if (fp)
- {
- /*
- * Read the config file and look for a ServerName line...
- */
-
- linenum = 0;
- while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum) != NULL)
- if (!strcasecmp(line, "ServerName") && value)
- {
- /*
- * Got it!
- */
-
- server = value;
- break;
- }
-
- cupsFileClose(fp);
- }
- }
+void
+cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- /*
- * Copy the server name over and set the port number, if any...
- */
- strlcpy(cg->server, server, sizeof(cg->server));
+ cg->encryption = e;
- if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
- !strchr(port, ']') && isdigit(port[1] & 255))
- {
- *port++ = '\0';
+ if (cg->http)
+ httpEncryption(cg->http, e);
+}
- ippSetPort(atoi(port));
- }
- if (cg->server[0] == '/')
- strcpy(cg->servername, "localhost");
- else
- strlcpy(cg->servername, cg->server, sizeof(cg->servername));
- }
+/*
+ * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
+ *
+ * Pass @code NULL@ to restore the default (console) password callback, which
+ * reads the password from the console. Programs should call either this
+ * function or @link cupsSetPasswordCB2@, as only one callback can be registered
+ * by a program per thread.
+ *
+ * Note: The current password callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ */
- return (cg->server);
+void
+cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (cb == (cups_password_cb_t)0)
+ cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
+ else
+ cg->password_cb = (cups_password_cb2_t)cb;
+
+ cg->password_data = NULL;
}
/*
- * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
+ * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
*
- * Pass NULL to restore the default (console) password callback.
+ * Pass @code NULL@ to restore the default (console) password callback, which
+ * reads the password from the console. Programs should call either this
+ * function or @link cupsSetPasswordCB2@, as only one callback can be registered
+ * by a program per thread.
+ *
+ * Note: The current password callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
*/
void
-cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
+cupsSetPasswordCB2(
+ cups_password_cb2_t cb, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
{
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- if (cb == (const char *(*)(const char *))0)
- cg->password_cb = _cupsGetPassword;
+ if (cb == (cups_password_cb2_t)0)
+ cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
else
cg->password_cb = cb;
+
+ cg->password_data = user_data;
}
/*
- * 'cupsSetServer()' - Set the default server name.
+ * 'cupsSetServer()' - Set the default server name and port.
*
* The "server" string can be a fully-qualified hostname, a numeric
- * IPv4 or IPv6 address, or a domain socket pathname. Pass NULL to
- * restore the default server name.
+ * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
+ * addresses can be optionally followed by a colon and port number to override
+ * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
+ * default server name and port.
+ *
+ * Note: The current server is tracked separately for each thread in a program.
+ * Multi-threaded programs that override the server need to do so in each
+ * thread for the same server to be used.
*/
void
{
*port++ = '\0';
- ippSetPort(atoi(port));
+ cg->ipp_port = atoi(port);
}
if (cg->server[0] == '/')
cg->server[0] = '\0';
cg->servername[0] = '\0';
}
+
+ if (cg->http)
+ {
+ httpClose(cg->http);
+ cg->http = NULL;
+ }
}
/*
* 'cupsSetUser()' - Set the default user name.
*
- * Pass NULL to restore the default user name.
+ * Pass @code NULL@ to restore the default user name.
+ *
+ * Note: The current user name is tracked separately for each thread in a
+ * program. Multi-threaded programs that override the user name need to do so
+ * in each thread for the same user name to be used.
*/
void
}
-#if defined(WIN32)
-/*
- * WIN32 username and password stuff.
- */
-
/*
* 'cupsUser()' - Return the current user's name.
+ *
+ * Note: The current user name is tracked separately for each thread in a
+ * program. Multi-threaded programs that override the user name with the
+ * @link cupsSetUser@ function need to do so in each thread for the same user
+ * name to be used.
*/
const char * /* O - User name */
if (!cg->user[0])
{
- DWORD size; /* Size of string */
+#ifdef WIN32
+ /*
+ * Get the current user name from the OS...
+ */
+ DWORD size; /* Size of string */
size = sizeof(cg->user);
if (!GetUserName(cg->user, &size))
+#else
+ /*
+ * Get the user name corresponding to the current UID...
+ */
+
+ struct passwd *pwd; /* User/password entry */
+
+ setpwent();
+ if ((pwd = getpwuid(getuid())) != NULL)
{
/*
- * Use the default username...
+ * Found a match!
*/
+ strlcpy(cg->user, pwd->pw_name, sizeof(cg->user));
+ }
+ else
+#endif /* WIN32 */
+ {
+ /*
+ * Use the default "unknown" user name...
+ */
+
strcpy(cg->user, "unknown");
}
}
const char * /* O - Password */
_cupsGetPassword(const char *prompt) /* I - Prompt string */
{
+#ifdef WIN32
+ /*
+ * Currently no console password support is provided on Windows.
+ */
+
return (NULL);
-}
+
#else
-/*
- * UNIX username and password stuff...
- */
+ /*
+ * Use the standard getpass function to get a password from the console.
+ */
+
+ return (getpass(prompt));
+#endif /* WIN32 */
+}
-# include <pwd.h>
/*
- * 'cupsUser()' - Return the current user's name.
+ * '_cupsSetDefaults()' - Set the default server, port, and encryption.
*/
-const char * /* O - User name */
-cupsUser(void)
+void
+_cupsSetDefaults(void)
{
- struct passwd *pwd; /* User/password entry */
+ cups_file_t *fp; /* File */
+ const char *home, /* Home directory of user */
+ *cups_encryption, /* CUPS_ENCRYPTION env var */
+ *cups_server; /* CUPS_SERVER env var */
+ char filename[1024]; /* Filename */
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- if (!cg->user[0])
+ DEBUG_puts("_cupsSetDefaults()");
+
+ /*
+ * First collect environment variables...
+ */
+
+ cups_encryption = getenv("CUPS_ENCRYPTION");
+ cups_server = getenv("CUPS_SERVER");
+
+ /*
+ * Then, if needed, the .cups/client.conf or .cupsrc file in the home
+ * directory...
+ */
+
+ if ((cg->encryption == (http_encryption_t)-1 || !cg->server[0] ||
+ !cg->ipp_port) && (home = getenv("HOME")) != NULL)
{
/*
- * Rewind the password file...
+ * Look for ~/.cups/client.conf...
*/
- setpwent();
+ snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ cups_read_client_conf(fp, cg, cups_encryption, cups_server);
+ cupsFileClose(fp);
+ }
+ }
+ if (cg->encryption == (http_encryption_t)-1 || !cg->server[0] ||
+ !cg->ipp_port)
+ {
/*
- * Lookup the password entry for the current user.
+ * Look for CUPS_SERVERROOT/client.conf...
*/
- if ((pwd = getpwuid(getuid())) == NULL)
- strcpy(cg->user, "unknown"); /* Unknown user! */
- else
+ snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot);
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ cups_read_client_conf(fp, cg, cups_encryption, cups_server);
+ cupsFileClose(fp);
+ }
+ }
+
+ /*
+ * If we still have things that aren't set, use the compiled in defaults...
+ */
+
+ if (cg->encryption == (http_encryption_t)-1)
+ cg->encryption = HTTP_ENCRYPT_IF_REQUESTED;
+
+ if (!cg->server[0])
+ {
+ if (!cups_server)
{
+#ifdef CUPS_DEFAULT_DOMAINSOCKET
/*
- * Copy the username...
+ * If we are compiled with domain socket support, only use the
+ * domain socket if it exists and has the right permissions...
*/
- setpwent();
+ struct stat sockinfo; /* Domain socket information */
- strlcpy(cg->user, pwd->pw_name, sizeof(cg->user));
+ if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) &&
+ (sockinfo.st_mode & S_IRWXO) == S_IRWXO)
+ cups_server = CUPS_DEFAULT_DOMAINSOCKET;
+ else
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+ cups_server = "localhost";
}
- /*
- * Rewind the password file again...
- */
-
- setpwent();
+ cupsSetServer(cups_server);
}
- return (cg->user);
-}
-
+ if (!cg->ipp_port)
+ {
+ const char *ipp_port; /* IPP_PORT environment variable */
+ struct servent *service; /* Port number info */
-/*
- * '_cupsGetPassword()' - Get a password from the user.
- */
-const char * /* O - Password */
-_cupsGetPassword(const char *prompt) /* I - Prompt string */
-{
- return (getpass(prompt));
+ if ((ipp_port = getenv("IPP_PORT")) != NULL)
+ {
+ if ((cg->ipp_port = atoi(ipp_port)) <= 0)
+ cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
+ }
+ else if ((service = getservbyname("ipp", NULL)) == NULL ||
+ service->s_port <= 0)
+ cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
+ else
+ cg->ipp_port = ntohs(service->s_port);
+ }
}
-#endif /* WIN32 */
/*
- * 'cups_open_client_conf()' - Open the client.conf file.
+ * 'cups_read_client_conf()' - Read a client.conf file.
*/
-static cups_file_t * /* O - File or NULL */
-cups_open_client_conf(void)
+static void
+cups_read_client_conf(
+ cups_file_t *fp, /* I - File to read */
+ _cups_globals_t *cg, /* I - Global data */
+ const char *cups_encryption, /* I - CUPS_ENCRYPTION env var */
+ const char *cups_server) /* I - CUPS_SERVER env var */
{
- cups_file_t *fp; /* File */
- const char *home; /* Home directory of user */
- char filename[1024]; /* Filename */
- _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+ int linenum; /* Current line number */
+ char line[1024], /* Line from file */
+ *value, /* Pointer into line */
+ encryption[1024], /* Encryption value */
+ server_name[1024]; /* ServerName value */
+
+ /*
+ * Read from the file...
+ */
- if ((home = getenv("HOME")) != NULL)
+ linenum = 0;
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
{
- /*
- * Look for ~/.cups/client.conf or ~/.cupsrc...
- */
+ if (!cups_encryption && cg->encryption == (http_encryption_t)-1 &&
+ !strcasecmp(line, "Encryption") && value)
+ {
+ strlcpy(encryption, value, sizeof(encryption));
+ cups_encryption = encryption;
+ }
+ else if (!cups_server && (!cg->server[0] || !cg->ipp_port) &&
+ !strcasecmp(line, "ServerName") && value)
+ {
+ strlcpy(server_name, value, sizeof(server_name));
+ cups_server = server_name;
+ }
+ }
- snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
- if ((fp = cupsFileOpen(filename, "r")) != NULL)
- return (fp);
+ /*
+ * Set values...
+ */
- snprintf(filename, sizeof(filename), "%s/.cupsrc", home);
- if ((fp = cupsFileOpen(filename, "r")) != NULL)
- return (fp);
+ if (cg->encryption == (http_encryption_t)-1 && cups_encryption)
+ {
+ if (!strcasecmp(cups_encryption, "never"))
+ cg->encryption = HTTP_ENCRYPT_NEVER;
+ else if (!strcasecmp(cups_encryption, "always"))
+ cg->encryption = HTTP_ENCRYPT_ALWAYS;
+ else if (!strcasecmp(cups_encryption, "required"))
+ cg->encryption = HTTP_ENCRYPT_REQUIRED;
+ else
+ cg->encryption = HTTP_ENCRYPT_IF_REQUESTED;
}
- snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot);
- return (cupsFileOpen(filename, "r"));
+ if ((!cg->server[0] || !cg->ipp_port) && cups_server)
+ {
+ if (!cg->server[0])
+ {
+ /*
+ * Copy server name...
+ */
+
+ strlcpy(cg->server, cups_server, sizeof(cg->server));
+
+ if (cg->server[0] != '/' && (value = strrchr(cg->server, ':')) != NULL &&
+ !strchr(value, ']') && isdigit(value[1] & 255))
+ *value++ = '\0';
+ else
+ value = NULL;
+
+ if (cg->server[0] == '/')
+ strcpy(cg->servername, "localhost");
+ else
+ strlcpy(cg->servername, cg->server, sizeof(cg->servername));
+ }
+ else if (cups_server[0] != '/' &&
+ (value = strrchr(cups_server, ':')) != NULL &&
+ !strchr(value, ']') && isdigit(value[1] & 255))
+ value ++;
+ else
+ value = NULL;
+
+ if (!cg->ipp_port && value)
+ cg->ipp_port = atoi(value);
+ }
}
/*
- * End of "$Id: usersys.c 5182 2006-02-26 04:10:27Z mike $".
+ * End of "$Id: usersys.c 8498 2009-04-13 17:03:15Z mike $".
*/