]> andersk Git - moira.git/blobdiff - server/qsetup.pc
oops, wrong argument.
[moira.git] / server / qsetup.pc
index 12ab61e62791f6f8639c49595872aa1566dd056d..64e76fb655c2e4128c03fab46e36f3c0eb7b1bd0 100644 (file)
@@ -1,27 +1,29 @@
-/*
- *     $Source$
- *     $Author$
- *     $Header$
+/* $Id$
  *
- *     Copyright (C) 1987 by the Massachusetts Institute of Technology
- *     For copying and distribution information, please see the file
- *     <mit-copyright.h>.
+ * Query setup routines
  *
+ * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
  */
 
-#ifndef lint
-static char *rcsid_qsupport_dc = "$Header$";
-#endif lint
-
 #include <mit-copyright.h>
 #include "mr_server.h"
 #include "query.h"
-#include <ctype.h>
+#include "qrtn.h"
+
 #include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
 EXEC SQL INCLUDE sqlca;
-#include "qrtn.h"
 
-extern char *whoami, *strsave();
+RCSID("$Header$");
+
+extern char *whoami;
 extern int dbms_errno, mr_errcode;
 
 EXEC SQL BEGIN DECLARE SECTION;
@@ -30,9 +32,11 @@ EXEC SQL END DECLARE SECTION;
 
 EXEC SQL WHENEVER SQLERROR DO dbmserr();
 
-
+int hostname_check(char *name);
+int hostinfo_check(char *name, int num);
 int prefetch_value(struct query *q, char **argv, client *cl);
 int check_nfs(int mach_idx, char *name, char *access);
+int check_mailman_listname(char *name, const char *suffix);
 
 /* Setup Routines */
 
@@ -47,134 +51,153 @@ int check_nfs(int mach_idx, char *name, char *access);
  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
  */
 
-int setup_ausr(q, argv, cl)
-     struct query *q;
-     char *argv[];
-     client *cl;
+int setup_ausr(struct query *q, char *argv[], client *cl)
 {
-    int row, err;
-    EXEC SQL BEGIN DECLARE SECTION;
-    int nuid;
-    EXEC SQL END DECLARE SECTION;
-
-    if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
-      row = 2;
-    else
-      row = 1;
-    if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1) {
-       if ((err=set_next_object_id("unix_uid", USERS_TABLE, 1)))
-         return(err);
-       EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
-       if (sqlca.sqlerrd[2] != 1)
-         return(MR_INTERNAL);
-       sprintf(argv[row], "%d", nuid);
+  int row, err;
+  EXEC SQL BEGIN DECLARE SECTION;
+  int nuid;
+  EXEC SQL END DECLARE SECTION;
+
+  if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
+    row = 2;
+  else
+    row = 1;
+
+  if (q->version > 2)
+    {
+      if (strlen(argv[row + 3]) + strlen(argv[row + 4]) +
+         strlen(argv[row + 5]) + 2 > USERS_FULLNAME_SIZE)
+       return MR_ARG_TOO_LONG;
+    }
+  else
+    {
+      if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
+         strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
+       return MR_ARG_TOO_LONG;
     }
 
-    if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1) {
-       sprintf(argv[0], "#%s", argv[row]);
+  if (q->version > 10)
+    {
+      /* For both winhomedir and winprofiledir, we allow values of the
+       * following forms:
+       *
+       * [AFS] - Magic token for AFS home directory.
+       * [LOCAL] - Magic token for AD default local values, i.e. C:\<mumble>
+       * [DFS] - Magic token for DFS home directory
+       * UNC pathname - \\<something>
+       * local pathname - <drive letter>:<something>
+       */
+
+      if ((strcasecmp(argv[row + 12], "[AFS]")) &&
+         (strcasecmp(argv[row + 12], "[LOCAL]")) &&
+         (strcasecmp(argv[row + 12], "[DFS]")) &&
+         (!(argv[row + 12][0] == '\\' && argv[row + 12][1] == '\\')) &&
+         (!(isalpha(*argv[row + 12]) && (argv[row + 12][1] == ':'))))
+       return MR_BAD_CHAR;
+      
+      if ((strcasecmp(argv[row + 13], "[AFS]")) &&
+         (strcasecmp(argv[row + 13], "[LOCAL]")) &&
+         (strcasecmp(argv[row + 13], "[DFS]")) &&
+         (!(argv[row + 13][0] == '\\' && argv[row + 13][1] == '\\')) &&
+         (!(isalpha(*argv[row + 13]) && (argv[row + 13][1] == ':'))))
+       return MR_BAD_CHAR;
     }
 
-    if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
-      return(mr_errcode);
+  if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
+    {
+      if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
+       return err;
+      EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
+      if (sqlca.sqlerrd[2] != 1)
+       return MR_INTERNAL;
+      sprintf(argv[row], "%d", nuid);
+    }
 
-    return(MR_SUCCESS);
-}
+  if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
+    sprintf(argv[0], "#%s", argv[row]);
 
+  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
+    return mr_errcode;
 
-/* setup_dusr - verify that the user is no longer being referenced
- * and may safely be deleted.
- */
+  /* If this is an MR_Q_UPDATE query, we're done. */
+  if (row == 2)
+    return MR_SUCCESS;
 
-int setup_dusr(q, argv)
-     struct query *q;
-     char **argv;
-{
-    EXEC SQL BEGIN DECLARE SECTION;
-    int flag, id, cnt;
-    EXEC SQL END DECLARE SECTION;
-
-    id = *(int *)argv[0];
-
-    /* For now, only allow users to be deleted if their status is 0 */
-    EXEC SQL SELECT status INTO :flag FROM users
-      WHERE users_id = :id;
-    if (flag != 0 && flag != 4)
-      return(MR_IN_USE);
-
-    EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type='USER';
-    EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
-    EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
-      WHERE member_id = :id AND member_type = 'USER';
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys 
-       WHERE owner = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
-      WHERE acl_id = :id AND acl_type = 'USER';
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
-      WHERE acl_id = :id AND acl_type = 'USER';
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
-      WHERE acl_id = :id AND acl_type = 'USER';
-    if (cnt > 0)
-       return(MR_IN_USE);
-    if (dbms_errno)
-       return(mr_errcode);
-    return(MR_SUCCESS);
+  /* For an add query, we need to fill in the creator id. */
+  sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
+  return MR_SUCCESS;
 }
 
 
-/* setup_spop: verify that there is already a valid POP machine_id in the
- * pop_id field.  Also take care of keeping track of the post office usage.
+/* setup_dusr - verify that the user is no longer being referenced
+ * and may safely be deleted.
  */
-int setup_spop(q, argv)
-     struct query *q;
-     char **argv;
+
+int setup_dusr(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int id, mid;
-    char type[9];
-    EXEC SQL END DECLARE SECTION;
-
-    id = *(int *)argv[0];
-    EXEC SQL SELECT potype, pop_id INTO :type, :mid FROM users
-      WHERE users_id = :id;
-    if(sqlca.sqlerrd[2] = 0)
-      return(MR_MACHINE);
-    EXEC SQL SELECT mach_id INTO :mid FROM machine
-      WHERE mach_id = :mid;
-    if (sqlca.sqlerrd[2] = 0)
-      return(MR_MACHINE);
-    if (strcmp(strtrim(type), "POP"))
-      set_pop_usage(mid, 1);
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int flag, id, cnt;
+  char resv[USERS_RESERVATIONS_SIZE];
+  EXEC SQL END DECLARE SECTION;
+
+  id = *(int *)argv[0];
+
+  /* For now, only allow users to be deleted if their status is
+   * one of 0, 4, or 8 (the various registerable statuses)
+   * and we have no reservations about deleting them.
+   */
+  EXEC SQL SELECT status, reservations INTO :flag, :resv
+    FROM users WHERE users_id = :id;
+  if ((flag != 0 && flag != 4 && flag != 8) || *resv)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
+    WHERE member_id = :id AND member_type = 'USER';
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
+    WHERE owner = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
+    WHERE acl_id = :id AND acl_type = 'USER';
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
+    WHERE acl_id = :id AND acl_type = 'USER';
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
+    WHERE acl_id = :id AND acl_type = 'USER';
+  if (cnt > 0)
+    return MR_IN_USE;
+  if (dbms_errno)
+    return mr_errcode;
+
+  EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
+  EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
+  return MR_SUCCESS;
 }
 
 
 /* setup_dpob:  Take care of keeping track of the post office usage.
  */
-int setup_dpob(q, argv)
-     struct query *q;
-     char **argv;
+int setup_dpob(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int id, user;
-    char type[9];
-    EXEC SQL END DECLARE SECTION;
-
-    user = *(int *)argv[0];
-    EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
-      WHERE users_id = :user;
-    if (dbms_errno) return(mr_errcode);
-
-    if (!strcmp(strtrim(type), "POP"))
-      set_pop_usage(id, -1);
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int id, user;
+  char type[USERS_POTYPE_SIZE];
+  EXEC SQL END DECLARE SECTION;
+
+  user = *(int *)argv[0];
+  EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
+    WHERE users_id = :user;
+  if (dbms_errno)
+    return mr_errcode;
+
+  if (!strcmp(strtrim(type), "POP"))
+    set_pop_usage(id, -1);
+  return MR_SUCCESS;
 }
 
 
@@ -182,77 +205,139 @@ int setup_dpob(q, argv)
  * and may safely be deleted.
  */
 
-int setup_dmac(q, argv)
-     struct query *q;
-     char **argv;
+int setup_dmac(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int flag, id, cnt;
-    EXEC SQL END DECLARE SECTION;
-
-    id = *(int *)argv[0];
-
-    EXEC SQL SELECT status INTO :flag FROM machine
-      WHERE mach_id = :id;
-    if (flag != 3)
-      return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
-      WHERE potype='POP' AND pop_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
-      WHERE mach_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
-      WHERE mach_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
-      WHERE mach_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printcap
-      WHERE mach_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(quotaserver) INTO :cnt FROM printcap
-      WHERE quotaserver = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM palladium
-      WHERE mach_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
-      WHERE mach_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-
-    EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
-    if (dbms_errno) return(mr_errcode);
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int flag, id, cnt;
+  EXEC SQL END DECLARE SECTION;
+
+  id = *(int *)argv[0];
+
+  EXEC SQL SELECT status INTO :flag FROM machine
+    WHERE mach_id = :id;
+  if (flag != 3)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
+    WHERE potype = 'POP' AND pop_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
+    WHERE potype = 'EXCHANGE' and exchange_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
+    WHERE mach_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
+    WHERE mach_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
+    WHERE mach_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
+    WHERE mach_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
+    WHERE rm = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
+    WHERE rq = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
+    WHERE mach_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
+    WHERE mach_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
+    WHERE member_type = 'MACHINE' and member_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
+  if (dbms_errno)
+    return mr_errcode;
+
+  EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
+  if (dbms_errno)
+    return mr_errcode;
+  return MR_SUCCESS;
 }
 
+/* setup_asnt - verify that the data entered for the subnet is sane.
+ * In particular, make sure that the "low" and "high" addresses are
+ * correctly ordered, i.e., high > low.
+ */
+
+int setup_asnt(struct query *q, char *argv[], client *cl)
+{
+  int high, low, row, status;
+  char *account_number;
+
+  /* Check for asnt or usnt. */
+  if (q->type == MR_Q_APPEND)
+    row = 0;
+  else
+    row = 1;
+
+  low = atoi(argv[row + 7]);
+  high = atoi(argv[row + 8]);
+  status = atoi(argv[row + 2]);
+  account_number = argv[row + 4];
+  
+  /* Don't allow Private subnets to be created without a valid billing
+   * number.
+   */
+  if (status == SNET_STATUS_PRIVATE_10MBPS || 
+      status == SNET_STATUS_PRIVATE_100MBPS ||
+      status == SNET_STATUS_PRIVATE_1000MBPS)
+    {
+      EXEC SQL SELECT account_number FROM accountnumbers
+       WHERE account_number = :account_number;
+      if (sqlca.sqlcode == SQL_NO_MATCH)
+       return MR_ACCOUNT_NUMBER;
+    }
+      
+  /* Special case 0.0.0.0 and 255.255.255.255 */
+  if (!(low == 0 || low == -1 || high == 0 || high == -1))
+    if (low > high)
+      return MR_ADDRESS;
+
+  /* If this is update_subnet, we're done. */
+  if (row == 1)
+    return MR_SUCCESS;
+
+  /* For an add_subnet query, allocate and fill in a new snet_id */
+  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
+    return mr_errcode;
+
+  return MR_SUCCESS;
+}
 
 /* setup_dsnt - verify that the subnet is no longer being referenced
  * and may safely be deleted.
  */
 
-int setup_dsnt(q, argv)
-     struct query *q;
-     char **argv;
+int setup_dsnt(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int id, cnt = 0;
-    EXEC SQL END DECLARE SECTION;
-
-    id = *(int *)argv[0];
-    EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
-      WHERE snet_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int id, cnt = 0;
+  EXEC SQL END DECLARE SECTION;
+
+  id = *(int *)argv[0];
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
+    WHERE snet_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  return MR_SUCCESS;
 }
 
 
@@ -260,26 +345,24 @@ int setup_dsnt(q, argv)
  * and may safely be deleted.
  */
 
-int setup_dclu(q, argv)
-     struct query *q;
-     char **argv;
+int setup_dclu(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int id, cnt;
-    EXEC SQL END DECLARE SECTION;
-
-    id = *(int *)argv[0];
-    EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
-      WHERE clu_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
-      WHERE clu_id = :id;
-    if (cnt > 0)
-       return(MR_IN_USE);
-    if (dbms_errno)
-       return(mr_errcode);
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int id, cnt;
+  EXEC SQL END DECLARE SECTION;
+
+  id = *(int *)argv[0];
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
+    WHERE clu_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
+    WHERE clu_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+  if (dbms_errno)
+    return mr_errcode;
+  return MR_SUCCESS;
 }
 
 
@@ -289,64 +372,189 @@ int setup_dclu(q, argv)
  * a -1 there.  Remember that this is also used for ulis, with the indexes
  * at 6 & 7.  Also check that the list name does not contain uppercase
  * characters, control characters, @, or :.
+ *
+ *  Newlines in list descriptions do bad things to the aliases file
+ *  moira generates, so make sure the description doesn't contain any, too.
  */
 
 static int badlistchars[] = {
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
-    1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
+  1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 };
 
-int setup_alis(q, argv, cl)
-     struct query *q;
-     char *argv[];
-     client *cl;
+static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
+                                         "-bounces", "-confirm", "-join",
+                                         "-leave", "-subscribe",
+                                         "-unsubscribe", NULL };
+
+int setup_alis(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int ngid;
-    EXEC SQL END DECLARE SECTION;
-    unsigned char *p;
-    int idx, err;
-
-    if (!strcmp(q->shortname, "alis"))
-      idx = 0;
-    else if (!strcmp(q->shortname, "ulis"))
-      idx = 1;
-
-    for (p = (unsigned char *) argv[idx]; *p; p++)
+  EXEC SQL BEGIN DECLARE SECTION;
+  int ngid, cnt, mailman, mailman_id, lid;
+  char *name, *desc;
+  EXEC SQL END DECLARE SECTION;
+  unsigned char *p;
+  int idx, err, best = -1, usage, i;
+
+  if (!strcmp(q->shortname, "alis"))
+    idx = 0;
+  else if (!strcmp(q->shortname, "ulis"))
+    idx = 1;
+  name = argv[idx];
+
+  if (q->version == 2)
+    desc = argv[9 + idx];
+  else if (q->version == 3)
+    desc = argv[10 + idx];
+  else if (q->version == 4)
+    desc = argv[12 + idx];
+  else if (q->version >= 10)
+    desc = argv[14 + idx];
+
+  if (idx == 1)
+    {
+      lid = *(int *)argv[0];
+
+      if (acl_access_check(lid, cl))
+       return MR_PERM;
+    }
+
+  for (p = (unsigned char *) name; *p; p++)
+    {
       if (badlistchars[*p])
-        return(MR_BAD_CHAR);
-    if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1) {
-       if (atoi(argv[5 + idx])) {
-           if ((err=set_next_object_id("gid", LIST_TABLE, 1)))
-             return(err);
-           EXEC SQL SELECT value INTO :ngid FROM numvalues
-             WHERE name = 'gid';
-           if (dbms_errno) return(mr_errcode);
-           sprintf(argv[6 + idx], "%d", ngid);
-       } else {
-           strcpy(argv[6 + idx], "-1");
+       return MR_BAD_CHAR;
+    }
+
+  for (p = (unsigned char *) desc; *p; p++)
+    {
+      if (*p == '\n')
+       return MR_BAD_CHAR;
+    }
+
+  /* Check that it doesn't conflict with a pre-existing weirdly-cased
+   * name. */
+  EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
+    WHERE LOWER(name) = :name AND name != :name;
+  if (cnt)
+    return MR_EXISTS;
+
+  if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
+    {
+      if (atoi(argv[5 + idx]))
+       {
+         if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
+           return err;
+         EXEC SQL SELECT value INTO :ngid FROM numvalues
+           WHERE name = 'gid';
+         if (dbms_errno)
+           return mr_errcode;
+         sprintf(argv[6 + idx], "%d", ngid);
        }
+      else
+       strcpy(argv[6 + idx], "-1");
     }
 
-    if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
-      return(mr_errcode);
+  /* Don't let someone rename a list to one of the magic mailman names
+   * (foo-admin, etc) if foo already exists as a mailman list.
+   */
+  for (i = 0; mailman_suffixes[i]; i++)
+    {
+      if ((err = check_mailman_listname(name, mailman_suffixes[i])) 
+         != MR_SUCCESS)
+       return err;
+    }
+
+  if (q->version >= 10)
+    {
+      /* Don't let them take this name for a mailman list if we can't
+       * reserve the -admin, -owner, and -request names.
+       */
+      if (atoi(argv[8 + idx]))
+       {
+         EXEC SQL SELECT  COUNT(name) INTO :cnt FROM list
+           WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
+                  name = :name || '-request');
+         if (cnt)
+           return MR_EXISTS;
+       }
+
+      /* Handle the [ANY] case for mailman server. */
+      mailman_id = *(int *)argv[9 + idx];
+      if (mailman_id == -1)
+       {
+         EXEC SQL DECLARE csr_mailman CURSOR FOR
+           SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN'
+           AND enable = 1;
+         if (dbms_errno)
+           return mr_errcode;
+         EXEC SQL OPEN csr_mailman;
+         if (dbms_errno)
+           return mr_errcode;
+
+         while (1)
+           {
+             EXEC SQL FETCH csr_mailman INTO :mailman_id;
+             if (sqlca.sqlcode)
+               break;
+             
+             EXEC SQL SELECT COUNT(name) INTO :usage FROM list
+               WHERE mailman_id = :mailman_id;
+
+             if (best < 0 || usage < best)
+               {
+                 best = usage;
+                 *(int *)argv[9 + idx] = mailman_id;
+                 break;
+               }
+           }
+         EXEC SQL CLOSE csr_mailman;
+         if (dbms_errno)
+           return mr_errcode;
+
+         if (best == -1)
+           return MR_SERVICE;
+       }
+    }
+  else
+    {
+      /* Client too old to know about the mailman code.
+       * Use existing value of mailman boolean in the table.
+       * Don't do this for add_list from an old client, since the row
+       * they're creating won't exist yet, and there's no way for them to
+       * create a list with the mailman bit set, anyway.
+       */
+      if (idx == 1)
+       {
+         EXEC SQL SELECT mailman INTO :mailman FROM list WHERE list_id = :lid;
+         if (mailman)
+           {
+             EXEC SQL SELECT  COUNT(name) INTO :cnt FROM list
+               WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
+                      name = :name || '-request');
+             if (cnt)
+               return MR_EXISTS;
+           }
+       }
+    }
 
-    return(MR_SUCCESS);
+  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
+    return mr_errcode;
+
+  return MR_SUCCESS;
 }
 
 
@@ -354,59 +562,94 @@ int setup_alis(q, argv, cl)
  * and may safely be deleted.
  */
 
-int setup_dlis(q, argv)
-     struct query *q;
-     char *argv[];
+int setup_dlis(struct query *q, char *argv[], client *cl)
 {
-    int id;
-    EXEC SQL BEGIN DECLARE SECTION;
-    int cnt;
-    EXEC SQL END DECLARE SECTION;
-
-    id = *(int *)argv[0];
-
-    EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
-      WHERE member_id = :id AND member_type='LIST';
-    if(cnt>0) return MR_IN_USE;
-
-    EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
-      WHERE member_id = :id AND member_type='LIST';
-    if(cnt>0) return MR_IN_USE;
-    
-    EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
-      WHERE list_id = :id;
-    if(cnt>0) return MR_IN_USE;
-
-    EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
-    if(cnt>0) return MR_IN_USE;
-
-    EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
-    if(cnt>0) return MR_IN_USE;
-
-    EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
-      WHERE acl_id = :id AND acl_type='LIST' AND list_id != :id;
-    if(cnt>0) return MR_IN_USE;
-
-    EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
-      WHERE acl_id = :id AND acl_type='LIST';
-    if(cnt>0) return MR_IN_USE;
-
-    EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
-      WHERE entity_id = :id AND type='GROUP';
-    if(cnt>0) return MR_IN_USE;
-    EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
-      WHERE acl_id = :id AND acl_type='LIST';
-    if(cnt>0) return MR_IN_USE;
-
-    EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
-      WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
-      OR z.sub_type = 'LIST' AND z.sub_id = :id
-      OR z.iws_type = 'LIST' AND z.iws_id = :id
-      OR z.iui_type = 'LIST' AND z.iui_id = :id;
-    if(cnt>0) return MR_IN_USE;
-
-    return(MR_SUCCESS);
+  int id;
+  EXEC SQL BEGIN DECLARE SECTION;
+  int cnt;
+  EXEC SQL END DECLARE SECTION;
+
+  id = *(int *)argv[0];
+
+  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
+    WHERE member_id = :id AND member_type = 'LIST';
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
+    WHERE member_id = :id AND member_type = 'LIST';
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
+    WHERE list_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
+    WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
+    WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
+    WHERE acl_id = :id AND acl_type = 'LIST';
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
+    WHERE entity_id = :id AND type = 'GROUP';
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
+    WHERE acl_id = :id AND acl_type = 'LIST';
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
+    WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
+    OR z.sub_type = 'LIST' AND z.sub_id = :id
+    OR z.iws_type = 'LIST' AND z.iws_id = :id
+    OR z.iui_type = 'LIST' AND z.iui_id = :id
+    OR z.owner_type = 'LIST' and z.owner_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
+    WHERE lpc_acl = :id OR ac = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
+    WHERE owner_type = 'LIST' AND owner_id = :id
+    OR lpc_acl = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT count(name) INTO :cnt FROM containers
+    WHERE acl_id = :id AND acl_type = 'LIST';
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT count(name) INTO :cnt FROM containers
+    WHERE memacl_id = :id AND memacl_type = 'LIST';
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  return MR_SUCCESS;
 }
 
 
@@ -414,28 +657,27 @@ int setup_dlis(q, argv)
  * and may safely be deleted.
  */
 
-int setup_dsin(q, argv)
-     struct query *q;
-     char **argv;
+int setup_dsin(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;     
-    int ec, cnt;
-    char *svrname;
-    EXEC SQL END DECLARE SECTION;
-
-    svrname=argv[0];
-    EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
-      WHERE service = UPPER(:svrname);
-    if(cnt>0) return MR_IN_USE;
-
-    EXEC SQL SELECT inprogress INTO :ec FROM servers 
-      WHERE name=UPPER(:svrname);
-    if(dbms_errno) 
-       return(mr_errcode);
-    if(ec) 
-       return(MR_IN_USE); 
-
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int ec, cnt;
+  char *svrname;
+  EXEC SQL END DECLARE SECTION;
+
+  svrname = argv[0];
+  EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
+    WHERE service = UPPER(:svrname);
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  EXEC SQL SELECT inprogress INTO :ec FROM servers
+    WHERE name = UPPER(:svrname);
+  if (dbms_errno)
+    return mr_errcode;
+  if (ec)
+    return MR_IN_USE;
+
+  return MR_SUCCESS;
 }
 
 
@@ -443,27 +685,24 @@ int setup_dsin(q, argv)
  * and may safely be deleted.
  */
 
-int setup_dshi(q, argv)
-     struct query *q;
-     char **argv;
+int setup_dshi(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int id, ec;
-    char *svrname;
-    EXEC SQL END DECLARE SECTION;
-
-    svrname=argv[0];
-    id = *(int *)argv[1];
-
-    EXEC SQL SELECT inprogress INTO :ec FROM serverhosts 
-      WHERE service=UPPER(:svrname) AND mach_id = :id;
-    if(dbms_errno) 
-       return(mr_errcode);
-    if(ec) 
-       return(MR_IN_USE); 
-
-
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int id, ec;
+  char *svrname;
+  EXEC SQL END DECLARE SECTION;
+
+  svrname = argv[0];
+  id = *(int *)argv[1];
+
+  EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
+    WHERE service = UPPER(:svrname) AND mach_id = :id;
+  if (dbms_errno)
+    return mr_errcode;
+  if (ec)
+    return MR_IN_USE;
+
+  return MR_SUCCESS;
 }
 
 
@@ -479,7 +718,7 @@ int setup_dshi(q, argv)
  ** Description:
  **   - for type = RVD:
  **       * allow anything
- **   - for type = NFS:
+ **   - for type = NFS/IMAP:
  **        * extract directory prefix from name
  **        * verify mach_id/dir in nfsphys
  **        * verify rwaccess in {r, w, R, W}
@@ -497,37 +736,36 @@ EXEC SQL BEGIN DECLARE SECTION;
 int _var_phys_id;
 EXEC SQL END DECLARE SECTION;
 
-int setup_afil(q, argv, cl)
-     struct query *q;
-     char *argv[];
-     client *cl;
+int setup_afil(struct query *q, char *argv[], client *cl)
 {
-    char *type, *name;
-    int mach_id;
-    EXEC SQL BEGIN DECLARE SECTION;
-    int ok;
-    char ftype[32], *rwaccess;
-    EXEC SQL END DECLARE SECTION;
-
-    type = argv[1];
-    mach_id = *(int *)argv[2];
-    name = argv[3];
-    rwaccess = argv[5];
-    _var_phys_id = 0;
-
-    sprintf(ftype, "fs_access_%s", type);
-    EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
-       WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
-    if (dbms_errno) return(mr_errcode);
-    if (ok == 0) return(MR_FILESYS_ACCESS);
-
-    if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
-      return(mr_errcode);
-
-    if (!strcmp(type, "NFS"))
-       return (check_nfs(mach_id, name, rwaccess));
-
-    return(MR_SUCCESS);
+  char *type, *name;
+  int mach_id;
+  EXEC SQL BEGIN DECLARE SECTION;
+  int ok;
+  char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
+  EXEC SQL END DECLARE SECTION;
+
+  type = argv[1];
+  mach_id = *(int *)argv[2];
+  name = argv[3];
+  rwaccess = argv[5];
+  _var_phys_id = 0;
+
+  sprintf(ftype, "fs_access_%s", type);
+  EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
+    WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
+  if (dbms_errno)
+    return mr_errcode;
+  if (ok == 0)
+    return MR_FILESYS_ACCESS;
+
+  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
+    return mr_errcode;
+
+  if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
+    return check_nfs(mach_id, name, rwaccess);
+
+  return MR_SUCCESS;
 }
 
 
@@ -536,68 +774,73 @@ int setup_afil(q, argv, cl)
  * the new phys_id.
  */
 
-int setup_ufil(q, argv, cl)
-     struct query *q;
-     char *argv[];
-     client *cl;
+int setup_ufil(struct query *q, char *argv[], client *cl)
 {
-    int mach_id, status;
-    char *type, *name;
-    EXEC SQL BEGIN DECLARE SECTION;
-    int fid, total, who, ok;
-    char *entity, ftype[32], *access;
-    short int total_null;
-    EXEC SQL END DECLARE SECTION;
-
-    _var_phys_id = 0;
-    type = argv[2];
-    mach_id = *(int *)argv[3];
-    name = argv[4];
-    access = argv[6];
-    fid = *(int *)argv[0];
-    who = cl->client_id;
-    entity = cl->entity;
-
-    sprintf(ftype, "fs_access_%s", type);
-    EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
-      WHERE name = :ftype AND type='TYPE' AND trans = :access;
-    if (dbms_errno) return(mr_errcode);
-    if (ok == 0) return(MR_FILESYS_ACCESS);
-
-    EXEC SQL SELECT type INTO :ftype FROM filesys
-      WHERE filsys_id = :fid;
-    if (dbms_errno) return(mr_errcode);
-
-    if (!strcmp(type, "NFS")) {
-       status = check_nfs(mach_id, name, access);
-       EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
-         WHERE filsys_id = :fid;
-       if (dbms_errno) return(mr_errcode);
-       return(status);
-    } else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")) {
-       total = 0;
-       EXEC SQL DELETE FROM quota
-         WHERE type = 'ANY' AND filsys_id = :fid;
-       EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
-         WHERE filsys_id = :fid AND phys_id != 0;
-       if (dbms_errno) return(mr_errcode);
-       if (!total_null && (total != 0)) {
-/*
- *             append quota (quota = total, filsys_id = fid,
- *                          phys_id = 0, entity_id = 0, type = "ANY",
- *                          modtime = "now", modby = who, modwith = entity)
- */
-           EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
-                                       type, modtime, modby, modwith)
-             VALUES (:total, :fid, 0, 0,
-                     'ANY', SYSDATE, :who, :entity) ;
-           if (dbms_errno) return(mr_errcode);
+  int mach_id, status;
+  char *type, *name;
+  EXEC SQL BEGIN DECLARE SECTION;
+  int fid, total, who, ok;
+  char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
+  short int total_null;
+  EXEC SQL END DECLARE SECTION;
+
+  _var_phys_id = 0;
+  type = argv[2];
+  mach_id = *(int *)argv[3];
+  name = argv[4];
+  access = argv[6];
+  fid = *(int *)argv[0];
+  who = cl->client_id;
+  entity = cl->entity;
+
+  sprintf(ftype, "fs_access_%s", type);
+  EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
+    WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
+  if (dbms_errno)
+    return mr_errcode;
+  if (ok == 0)
+    return MR_FILESYS_ACCESS;
+
+  EXEC SQL SELECT type INTO :ftype FROM filesys
+    WHERE filsys_id = :fid;
+  if (dbms_errno)
+    return mr_errcode;
+
+  if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
+    {
+      status = check_nfs(mach_id, name, access);
+      EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
+       WHERE filsys_id = :fid;
+      if (dbms_errno)
+       return mr_errcode;
+      return status;
+    }
+  else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
+          && strcmp(strtrim(ftype), "ERR"))
+    {
+      total = 0;
+      EXEC SQL DELETE FROM quota
+       WHERE type = 'ANY' AND filsys_id = :fid;
+      EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
+       WHERE filsys_id = :fid AND phys_id != 0;
+      if (dbms_errno)
+       return mr_errcode;
+      if (!total_null && (total != 0))
+       {
+         EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
+                                     type, modtime, modby, modwith)
+           VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
+         if (dbms_errno)
+           return mr_errcode;
        }
-    } else {
-       EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
-       if (dbms_errno) return(mr_errcode);
     }
-    return(MR_SUCCESS);
+  else
+    {
+      EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
+      if (dbms_errno)
+       return mr_errcode;
+    }
+  return MR_SUCCESS;
 }
 
 
@@ -607,47 +850,49 @@ int setup_ufil(q, argv, cl)
  * more than one, we sort the query in reverse order by dir name.
  */
 
-int check_nfs(mach_id, name, access)
-EXEC SQL BEGIN DECLARE SECTION;
-    int mach_id;
-EXEC SQL END DECLARE SECTION;
-    char *name, *access;
+int check_nfs(int mach_id, char *name, char *access)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    char dir[81];
-    EXEC SQL END DECLARE SECTION;
-    register int status;
-    register char *cp1;
-    register char *cp2;
-
-    status = MR_NFS;
-    EXEC SQL DECLARE csr101 CURSOR FOR
-      SELECT nfsphys_id, dir FROM nfsphys
-       WHERE mach_id = :mach_id
-       ORDER BY 2 DESC;
-    if (dbms_errno)
-       return(mr_errcode);
-    EXEC SQL OPEN csr101;
-    if (dbms_errno)
-       return(mr_errcode);
-    while(1) {
-       EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
-       if(sqlca.sqlcode != 0) break;
-       cp1 = name;
-       cp2 = strtrim(dir);
-       while (*cp2) {
-           if (*cp1++ != *cp2) break;
-           cp2++;
-       }
-       if (*cp2 == 0) {
-           status = MR_SUCCESS;
+  EXEC SQL BEGIN DECLARE SECTION;
+  char dir[NFSPHYS_DIR_SIZE];
+  int mid = mach_id;
+  EXEC SQL END DECLARE SECTION;
+  int status;
+  char *cp1;
+  char *cp2;
+
+  status = MR_NFS;
+  EXEC SQL DECLARE csr101 CURSOR FOR
+    SELECT nfsphys_id, dir FROM nfsphys
+    WHERE mach_id = :mid
+    ORDER BY 2 DESC;
+  if (dbms_errno)
+    return mr_errcode;
+  EXEC SQL OPEN csr101;
+  if (dbms_errno)
+    return mr_errcode;
+  while (1)
+    {
+      EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
+      if (sqlca.sqlcode)
+       break;
+      cp1 = name;
+      cp2 = strtrim(dir);
+      while (*cp2)
+       {
+         if (*cp1++ != *cp2)
            break;
+         cp2++;
+       }
+      if (!*cp2)
+       {
+         status = MR_SUCCESS;
+         break;
        }
     }
-    EXEC SQL CLOSE csr101;
-    if (dbms_errno)
-       return(mr_errcode);
-    return(status);
+  EXEC SQL CLOSE csr101;
+  if (dbms_errno)
+    return mr_errcode;
+  return status;
 }
 
 
@@ -655,35 +900,33 @@ EXEC SQL END DECLARE SECTION;
  * a filesystem when it is deleted.  Also adjust the allocation numbers.
  */
 
-int setup_dfil(q, argv, cl)
-     struct query *q;
-     char **argv;
-     client *cl;
+int setup_dfil(struct query *q, char **argv, client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int id, total, phys_id;
-    short int none;
-    EXEC SQL END DECLARE SECTION;
-
-    id = *(int *)argv[0];
-    EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
-      WHERE filsys_id = :id;
-
-    if(none) total=0;
-
-    /** What if there are multiple phys_id's per f/s? (bad data) **/
-    EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
-      WHERE filsys_id = :id;
-    EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
-      WHERE nfsphys_id = :phys_id;
-
-    if(!none) {
-       EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
-    }
-    EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
-    EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
-    if (dbms_errno) return(mr_errcode);
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int id, total, phys_id;
+  short int none;
+  EXEC SQL END DECLARE SECTION;
+
+  id = *(int *)argv[0];
+  EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
+    WHERE filsys_id = :id;
+
+  if (none)
+    total = 0;
+
+  /** What if there are multiple phys_id's per f/s? (bad data) **/
+  EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
+    WHERE filsys_id = :id;
+  EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
+    WHERE nfsphys_id = :phys_id;
+
+  if (!none)
+    EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
+  EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
+  EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
+  if (dbms_errno)
+    return mr_errcode;
+  return MR_SUCCESS;
 }
 
 
@@ -691,26 +934,23 @@ int setup_dfil(q, argv, cl)
  * any filesystems assigned to it before allowing it to be deleted.
  */
 
-int setup_dnfp(q, argv, cl)
-     struct query *q;
-     char **argv;
-     client *cl;
+int setup_dnfp(struct query *q, char **argv, client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int id, cnt;
-    char *dir;
-    EXEC SQL END DECLARE SECTION;
-
-    id = *(int *)argv[0];
-    dir = argv[1];
-    EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
-      WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
-       AND np.mach_id = :id AND np.dir = :dir;
-    if (cnt > 0)
-      return(MR_IN_USE);
-    if (dbms_errno)
-      return(mr_errcode);
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  int id, cnt;
+  char *dir;
+  EXEC SQL END DECLARE SECTION;
+
+  id = *(int *)argv[0];
+  dir = argv[1];
+  EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
+    WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
+    AND np.mach_id = :id AND np.dir = :dir;
+  if (cnt > 0)
+    return MR_IN_USE;
+  if (dbms_errno)
+    return mr_errcode;
+  return MR_SUCCESS;
 }
 
 
@@ -720,60 +960,35 @@ int setup_dnfp(q, argv, cl)
  *   argv[2 or 1] = users_id or list_id
  */
 
-int setup_dqot(q, argv, cl)
-     struct query *q;
-     char **argv;
-     client *cl;
+int setup_dqot(struct query *q, char **argv, client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int quota, fs, id, physid;
-    char *qtype;
-    EXEC SQL END DECLARE SECTION;
-
-    fs = *(int *)argv[0];
-    if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
-       qtype = argv[1];
-       id = *(int *)argv[2];
-    } else {
-       qtype = "USER";
-       id = *(int *)argv[1];
+  EXEC SQL BEGIN DECLARE SECTION;
+  int quota, fs, id, physid;
+  char *qtype;
+  EXEC SQL END DECLARE SECTION;
+
+  fs = *(int *)argv[0];
+  if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
+    {
+      qtype = argv[1];
+      id = *(int *)argv[2];
+    }
+  else
+    {
+      qtype = "USER";
+      id = *(int *)argv[1];
     }
 
-    EXEC SQL SELECT quota INTO :quota FROM quota
-      WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
-    EXEC SQL SELECT phys_id INTO :physid FROM filesys 
-      WHERE filsys_id = :fs;
-    EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
-      WHERE nfsphys_id = :physid;
+  EXEC SQL SELECT quota INTO :quota FROM quota
+    WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
+  EXEC SQL SELECT phys_id INTO :physid FROM filesys
+    WHERE filsys_id = :fs;
+  EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
+    WHERE nfsphys_id = :physid;
 
-    if (dbms_errno) return(mr_errcode);
-    return(MR_SUCCESS);
-}
-
-
-/* setup add_kerberos_user_mapping: add the string to the string
- * table if necessary.
- */
-
-int setup_akum(q, argv, cl)
-     struct query *q;
-     char **argv;
-     client *cl;
-{
-    EXEC SQL BEGIN DECLARE SECTION;
-    int id;
-    char *name;
-    EXEC SQL END DECLARE SECTION;
-
-    name = argv[1];
-    if (name_to_id(name, STRINGS_TABLE, &id) != MR_SUCCESS) {
-       if (q->type != APPEND) return(MR_STRING);
-       id=add_string(name);
-       cache_entry(name, STRINGS_TABLE, id);
-    }
-    if (dbms_errno) return(mr_errcode);
-    *(int *)argv[1] = id;
-    return(MR_SUCCESS);
+  if (dbms_errno)
+    return mr_errcode;
+  return MR_SUCCESS;
 }
 
 
@@ -782,41 +997,40 @@ int setup_akum(q, argv, cl)
  * It is a little hack to get around the fact that SQL doesn't let you
  * do something like INSERT INTO table (foo) VALUES (other_table.bar).
  *
- * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
+ * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
  * from within a setup_...() routine with the appropriate arguments.
  *
  * Correct functioning of this routine may depend on the assumption
- * that this query is an APPEND.
+ * that this query is an MR_Q_APPEND.
  */
 
-int prefetch_value(q, argv, cl)
-     struct query *q;
-     char **argv;
-     client *cl;
+int prefetch_value(struct query *q, char **argv, client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    char *name = q->validate->object_id;
-    int value;
-    EXEC SQL END DECLARE SECTION;
-    int status, limit, argc;
-
-    /* set next object id, limiting it if necessary */
-    if(!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
-      limit = 1; /* So far as I know, this isn't needed.  Just CMA. */
-    else
-      limit = 0;
-    if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
-      return(status);
-
-    /* fetch object id */
-    EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
-    if(dbms_errno) return(mr_errcode);
-    if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
-
-    argc = q->argc + q->vcnt;   /* end of Argv for APPENDs */
-    sprintf(argv[argc],"%d",value);  /** Could save this step by changing tlist from %s to %d **/
-
-    return(MR_SUCCESS);
+  EXEC SQL BEGIN DECLARE SECTION;
+  char *name = q->validate->object_id;
+  int value;
+  EXEC SQL END DECLARE SECTION;
+  int status, limit, argc;
+
+  /* set next object id, limiting it if necessary */
+  if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
+    limit = 1; /* So far as I know, this isn't needed.  Just CMA. */
+  else
+    limit = 0;
+  if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
+    return status;
+
+  /* fetch object id */
+  EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
+  if (dbms_errno)
+    return mr_errcode;
+  if (sqlca.sqlerrd[2] != 1)
+    return MR_INTERNAL;
+
+  argc = q->argc + q->vcnt;   /* end of Argv for MR_Q_APPENDs */
+  sprintf(argv[argc], "%d", value);
+
+  return MR_SUCCESS;
 }
 
 /* prefetch_filesys():
@@ -828,286 +1042,611 @@ int prefetch_value(q, argv, cl)
  * Assumes the existence of a row where filsys_id = argv[0], since a
  * filesys label has already been resolved to a filsys_id.
  */
-int prefetch_filesys(q, argv, cl)
-     struct query *q;
-     char **argv;
-     client *cl;
+int prefetch_filesys(struct query *q, char **argv, client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    int fid,phid;
-    EXEC SQL END DECLARE SECTION;
-    int argc;
+  EXEC SQL BEGIN DECLARE SECTION;
+  int fid, phid;
+  EXEC SQL END DECLARE SECTION;
+  int argc;
 
-    fid = *(int *)argv[0];
-    EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
-    if(dbms_errno) return(mr_errcode);
+  fid = *(int *)argv[0];
+  EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
+  if (dbms_errno)
+    return mr_errcode;
 
-    argc=q->argc+q->vcnt;
-    sprintf(argv[argc++],"%d",phid);
-    sprintf(argv[argc],"%d",fid);
+  argc = q->argc + q->vcnt;
+  sprintf(argv[argc++], "%d", phid);
+  sprintf(argv[argc], "%d", fid);
 
-    return(MR_SUCCESS);
+  return MR_SUCCESS;
 }
 
 
+/* setup_ghst():
+ */
+
+int setup_ghst(struct query *q, char **argv, client *cl)
+{
+  if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
+      strcmp(argv[2], "*") || strcmp(argv[3], "*"))
+    return MR_SUCCESS;
+  else
+    return MR_PERM;
+}
+
 /* setup_ahst():
  */
 
-int setup_ahst(q, argv, cl)
-     struct query *q;
-     char **argv;
-     client *cl;
+int setup_ahst(struct query *q, char **argv, client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    char *name;
-    int value, id, saddr, mask, high, low, cnt;
-    EXEC SQL END DECLARE SECTION;
-    int row;
-    struct in_addr addr;
-    extern int host_access_level, privileged;
-
-    if (!strcmp(q->shortname, "uhst"))
+  EXEC SQL BEGIN DECLARE SECTION;
+  char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
+  char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
+  int value, id, ssaddr, smask, shigh, slow, cnt;
+  unsigned int saddr, mask, high, low;
+  EXEC SQL END DECLARE SECTION;
+  int row, idx;
+  struct in_addr addr;
+
+  id = *(int *)argv[0];
+
+  if (!strcmp(q->shortname, "uhst"))
+    {
       row = 1;
-    else
-      row = 0;
-
-    /* sanity check name: must start with a letter, contain only
-     * letters, numerals, and hyphen, and not end with a hyphen.
-     */
-    if (row == 0 || strcmp(argv[1], cl->args->mr_argv[1])) {
-       char *p = argv[row];
-
-       if (!isalpha(*p)) return(MR_BAD_CHAR);
-       for (; *p; p++) {
-           if ((!isalnum(*p) && *p != '-' && *p != '.') ||
-               (*p == '-' && p[1] == '.'))
-             return(MR_BAD_CHAR);
+      EXEC SQL SELECT name, vendor, model, os
+       INTO :oldname, :vendor, :model, :os
+       FROM machine WHERE mach_id = :id;
+    }
+  else
+    row = 0;
+
+  if (q->version < 6)
+    idx = 0;
+  else if (q->version >= 6 && q->version < 8)
+    idx = 1;
+  else
+    idx = 2;
+
+  /* Sanity check name, vendor, model, and os. */
+  if ((row == 0 || strcasecmp(argv[1], oldname)) &&
+      !hostname_check(argv[row]))
+    return MR_BAD_CHAR;
+  if ((row == 0 || strcasecmp(argv[2], vendor)) &&
+      !hostinfo_check(argv[row + 1], 0))
+    return MR_BAD_CHAR;
+  if ((row == 0 || strcasecmp(argv[3], model)) &&
+      !hostinfo_check(argv[row + 2], 1))
+    return MR_BAD_CHAR;
+  if ((row == 0 || strcasecmp(argv[4], os)) &&
+      !hostinfo_check(argv[row + 3], 0))
+    return MR_BAD_CHAR;
+
+  /* check for duplicate name */
+  name = argv[row];
+  EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
+    WHERE name = UPPER(:name);
+  if (dbms_errno)
+    return mr_errcode;
+  if (cnt != 0)
+    return MR_EXISTS;
+
+  /* check address */
+  if (!strcmp(argv[9 + row + idx], "unassigned"))
+    value = -1;
+  else if (!strcmp(argv[9 + row + idx], "unique"))
+    {
+      if (*(int *)argv[8 + row + idx] == 0)
+       value = -1;
+      else
+       value = -2;
+    }
+  else
+    {
+      value = ntohl(inet_addr(argv[9 + row + idx]));
+      if (value == -1)
+       return MR_ADDRESS;
+    }
+  if (value == 0)
+    return MR_ADDRESS;
+  if (value != -1)
+    {
+      /*
+       * an address or unique was specified.
+       */
+      id = *(int *)argv[8 + row + idx];
+      EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
+       :shigh, :slow FROM subnet WHERE snet_id = :id;
+      if (dbms_errno)
+       return mr_errcode;
+      saddr = (unsigned) ssaddr;
+      mask = (unsigned) smask;
+      high = (unsigned) shigh;
+      low = (unsigned) slow;
+      if (value != -2)
+       {
+         /*
+          * someone specified an IP address for the host record
+          */
+         if ((value & mask) != saddr || value < low || value > high)
+           return MR_ADDRESS;
+         /*
+          * run the address argument through inet_addr(). This
+          * has the effect that any out of bounds host addrs will
+          * be converted to a valid host addr. We do this now
+          * so that the uniqueness check works. We should also
+          * link in an inet_addr() that returns an error for
+          * this case.
+          */
+         addr.s_addr = inet_addr(argv[9 + row + idx]);
+         name = inet_ntoa(addr);
+         EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
+           WHERE address = :name;
+         if (dbms_errno)
+           return mr_errcode;
+         if (cnt > 0)
+           {
+             /*
+              * make IP address is unique. If this a modify request
+              * (row == 1), then we expect one record to exist.
+              */
+             if (row == 0 || (row == 1 && cnt > 1))
+               return MR_ADDRESS;
+             if (row == 1 && cnt == 1)
+               {
+                 EXEC SQL SELECT mach_id INTO :id FROM machine
+                   WHERE address = :name;
+                 if (id != *(int *)argv[0])
+                   return MR_ADDRESS;
+               }
+           }
        }
-       if (*(p-1) == '-') return(MR_BAD_CHAR);
+      else
+       {
+         /*
+          * a "unique" address was specified. Walk through the
+          * range specified in the network record, return
+          * error if no room left.
+          */
+         for (id = low; id <= high; id++)
+           {
+             if (((id & 0xff) == 0) || ((id & 0xff) == 255))
+               continue;
+             addr.s_addr = htonl(id);
+             name = inet_ntoa(addr);
+             EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
+               WHERE address = :name;
+             if (dbms_errno)
+               return mr_errcode;
+             if (cnt == 0)
+               break;
+           }
+         if (cnt != 0)
+           return MR_NO_ID;
+         else
+           value = htonl(id);
+       }
+      /*
+       * we have an address in value. Convert it to a string and store it.
+       */
+      addr.s_addr = htonl(value);
+      strcpy(argv[9 + row + idx], inet_ntoa(addr));
     }
-
-    /* sanity check host vendor: must start with a letter, contain only
-     * letters, numerals, and hyphen, and end with an alphanumeric.
-     */
-    if (*argv[row+1] && (row == 0 || strcmp(argv[2], cl->args->mr_argv[2]))) {
-       char *p = argv[row+1];
-
-       if (!isalpha(*p)) return(MR_BAD_CHAR);
-       for (; *p; p++) {
-           if ((!isalnum(*p) && *p != '-' && *p != '.') ||
-               (*p == '-' && p[1] == '.'))
-             return(MR_BAD_CHAR);
+  else
+    strcpy(argv[9 + row + idx], "unassigned");
+
+  /* status checking */
+  value = atoi(argv[7 + row + idx]);
+  if (row == 0 && !(value == 1 || value == 0))
+    return MR_TYPE;
+  if (row == 1)
+    {
+      id = *(int *)argv[0];
+      EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
+      if (dbms_errno)
+       return mr_errcode;
+      if (value != cnt)
+       {
+         EXEC SQL UPDATE machine SET statuschange = SYSDATE
+           WHERE mach_id = :id;
        }
-       if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
     }
 
-    /* sanity check host type: must start with a letter, contain only
-     * letters, numerals, and hyphen, and end with an alphanumeric.
-     */
-    if (*argv[row+2] && (row == 0 || strcmp(argv[3], cl->args->mr_argv[3]))) {
-       char *p = argv[row+2];
-
-       if (!isalnum(*p)) return(MR_BAD_CHAR);
-       for (; *p; p++) {
-           if ((!isalnum(*p) && *p != '-' && *p != '.') ||
-               (*p == '-' && p[1] == '.'))
-             return(MR_BAD_CHAR);
+  /*
+   * If this is an update_host query, we're done.
+   */
+  if (row == 1)
+    return MR_SUCCESS;
+
+  /*
+   * For an add_host query, allocate and fill in a new machine id,
+   * and then insert the creator id.
+   */
+  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
+    return mr_errcode;
+
+  sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
+  return MR_SUCCESS;
+}
+
+
+/* setup_ahal():
+ */
+
+int setup_ahal(struct query *q, char **argv, client *cl)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  char *name;
+  int cnt;
+  EXEC SQL END DECLARE SECTION;
+  char *p;
+
+  name = argv[0];
+  if (!hostname_check(argv[0]))
+    return MR_BAD_CHAR;
+
+  EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
+    name = UPPER(:name);
+  if (dbms_errno)
+    return mr_errcode;
+  if (cnt > 0)
+    return MR_EXISTS;
+
+  return MR_SUCCESS;
+}
+
+/* setup_uhha(): Check characters in hwaddr, and make sure it's not
+ * a duplicate.
+ */
+int setup_uhha(struct query *q, char **argv, client *cl)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  char *hwaddr = argv[1];
+  int count;
+  EXEC SQL END DECLARE SECTION;
+  char *p;
+
+  if (*hwaddr && strcasecmp(hwaddr, "unknown"))
+    {
+      for (p = hwaddr; *p; p++)
+       {
+         if (isupper(*p))
+           *p = tolower(*p);
+         if (!isxdigit(*p))
+           return MR_BAD_CHAR;
        }
-       if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
+      if (p != hwaddr + 12)
+       return MR_ADDRESS;
+
+      EXEC SQL SELECT COUNT(hwaddr) INTO :count
+       FROM machine WHERE hwaddr = :hwaddr;
+      if (count)
+       return MR_NOT_UNIQUE;
     }
 
-    /* sanity check host vendor: must start with a letter, contain only
-     * letters, numerals, and hyphen, and end with an hyphen alphanumeric.
-     */
-    if (*argv[row+3] && (row == 0 || strcmp(argv[4], cl->args->mr_argv[4]))) {
-       char *p = argv[row+3];
-
-       if (!isalpha(*p)) return(MR_BAD_CHAR);
-       for (; *p; p++) {
-           if ((!isalnum(*p) && *p != '-' && *p != '.') ||
-               (*p == '-' && p[1] == '.'))
-             return(MR_BAD_CHAR);
+  return MR_SUCCESS;
+}
+
+/* setup_aprn(): Make sure name/duplexname don't conflict with
+ * anything. If [ANY] was specified for the spooling host, pick the
+ * least loaded print server that serves this kind of printer.
+ */
+int setup_aprn(struct query *q, char **argv, client *cl)
+{
+  int best = -1, row;
+  char *p;
+  EXEC SQL BEGIN DECLARE SECTION;
+  int mid, usage, count;
+  char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
+  EXEC SQL END DECLARE SECTION;
+
+  /* Check for aprn or uprn. */
+  if (q->type == MR_Q_APPEND)
+    row = 0;
+  else
+    row = 1;
+
+  name = argv[PRN_NAME + row];
+  duplexname = argv[PRN_DUPLEXNAME + row];
+  oldname = argv[0];
+
+  if (!*name)
+    return MR_BAD_CHAR;
+  else
+    {
+      if (q->type == MR_Q_APPEND)
+       {
+         EXEC SQL SELECT COUNT(name) INTO :count FROM printers
+           WHERE name = :name OR duplexname = :name;
        }
-       if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
+      else
+       {
+         EXEC SQL SELECT COUNT(name) INTO :count FROM printers
+           WHERE ( name = :name OR duplexname = :name )
+           AND name != :oldname;
+       }
+      if (dbms_errno)
+       return mr_errcode;
+      if (count)
+       return MR_NOT_UNIQUE;
     }
 
-    /* check for duplicate name */
-    name = argv[row];
-    EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
-      WHERE name = :name;
-    if (dbms_errno) return(mr_errcode);
-    if (cnt != 0) return(MR_EXISTS);
-
-    /* check address */
-    if (!strcmp(argv[9+row], "unassigned"))
-      value = -1;
-    else if (!strcmp(argv[9+row], "unique")) {
-       if (*(int *)argv[8+row] == 0)
-         value = -1;
-       else
-         value = -2;
-    } else {
-       value = ntohl(inet_addr(argv[9+row]));
-       if (value == -1) return(MR_ADDRESS);
+  if (*duplexname)
+    {
+      if (q->type == MR_Q_APPEND)
+       {
+         EXEC SQL SELECT COUNT(name) INTO :count FROM printers
+           WHERE name = :duplexname OR duplexname = :duplexname;
+       }
+      else
+       {
+         EXEC SQL SELECT COUNT(name) INTO :count FROM printers
+           WHERE ( name = :duplexname OR duplexname = :duplexname )
+           AND name != :oldname;
+       }
+
+      if (dbms_errno)
+       return mr_errcode;
+      if (count)
+       return MR_NOT_UNIQUE;
     }
-    if (value == 0) return(MR_ADDRESS);
-    if (value != -1) {
-        /*
-         * an address or unique was specified.
-         */
-       id = *(int *)argv[8+row];
-       EXEC SQL SELECT saddr, mask, high, low INTO :saddr, :mask, :high, :low
-         FROM subnet WHERE snet_id = :id;
-       if (dbms_errno) return(mr_errcode);
-       if (value != -2) {
-            /*
-             * someone specified an IP address for the host record
-             */
-           if ((value & mask) != saddr) return(MR_ADDRESS);
-            /* 
-             * run the address argument through inet_addr(). This
-             * has the effect that any out of bounds host addrs will
-             * be converted to a valid host addr. We do this now
-             * so that the uniqueness check works. We should also
-             * link in an inet_addr() that returns an error for
-             * this case. 
-             */
-           addr.s_addr=inet_addr(argv[9+row]);
-           name = inet_ntoa(addr);
-           EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
-             WHERE address = :name;
-           if (dbms_errno) return(mr_errcode);
-           if (cnt > 0) {
-                /*
-                 * make IP address is unique. If this a modify request
-                 * (row == 1), then we expect one record to exist.
-                 */
-               if (row == 0 || row == 1 && cnt > 1) return(MR_ADDRESS);
-               if (row == 1 && cnt == 1) {
-                   EXEC SQL SELECT mach_id INTO :id FROM machine
-                     WHERE address = :name;
-                   if (id != *(int *)argv[0]) return(MR_ADDRESS);
+
+  if (!strcmp(name, duplexname))
+    return MR_NOT_UNIQUE;
+
+  mid = *(int *)argv[PRN_RM + row];
+  if (mid == -1)
+    {
+      EXEC SQL DECLARE csr_rm CURSOR FOR
+       SELECT ps.mach_id, s.string FROM printservers ps, strings s
+       WHERE ps.mach_id IN
+       ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
+         AND enable = 1 )
+       AND ps.printer_types = s.string_id;
+      if (dbms_errno)
+       return mr_errcode;
+      EXEC SQL OPEN csr_rm;
+      if (dbms_errno)
+       return mr_errcode;
+
+      while (1)
+       {
+         EXEC SQL FETCH csr_rm INTO :mid, :types;
+         if (sqlca.sqlcode)
+           break;
+
+         for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
+           {
+             if (!strcasecmp(argv[PRN_TYPE + row], p))
+               {
+                 EXEC SQL SELECT COUNT(name) INTO :usage
+                   FROM printers WHERE rm = :mid;
+
+                 if (best < 0 || usage < best)
+                   {
+                     best = usage;
+                     *(int *)argv[PRN_RM + row] = mid;
+                     break;
+                   }
                }
            }
-       } else {
-            /*
-             * a "unique" address was specified. Walk through the
-             * range specified in the network record, return
-             * error if no room left.
-             */
-           for (id = low; id <= high; id++) {
-               if (((id & 0xff) == 0) ||
-                   ((id & 0xff) == 255))
-                 continue;
-               addr.s_addr = htonl(id);
-               name = (char *)inet_ntoa(addr);
-               EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
-                 WHERE address = :name;
-               if (dbms_errno) return(mr_errcode);
-               if (cnt == 0) break;
-           }
-           if (cnt != 0)
-             return(MR_ADDRESS);
-           else
-             value = htonl(id);
        }
-        /*
-         * we have an address in value. Convert it to a string and store it.
-         */
-       addr.s_addr = htonl(value);
-       strcpy(argv[9+row], inet_ntoa(addr));
-    } else {
-       strcpy(argv[9+row], "unassigned");
-    }
+      EXEC SQL CLOSE csr_rm;
+      if (dbms_errno)
+       return mr_errcode;
 
-    /* status checking */
-    value = atoi(argv[7+row]);
-    if (row == 0 && !(value == 1 || value == 0))
-      return(MR_TYPE);
-    if (row == 1) {
-       id = *(int *)argv[0];
-       EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
-       if (dbms_errno) return(mr_errcode);
-       if (value != cnt) {
-           EXEC SQL UPDATE machine SET statuschange = SYSDATE
-                 WHERE mach_id = :id;
-       }
+      if (best == -1)
+       return MR_SERVICE;
     }
-
-    if (row == 0 && !privileged) {
-       /* subnet owner is adding a host */
-       /* Non-query owner must set use to zero */
-       if (atoi(argv[6]) != 0) return(MR_PERM);
-    } else if (row == 1 && !privileged) {
-       EXEC SQL BEGIN DECLARE SECTION;
-       int i8, i12, i13, i7, i9, i14;
-       char s6[33], s10[33], s11[9];
-       EXEC SQL END DECLARE SECTION;
-       /* Non-query owner is restricted in changes that can be made */
-       id = *(int *)argv[0];
-       EXEC SQL SELECT contact, status, address, owner_type, owner_id,
-         acomment, use, snet_id, ocomment INTO :s6, :i8, :s10, :s11,
-         :i12, :i13, :i7, :i9, :i14 FROM machine WHERE mach_id = :id;
-       if (dbms_errno) return(mr_errcode);
-       /* subnet owner cannot change use, comment, or network */
-       if ((i7 != atoi(argv[7])) || (i14 != *(int *)argv[14]) ||
-            (i9 != *(int *)argv[9]))
-         return(MR_PERM);
-       /* host owner cannot change contact, status, address, owner_type,
-        * owner_id, acomment, or subnet */
-       if (host_access_level == 2 &&
-           (strcmp(argv[6], strtrim(s6)) || (i8 != atoi(argv[8])) ||
-            strcmp(argv[10], strtrim(s10)) ||strcmp(argv[11], strtrim(s11)) ||
-            (i12 != *(int *)argv[12]) || (i13 != *(int *)argv[13]) ||
-            (i9 != *(int *)argv[9])))
-         return(MR_PERM);
+  else
+    {
+      EXEC SQL SELECT mach_id INTO :mid FROM printservers
+       WHERE mach_id = :mid;
+      if (sqlca.sqlcode)
+       return MR_SERVICE;
     }
 
-    /*
-     * If this is an update_host query, we're done.
-     */
-    if (row == 1)
-       return(MR_SUCCESS);
-
-    /*
-     * For an add_host query, allocate and fill in a new machine id,
-     * and then insert the creator id.
-     */
-    if ((mr_errcode = prefetch_value(q,argv,cl)) != MR_SUCCESS)
-      return(mr_errcode);
-
-    sprintf(argv[q->argc + q->vcnt + 1], "%d",cl->client_id);
-    return(MR_SUCCESS);
+  return MR_SUCCESS;
 }
 
+int setup_dpsv(struct query *q, char **argv, client *cl)
+{
+  int id;
+  EXEC SQL BEGIN DECLARE SECTION;
+  int cnt;
+  EXEC SQL END DECLARE SECTION;
 
-/* setup_ahal():
+  id = *(int *)argv[0];
+
+  EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
+    WHERE rm = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  return MR_SUCCESS;
+}
+
+int setup_dcon(struct query *q, char *argv[], client *cl)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  int id, cnt;
+  char containername[CONTAINERS_NAME_SIZE];
+  EXEC SQL END DECLARE SECTION;
+
+  id = *(int *)argv[0];
+  /* check to see if there are machines in this container */
+  EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
+    WHERE cnt_id = :id;
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  /* check to see if there are subcontainers in this container */
+
+  /* get the container name */
+  
+  EXEC SQL SELECT name INTO :containername
+    FROM containers
+    WHERE cnt_id = :id; 
+
+  /* trim off the trailing spaces */
+   strcpy(containername, strtrim(containername));
+
+  EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
+    WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
+
+  if (cnt > 0)
+    return MR_IN_USE;
+
+  if (dbms_errno)
+    return mr_errcode;
+  return MR_SUCCESS;
+}
+
+int setup_scli(struct query *q, char *argv[], client *cl)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  int cnt_id, list_id;
+  EXEC SQL END DECLARE SECTION;
+
+  cnt_id = *(int *)argv[0];
+  /* Check if someone has already set the list for this container */
+  EXEC SQL SELECT list_id INTO :list_id FROM containers
+    WHERE cnt_id = :cnt_id;
+  if (list_id != 0)
+    return MR_EXISTS;
+
+  if (dbms_errno)
+    return mr_errcode;
+
+  return MR_SUCCESS;
+}
+
+/* hostname_check()
+ * validate the rfc1035/rfc1123-ness of a hostname
  */
 
-int setup_ahal(q, argv, cl)
-     struct query *q;
-     char **argv;
-     client *cl;
+int hostname_check(char *name)
+{
+  char *p;
+  int count;
+
+  /* Sanity check name: must contain only letters, numerals, and
+   * hyphen, and not start or end with a hyphen. Also make sure no
+   * label (the thing the .s seperate) is longer than 63 characters,
+   * or empty.
+   */
+
+  for (p = name, count = 0; *p; p++)
+    {
+      count++;
+      if ((!isalnum(*p) && *p != '-' && *p != '.') ||
+         (*p == '-' && p[1] == '.'))
+       return 0;
+      if (*p == '.')
+       {
+         if (count == 1)
+           return 0;
+         count = 0;
+       }
+      if (count == 64)
+       return 0;
+    }
+  if (*(p - 1) == '-')
+    return 0;
+  return 1;
+}
+
+int hostinfo_check(char *info, int num)
+{
+  char *p;
+
+  if (!*info)
+    return 1;
+
+  /* Sanity check host hostinfo: must start with a letter (or number
+   * if num is true), contain only letters, numerals, and hyphen, and
+   * not end with a hyphen.
+   */
+
+  if (!isalpha(*info) && (!num || !isdigit(*info)))
+    return 0;
+  for (p = info; *p; p++)
+    {
+      if ((!isalnum(*p) && *p != '-' && *p != '.') ||
+         (*p == '-' && p[1] == '.'))
+       return 0;
+    }
+  if (!isalnum(*(p - 1)))
+    return 1;
+}
+
+int setup_aali(struct query *q, char *argv[], client *cl)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  int cnt;
+  char *name, *type, *trans;
+  EXEC SQL END DECLARE SECTION;
+  name = argv[0];
+  type = argv[1];
+  trans = argv[2];
+
+  if (strcmp(strtrim(type), "FILESYS"))
+    return MR_SUCCESS;
+
+  EXEC SQL SELECT count(label) INTO :cnt FROM filesys WHERE
+    label = :name;
+  if (cnt > 0)
+    return MR_EXISTS;
+
+  return MR_SUCCESS;
+}
+
+int setup_acon(struct query *q, char *argv[], client *cl)
 {
-    EXEC SQL BEGIN DECLARE SECTION;
-    char *name;
-    int cnt;
-    EXEC SQL END DECLARE SECTION;
-    char *p;
-
-    p = name = argv[0];
-    if (!isalpha(*p)) return(MR_BAD_CHAR);
-    for (; *p; p++) {
-       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
-           (*p == '-' && p[1] == '.'))
-         return(MR_BAD_CHAR);
+  EXEC SQL BEGIN DECLARE SECTION;
+  char containername[CONTAINERS_NAME_SIZE];
+  EXEC SQL END DECLARE SECTION;
+  
+  char* ptr;
+  
+  memset(containername, 0, sizeof(containername));
+  strcpy(containername, argv[0]);
+  ptr = strrchr(containername, '/');
+  /* sub container, check for parents */
+  if (ptr)
+    {
+      *ptr = '\0';
+      EXEC SQL SELECT * FROM containers
+       WHERE lower(name) = lower(:containername);      
+      if (sqlca.sqlerrd[2] != 1)
+       return MR_CONTAINER_NO_PARENT;
     }
-    if (*(p-1) == '-') return(MR_BAD_CHAR);
+  
+  if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
+    return mr_errcode;
+  
+  return MR_SUCCESS;
+}
 
-    EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
-      name = :name;
-    if (dbms_errno) return(mr_errcode);
-    if (cnt > 0) return(MR_EXISTS);
+int check_mailman_listname(char *name, const char *suffix)
+{
+  char *p;
+  EXEC SQL BEGIN DECLARE SECTION;
+  int i, cnt;
+  EXEC SQL END DECLARE SECTION;
+
+  p = strstr(name, suffix);
+  if (p)
+    {
+      if (strlen(name) == (p - name + strlen(suffix)))
+       {
+         /* list is of the form "name-suffix" */
+         i = (p - name);
+         EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
+           WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;
+         if (cnt > 0)
+           return MR_EXISTS;
+       }
+    }
 
-    return(MR_SUCCESS);
+  return MR_SUCCESS;
 }
This page took 0.494792 seconds and 4 git commands to generate.