+ status = SMS_NFS;
+## range of np is nfsphys
+## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
+## where np.#mach_id = @mach_id sort by #dir:d {
+ cp1 = name;
+ cp2 = dir;
+ while (*cp2) {
+ if (*cp1++ != *cp2) break;
+ cp2++;
+ }
+ if (*cp2 == 0) {
+ status = SMS_SUCCESS;
+## endretrieve
+ }
+## }
+
+ return(status);
+##}
+
+
+/* setup_dfil: free any quota records associated with a filesystem
+ * when it is deleted.
+ */
+
+setup_dfil(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## int id;
+
+ id = *(int *)argv[0];
+## range of q is nfsquota
+## range of fs is filesys
+## range of n is nfsphys
+## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
+## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
+
+## repeat delete q where q.filsys_id = @id
+ return(SMS_SUCCESS);
+##}
+
+
+/* setup_dnfp: check to see that the nfs physical partition does not have
+ * any filesystems assigned to it before allowing it to be deleted.
+ */
+
+setup_dnfp(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## int id, exists;
+
+ id = *(int *)argv[0];
+## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
+ if (exists)
+ return(SMS_IN_USE);
+ return(SMS_SUCCESS);
+##}
+
+
+/* setup_dnfq: Remove allocation from nfsphys before deleting quota.
+ * argv[0] = filsys_id
+ * argv[1] = users_id
+ */
+
+setup_dnfq(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## int quota, fs, user;
+
+ fs = *(int *)argv[0];
+ user = *(int *)argv[1];
+
+## range of q is nfsquota
+## repeat retrieve (quota = q.#quota) where q.users_id = @user and
+## q.filsys_id = @fs
+## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
+## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
+ return(SMS_SUCCESS);
+##}
+
+
+\f
+/* FOLLOWUP ROUTINES */
+
+/* generic set_modtime routine. This takes the table name from the query,
+ * and will update the modtime, modby, and modwho fields in the entry in
+ * the table whose name field matches argv[0].
+ */
+
+set_modtime(q, argv, cl)
+ struct query *q;
+ char *argv[];
+ client *cl;
+##{
+## char *name, *entity, *table;
+## int who;
+
+ entity = cl->entity;
+ who = cl->users_id;
+ table = q->rtable;
+ name = argv[0];
+
+## replace table (modtime = "now", modby = who, modwith = entity)
+## where table.#name = name
+ return(SMS_SUCCESS);
+##}
+
+/* generic set_modtime_by_id routine. This takes the table name from
+ * the query, and the id name from the validate record,
+ * and will update the modtime, modby, and modwho fields in the entry in
+ * the table whose id matches argv[0].
+ */
+
+set_modtime_by_id(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## char *entity, *table, *id_name;
+## int who, id;
+
+ entity = cl->entity;
+ who = cl->users_id;
+ table = q->rtable;
+ id_name = q->validate->object_id;
+
+ id = *(int *)argv[0];
+## replace table (modtime = "now", modby = who, modwith = entity)
+## where table.id_name = id
+ return(SMS_SUCCESS);
+##}
+
+
+/* Sets the finger modtime on a user record. The users_id will be in argv[0].
+ */
+
+set_finger_modtime(q, argv, cl)
+ struct query *q;
+ char *argv[];
+ client *cl;
+##{
+## int users_id, who;
+## char *entity;
+
+ entity = cl->entity;
+ who = cl->users_id;
+ users_id = *(int *)argv[0];
+
+## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
+## where u.#users_id = @users_id
+ return(SMS_SUCCESS);
+##}
+
+
+/* Sets the pobox modtime on a user record. The users_id will be in argv[0].
+ */
+
+set_pobox_modtime(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## int users_id, who;
+## char *entity;
+
+ entity = cl->entity;
+ who = cl->users_id;
+ users_id = *(int *)argv[0];
+
+## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
+## where users.#users_id = @users_id
+ return(SMS_SUCCESS);
+##}
+
+
+/* Like set_modtime, but uppercases the name first.
+ */
+
+set_uppercase_modtime(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## char *name, *entity, *table;
+## int who;
+
+ entity = cl->entity;
+ who = cl->users_id;
+ table = q->rtable;
+ name = argv[0];
+
+## replace table (modtime = "now", modby = who, modwith = entity)
+## where table.#name = uppercase(name)
+ return(SMS_SUCCESS);
+##}
+
+
+/* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
+ * is necessary for add_machine_to_cluster becuase the table that query
+ * operates on is "mcm", not "machine".
+ */
+
+set_mach_modtime_by_id(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## char *entity;
+## int who, id;
+
+ entity = cl->entity;
+ who = cl->users_id;
+
+ id = *(int *)argv[0];
+## range of m is machine
+## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
+## where m.mach_id = @id
+ return(SMS_SUCCESS);
+##}
+
+
+/* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
+ * is necessary for add_cluster_data and delete_cluster_data becuase the
+ * table that query operates on is "svc", not "cluster".
+ */
+
+set_cluster_modtime_by_id(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## char *entity;
+## int who, id;
+
+ entity = cl->entity;
+ who = cl->users_id;
+
+ id = *(int *)argv[0];
+## range of c is cluster
+## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
+## where c.clu_id = @id
+ return(SMS_SUCCESS);
+##}
+
+
+/* sets the modtime on the serverhost where the service name is in argv[0]
+ * and the mach_id is in argv[1].
+ */
+
+set_serverhost_modtime(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## char *entity, *serv;
+## int who, id;
+
+ entity = cl->entity;
+ who = cl->users_id;
+
+ serv = argv[0];
+ id = *(int *)argv[1];
+## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
+## where sh.service = uppercase(@serv) and sh.mach_id = @id
+ return(SMS_SUCCESS);
+##}
+
+
+/* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
+ * directory name is in argv[1].
+ */
+
+set_nfsphys_modtime(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## char *entity, *dir;
+## int who, id;
+
+ entity = cl->entity;
+ who = cl->users_id;
+
+ id = *(int *)argv[0];
+ dir = argv[1];
+## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
+## where np.#dir = @dir and np.mach_id = @id
+ return(SMS_SUCCESS);
+##}
+
+
+/* sets the modtime on a filesystem, where argv[0] contains the filesys
+ * label.
+ */
+
+set_filesys_modtime(q, argv, cl)
+ struct query *q;
+ char *argv[];
+ client *cl;
+##{
+## char *label, *entity;
+## int who;
+
+ entity = cl->entity;
+ who = cl->users_id;
+
+ label = argv[0];
+ if (!strcmp(q->shortname, "ufil"))
+ label = argv[1];
+
+## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
+## #phys_id = @var_phys_id) where fs.#label = @label
+ return(SMS_SUCCESS);
+##}
+
+
+/* sets the modtime on a zephyr class, where argv[0] contains the class
+ * name.
+ */
+
+set_zephyr_modtime(q, argv, cl)
+ struct query *q;
+ char *argv[];
+ client *cl;
+##{
+## char *class, *entity;
+## int who;
+
+ entity = cl->entity;
+ who = cl->users_id;
+
+ class = argv[0];
+
+## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
+## where z.#class = @class
+ return(SMS_SUCCESS);
+##}
+
+
+/* fixes the modby field. This will be the second to last thing in the
+ * argv, the argv length is determined from the query structure. It is
+ * passed as a pointer to an integer. This will either turn it into a
+ * username, or # + the users_id.
+ */
+followup_fix_modby(q, sq, v, action, actarg, cl)
+ struct query *q;
+ register struct save_queue *sq;
+ struct validate *v;
+ register int (*action)();
+ register int actarg;
+ client *cl;
+##{
+ register int i, j;
+ char **argv, *malloc();
+## int id, rowcount;
+## char *name;
+
+ i = q->vcnt - 2;
+ while (sq_get_data(sq, &argv)) {
+ id = atoi(argv[i]);
+ free(argv[i]);
+ argv[i] = malloc(9);
+ name = argv[i];
+## repeat retrieve (name = users.login) where users.users_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1) {
+ sprintf(argv[i], "#%d", id);
+ }
+ (*action)(q->vcnt, argv, actarg);
+ for (j = 0; j < q->vcnt; j++)
+ free(argv[j]);
+ free(argv);
+ }
+ sq_destroy(sq);
+ return(SMS_SUCCESS);
+##}
+
+
+/**
+ ** followup_ausr - add finger and pobox entries, set_user_modtime
+ **
+ ** Inputs:
+ ** argv[0] - login (add_user)
+ ** argv[3] - last name
+ ** argv[4] - first name
+ ** argv[5] - middle name
+ **
+ **/
+
+followup_ausr(q, argv, cl)
+ struct query *q;
+ char *argv[];
+ client *cl;
+##{
+## int who;
+## char *login, *entity;
+## char fullname[129];
+
+ login = argv[0];
+ who = cl->users_id;
+ entity = cl->entity;
+
+ /* build fullname */
+ if (strlen(argv[4]) && strlen(argv[5]))
+ sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
+ else if (strlen(argv[4]))
+ sprintf(fullname, "%s %s", argv[4], argv[3]);
+ else
+ sprintf(fullname, "%s", argv[3]);
+
+ /* create finger entry, pobox & set modtime on user */
+## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
+## #fullname=@fullname, mit_affil = u.mit_year,
+## fmodtime="now", fmodby=@who, fmodwith=@entity,
+## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
+## where u.#login = @login
+
+ return(SMS_SUCCESS);
+##}
+
+
+/* followup_gpob: fixes argv[2] based on the IDs currently there and the
+ * type in argv[1]. Then completes the upcall to the user.
+ *
+ * argv[2] is of the form "123:234" where the first integer is the machine
+ * ID if it is a pop box, and the second is the string ID if it is an SMTP
+ * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
+ * are skipped.
+ */
+
+followup_gpob(q, sq, v, action, actarg, cl)
+ register struct query *q;
+ register struct save_queue *sq;
+ register struct validate *v;
+ register int (*action)();
+ int actarg;
+ client *cl;
+##{
+ char **argv, *index();
+ char *ptype, *p;
+## char box[129], *name;
+## int mid, sid, rowcount;
+
+ /* for each row */
+ while (sq_get_data(sq, &argv)) {
+ sms_trim_args(2, argv);
+ ptype = argv[1];
+ p = index(argv[2], ':');
+ *p++ = 0;
+ mid = atoi(argv[2]);
+ sid = atoi(p);
+ free(argv[2]);
+
+ if (!strcmp(ptype, "POP")) {
+## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ return(SMS_MACHINE);
+ } else if (!strcmp(ptype, "SMTP")) {
+## repeat retrieve (box=strings.string) where strings.string_id=@sid
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ return(SMS_STRING);
+ } else /* ptype == "NONE" */ {
+ goto skip;
+ }
+
+ if (!strcmp(q->shortname, "gpob")) {
+ sid = atoi(argv[4]);
+ free(argv[4]);
+ argv[4] = malloc(9);
+ name = argv[4];
+## repeat retrieve (name = users.login) where users.users_id = @sid
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ sprintf(name, "#%d", sid);
+ }
+
+ argv[2] = box;
+ (*action)(q->vcnt, argv, actarg);
+ skip:
+ /* free saved data */
+ free(argv[0]);
+ free(argv[1]);
+ free(argv);
+ }
+
+ sq_destroy(sq);
+ return (SMS_SUCCESS);
+##}
+
+
+/* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
+ * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
+ * proper name based on the type, and repace that string in the argv.
+ * Also fixes the modby field by called followup_fix_modby.
+ */
+
+followup_glin(q, sq, v, action, actarg, cl)
+ register struct query *q;
+ register struct save_queue *sq;
+ register struct validate *v;
+ register int (*action)();
+ int actarg;
+ client *cl;
+##{
+ char **argv, *malloc(), *realloc(), *type;
+## char *name;
+## int id, rowcount;
+ int i, idx;
+
+ idx = 8;
+ if (!strcmp(q->shortname, "gsin"))
+ idx = 12;
+
+ while (sq_get_data(sq, &argv)) {
+ sms_trim_args(q->vcnt, argv);
+
+ id = atoi(argv[i = q->vcnt - 2]);
+ free(argv[i]);
+ name = argv[i] = malloc(9);
+## repeat retrieve (name = users.login) where users.users_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ sprintf(argv[i], "#%d", id);
+
+ id = atoi(argv[idx]);
+ type = argv[idx - 1];
+ if ((name = malloc(33)) == NULL)
+ return(SMS_NO_MEM);
+
+ if (!strcmp(type, "LIST")) {
+## repeat retrieve (name = list.#name) where list.list_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ strcpy(name, "???");
+ } else if (!strcmp(type, "USER")) {
+## repeat retrieve (name = users.login) where users.users_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ strcpy(name, "???");
+ } else if (!strcmp(type, "NONE")) {
+ strcpy(name, "NONE");
+ } else
+ strcpy(name, "???");
+ free(argv[idx]);
+ argv[idx] = name;
+
+ if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
+ argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
+ strcpy(argv[6], UNIQUE_GID);
+ }
+
+ /* send the data */
+ (*action)(q->vcnt, argv, actarg);
+
+ /* free saved data */
+ for (i = 0; i < q->vcnt; i++)
+ free(argv[i]);
+ free(argv);
+ }
+
+ sq_destroy(sq);
+ return (SMS_SUCCESS);
+##}
+
+
+/** followup_amtl - followup for amtl and dmfl; when adding a list
+ ** member to a maillist, make member list a maillist also
+ ** unless list is a user-group.
+ ** Then set_list_modtime_by_id.
+ **
+ ** Inputs:
+ ** argv[0] - list_id
+ ** argv[1] - member_type
+ ** argv[2] - member_id
+ **
+ **/
+
+followup_amtl(q, argv, cl)
+ struct query *q;
+ char *argv[];
+ client *cl;
+##{
+## int list_id;
+## int member_id;
+## int exists, who;
+## char *entity;
+
+ list_id = *(int *)argv[0];
+ entity = cl->entity;
+ who = cl->users_id;
+
+## range of l is list
+## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
+## where l.#list_id = @list_id
+
+ /* if query is not amtl or if member_type is not LIST then return */
+ if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
+ return(SMS_SUCCESS);
+
+ member_id = *(int *)argv[2];
+
+ /* is parent list a mailing list? */
+## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
+ if (!exists)
+ return(SMS_SUCCESS);
+
+ /* list is not a user-group; add list to maillist table */
+## repeat replace l (maillist = 1) where l.#list_id = @member_id
+ return(SMS_SUCCESS);
+##}
+
+
+/* followup_anfq: Add allocation to nfsphys after creating quota.
+ * argv[0] = filsys_id
+ * argv[2] = ascii(quota)
+ */
+
+followup_anfq(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## int quota, user, fs, who;
+## char *entity;
+
+ fs = *(int *)argv[0];
+ user = *(int *)argv[1];
+ quota = atoi(argv[2]);
+ who = cl->users_id;
+ entity = cl->entity;
+
+## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
+## where nq.filsys_id = @fs and nq.users_id = @user
+## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
+## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
+ return(SMS_SUCCESS);
+##}
+
+
+/* followup_gzcl:
+ */
+
+followup_gzcl(q, sq, v, action, actarg, cl)
+ register struct query *q;
+ register struct save_queue *sq;
+ register struct validate *v;
+ register int (*action)();
+ int actarg;
+ client *cl;
+##{
+## char *name;
+## int rowcount, id;
+ char **argv;
+ int i;
+
+ while (sq_get_data(sq, &argv)) {
+ sms_trim_args(q->vcnt, argv);
+
+ id = atoi(argv[i = q->vcnt - 2]);
+ free(argv[i]);
+ name = argv[i] = malloc(9);
+## repeat retrieve (name = users.login) where users.users_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ sprintf(argv[i], "#%d", id);
+
+ for (i = 1; i < 8; i+=2) {
+ id = atoi(argv[i+1]);
+ free(argv[i+1]);
+ if ((name = argv[i+1] = malloc(33)) == NULL)
+ return(SMS_NO_MEM);
+ if (!strcmp(argv[i], "LIST")) {
+## repeat retrieve (name = list.#name) where list.list_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ strcpy(name, "???");
+ } else if (!strcmp(argv[i], "USER")) {
+## repeat retrieve (name = users.login) where users.users_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ strcpy(name, "???");
+ } else if (!strcmp(argv[i], "NONE")) {
+ strcpy(name, "NONE");
+ } else {
+ strcpy(name, "???");
+ }
+ }
+
+ /* send the data */
+ (*action)(q->vcnt, argv, actarg);
+
+ /* free saved data */
+ for (i = 0; i < q->vcnt; i++)
+ free(argv[i]);
+ free(argv);
+ }
+ sq_destroy(sq);
+ return(SMS_SUCCESS);
+##}
+
+
+/* followup_gsha:
+ */
+
+followup_gsha(q, sq, v, action, actarg, cl)
+ register struct query *q;
+ register struct save_queue *sq;
+ register struct validate *v;
+ register int (*action)();
+ int actarg;
+ client *cl;
+##{
+## char *name;
+## int rowcount, id;
+ char **argv;
+ int i;
+
+ while (sq_get_data(sq, &argv)) {
+ sms_trim_args(q->vcnt, argv);
+
+ id = atoi(argv[4]);
+ free(argv[4]);
+ name = argv[4] = malloc(9);
+## repeat retrieve (name = users.login) where users.users_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ sprintf(argv[4], "#%d", id);
+
+ id = atoi(argv[2]);
+ free(argv[2]);
+ if ((name = argv[2] = malloc(33)) == NULL)
+ return(SMS_NO_MEM);
+ if (!strcmp(argv[1], "LIST")) {
+## repeat retrieve (name = list.#name) where list.list_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ strcpy(name, "???");
+ } else if (!strcmp(argv[1], "USER")) {
+## repeat retrieve (name = users.login) where users.users_id = @id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ strcpy(name, "???");
+ } else if (!strcmp(argv[1], "NONE")) {
+ strcpy(name, "NONE");
+ } else {
+ strcpy(name, "???");
+ }
+
+ /* send the data */
+ (*action)(q->vcnt, argv, actarg);
+
+ /* free saved data */
+ for (i = 0; i < q->vcnt; i++)
+ free(argv[i]);
+ free(argv);
+ }
+ sq_destroy(sq);
+ return(SMS_SUCCESS);
+##}
+
+
+\f
+/* Special query routines */
+
+/* set_pobox - this does all of the real work.
+ * argv = user_id, type, box
+ * if type is POP, then box should be a machine, and its ID should be put in
+ * pop_id. If type is SMTP, then box should be a string and its ID should
+ * be put in box_id. If type is NONE, then box doesn't matter.
+ */
+
+int set_pobox(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## int user, id, rowcount;
+## char *box, potype[9];
+
+ box = argv[2];
+ user = *(int *)argv[0];
+
+## repeat retrieve (id = users.pop_id, potype = users.#potype)
+## where users.users_id = @user
+ if (!strcmp(strtrim(potype), "POP"))
+ set_pop_usage(id, -1);
+
+ if (!strcmp(argv[1], "POP")) {
+## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ return(SMS_MACHINE);
+## repeat replace users (#potype = "POP", pop_id = @id)
+## where users.users_id = @user
+ set_pop_usage(id, 1);
+ } else if (!strcmp(argv[1], "SMTP")) {
+## range of s is strings
+## repeat retrieve (id = s.string_id) where s.string = @box
+## inquire_equel (rowcount = "rowcount")
+ if (rowcount == 0) {
+## range of v is values
+## repeat retrieve (id = v.value) where v.name = "strings_id"
+ id++;
+## repeat replace v (value = @id) where v.name = "strings_id"
+## append to strings (string_id = id, string = box)
+ }
+## repeat replace users (#potype = "SMTP", box_id = @id)
+## where users.users_id = @user
+ } else /* argv[1] == "NONE" */ {
+## repeat replace users (#potype = "NONE") where users.users_id = @user
+ }
+
+ set_pobox_modtime(q, argv, cl);
+## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
+## where tblstats.#table = "users"
+ return(SMS_SUCCESS);
+##}
+
+
+/* get_list_info: passed a wildcard list name, returns lots of stuff about
+ * each list. This is tricky: first build a queue of all requested
+ * data. Rest of processing consists of fixing gid, ace_name, and modby.
+ */
+
+get_list_info(q, aargv, cl, action, actarg)
+ register struct query *q;
+ char **aargv;
+ client *cl;
+ register int (*action)();
+ int actarg;
+##{
+ char *argv[13], *malloc(), *realloc();
+## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
+## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
+## char modby[9], modwith[9];
+## int id, rowcount, acl_id, hid, modby_id;
+ int returned;
+ struct save_queue *sq, *sq_create();
+
+ returned = rowcount = 0;
+ name = aargv[0];
+
+ sq = sq_create();
+## range of l is list
+## repeat retrieve (id = l.list_id) where l.#name = @name {
+ sq_save_data(sq, id);
+ rowcount++;
+## }
+ if (rowcount == 0)
+ return(SMS_NO_MATCH);
+
+ argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
+ argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
+ argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
+ argv[12] = modwith;
+
+ while (sq_get_data(sq, &id)) {
+ if (id == 0)
+ continue;
+ argv[6] = gid;
+## repeat retrieve (listname = l.#name, active = text(l.#active),
+## public = text(l.#public), hidden = text(l.#hidden),
+## hid = l.#hidden, maillist = text(l.#maillist),
+## group = text(l.#group), gid = text(l.#gid),
+## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
+## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
+## modwith =l.#modwith)
+## where l.list_id = @id
+
+ if (atoi(gid) == -1)
+ argv[6] = UNIQUE_GID;
+
+ if (!strcmp(acl_type, "LIST")) {
+## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ strcpy(acl_name, "???");
+ } else if (!strcmp(acl_type, "USER")) {
+## repeat retrieve (acl_name = users.#login)
+## where users.users_id = @acl_id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ strcpy(acl_name, "???");
+ } else if (!strcmp(acl_type, "NONE")) {
+ strcpy(acl_name, "NONE");
+ } else
+ strcpy(acl_name, "???");
+
+## repeat retrieve (modby = users.login) where users.users_id = @modby_id
+## inquire_equel(rowcount = "rowcount")
+ if (rowcount != 1)
+ sprintf(modby, "#%d", id);
+
+ sms_trim_args(q->vcnt, argv);
+ returned++;
+ (*action)(q->vcnt, argv, actarg);
+ }
+
+ sq_destroy(sq);
+## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
+## where tblstats.#table = "list"
+
+ return (SMS_SUCCESS);
+##}
+
+
+/* get_ace_use - given a type and a name, return a type and a name.
+ * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
+ * and argv[1] will contain the ID of the entity in question. The R*
+ * types mean to recursively look at every containing list, not just
+ * when the object in question is a direct member. On return, the
+ * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
+ */
+
+int get_ace_use(q, argv, cl, action, actarg)
+ struct query *q;
+ char *argv[];
+ client *cl;
+ int (*action)();
+ int actarg;
+##{
+ int found = 0;
+## char *atype;
+## int aid, listid, id;
+ struct save_queue *sq, *sq_create();
+
+ atype = argv[0];
+ aid = *(int *)argv[1];
+ if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
+ return(get_ace_internal(atype, aid, action, actarg));
+ }
+
+ sq = sq_create();
+ if (!strcmp(atype, "RLIST")) {
+ sq_save_data(sq, aid);
+ /* get all the list_id's of containing lists */
+## range of m is members
+ while (sq_get_data(sq, &id)) {
+## repeat retrieve (listid = m.list_id)
+## where m.member_type = "LIST" and m.member_id = @id {
+ sq_save_unique_data(sq, listid);
+## }
+ }
+ /* now process each one */
+ while (sq_get_data(sq, &id)) {
+ if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
+ found++;
+ }
+ }
+
+ if (!strcmp(atype, "RUSER")) {
+## range of m is members
+## repeat retrieve (listid = m.list_id)
+## where m.member_type = "USER" and m.member_id = @aid {
+ sq_save_data(sq, listid);
+## }
+ /* get all the list_id's of containing lists */
+ while (sq_get_data(sq, &id)) {
+## repeat retrieve (listid = m.list_id)
+## where m.member_type = "LIST" and m.member_id = @id {
+ sq_save_unique_data(sq, listid);
+## }
+ }
+ /* now process each one */
+ while (sq_get_data(sq, &id)) {
+ if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
+ found++;
+ }
+ if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
+ found++;
+ }
+
+ sq_destroy(sq);
+ if (!found) return(SMS_NO_MATCH);
+ return(SMS_SUCCESS);
+##}
+
+
+/* This looks up a single list or user for ace use. atype must be "USER"
+ * or "LIST", and aid is the ID of the corresponding object. This is used
+ * by get_ace_use above.
+ */
+
+##get_ace_internal(atype, aid, action, actarg)
+## char *atype;
+## int aid;
+ int (*action)();
+ int actarg;
+##{
+ char *rargv[2];
+ int found = 0;
+## char name[33];
+
+ rargv[1] = name;
+ if (!strcmp(atype, "LIST")) {
+ rargv[0] = "FILESYS";
+## repeat retrieve (name = filesys.label)
+## where filesys.owners = @aid {
+ (*action)(2, rargv, actarg);
+ found++;
+## }
+
+ rargv[0] = "QUERY";
+## repeat retrieve (name = capacls.capability)
+## where capacls.list_id = @aid {
+ (*action)(2, rargv, actarg);
+ found++;
+## }
+ } else if (!strcmp(atype, "USER")) {
+ rargv[0] = "FILESYS";
+## repeat retrieve (name = filesys.label)
+## where filesys.owner = @aid {
+ (*action)(2, rargv, actarg);
+ found++;
+## }
+ }
+
+ rargv[0] = "LIST";
+## repeat retrieve (name = list.#name)
+## where list.acl_type = @atype and list.acl_id = @aid {
+ (*action)(2, rargv, actarg);
+ found++;
+## }
+
+ rargv[0] = "SERVICE";
+## repeat retrieve (name = servers.#name)
+## where servers.acl_type = @atype and servers.acl_id = @aid {
+ (*action)(2, rargv, actarg);
+ found++;
+## }
+
+ rargv[0] = "HOSTACCESS";
+## repeat retrieve (name = machine.#name)
+## where machine.mach_id = hostaccess.mach_id and
+## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
+ (*action)(2, rargv, actarg);
+ found++;
+## }
+ rargv[0] = "ZEPHYR";
+## repeat retrieve (name = zephyr.class)
+## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
+## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
+## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
+## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
+ (*action)(2, rargv, actarg);
+ found++;
+## }
+
+ if (!found) return(SMS_NO_MATCH);
+ return(SMS_SUCCESS);
+##}
+
+
+/* get_lists_of_member - given a type and a name, return the name and flags
+ * of all of the lists of the given member. The member_type is one of
+ * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
+ * and argv[1] will contain the ID of the entity in question. The R*
+ * types mean to recursively look at every containing list, not just
+ * when the object in question is a direct member.
+ */
+
+int get_lists_of_member(q, argv, cl, action, actarg)
+ struct query *q;
+ char *argv[];
+ client *cl;
+ int (*action)();
+ int actarg;
+##{
+ int found = 0;
+## char *atype;
+## int aid, listid, id;
+ struct save_queue *sq, *sq_create();
+
+ atype = argv[0];
+ aid = *(int *)argv[1];
+ if (!strcmp(atype, "LIST") ||
+ !strcmp(atype, "USER") ||
+ !strcmp(atype, "STRING")) {
+ return(glom_internal(atype, aid, action, actarg));
+ }
+
+ sq = sq_create();
+ if (!strcmp(atype, "RLIST")) {
+ sq_save_data(sq, aid);
+ /* get all the list_id's of containing lists */
+## range of m is members
+ while (sq_get_data(sq, &id)) {
+## repeat retrieve (listid = m.list_id)
+## where m.member_type = "LIST" and m.member_id = @id {
+ sq_save_unique_data(sq, listid);
+## }
+ }
+ /* now process each one */
+ while (sq_get_data(sq, &id)) {
+ if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
+ found++;
+ }
+ }
+
+ if (!strcmp(atype, "RUSER")) {
+## range of m is members
+## repeat retrieve (listid = m.list_id)
+## where m.member_type = "USER" and m.member_id = @aid {
+ sq_save_data(sq, listid);
+## }
+ /* get all the list_id's of containing lists */
+ while (sq_get_data(sq, &id)) {
+## repeat retrieve (listid = m.list_id)
+## where m.member_type = "LIST" and m.member_id = @id {
+ sq_save_unique_data(sq, listid);
+## }
+ }
+ /* now process each one */
+ while (sq_get_data(sq, &id)) {
+ if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
+ found++;
+ }
+ if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
+ found++;
+ }
+
+ if (!strcmp(atype, "RSTRING")) {
+## range of m is members
+## repeat retrieve (listid = m.list_id)
+## where m.member_type = "STRING" and m.member_id = @aid {
+ sq_save_data(sq, listid);
+## }
+ /* get all the list_id's of containing lists */
+ while (sq_get_data(sq, &id)) {
+## repeat retrieve (listid = m.list_id)
+## where m.member_type = "LIST" and m.member_id = @id {
+ sq_save_unique_data(sq, listid);
+## }
+ }
+ /* now process each one */
+ while (sq_get_data(sq, &id)) {
+ if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
+ found++;
+ }
+ if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
+ found++;
+ }
+
+## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
+## where tblstats.#table = "members"
+ sq_destroy(sq);
+ if (!found) return(SMS_NO_MATCH);
+ return(SMS_SUCCESS);
+##}
+
+
+/* This looks up a single list, user, or string as a member. atype must be
+ * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
+ * This is used by get_lists_of_members above.
+ */
+
+##glom_internal(atype, aid, action, actarg)
+## char *atype;
+## int aid;
+ int (*action)();
+ int actarg;
+##{
+ char *rargv[6];
+ int found = 0;
+## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
+
+ rargv[0] = name;
+ rargv[1] = active;
+ rargv[2] = public;
+ rargv[3] = hidden;
+ rargv[4] = maillist;
+ rargv[5] = group;
+## repeat retrieve (name = list.#name, active = text(list.#active),
+## public = text(list.#public), hidden = text(list.#hidden),
+## maillist = text(list.#maillist), group = text(list.#group))
+## where list.list_id = m.list_id and
+## m.member_type = @atype and m.member_id = @aid {
+ (*action)(6, rargv, actarg);
+ found++;
+## }
+
+ if (!found) return(SMS_NO_MATCH);
+ return(SMS_SUCCESS);
+##}
+
+
+/* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
+ * the five flags associated with each list. It will return the name of
+ * each list that meets the quailifications. It does this by building a
+ * where clause based on the arguments, then doing a retrieve.
+ */
+
+static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
+
+int qualified_get_lists(q, argv, cl, action, actarg)
+ struct query *q;
+ char *argv[];
+ client *cl;
+ int (*action)();
+ int actarg;
+{
+ return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
+ "l", "name", lflags));
+}