+int add_member_to_list(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## int id, lid, mid, exists, error, who, ref;
+## char *mtype, dtype[9], *entity;
+ int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
+ int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
+ int status;
+ char *dtypes[MAXLISTDEPTH];
+ char *iargv[3], *buf;
+
+## range of m is imembers
+ lid = *(int *)argv[0];
+ mtype = argv[1];
+ mid = *(int *)argv[2];
+ /* if the member is already a direct member of the list, punt */
+## repeat retrieve (exists = any(m.list_id where m.list_id=@lid and
+## m.member_id = @mid and m.member_type = @mtype
+## and m.direct = 1))
+ if (exists)
+ return(MR_EXISTS);
+ if (!strcasecmp(mtype, "STRING")) {
+ buf = malloc(0);
+ status = id_to_name(mid, "STRING", &buf);
+ if (status) return(status);
+ if (index(buf, '/') || index(buf, '|')) {
+ free(buf);
+ return(MR_BAD_CHAR);
+ }
+ free(buf);
+ }
+
+ ancestors[0] = lid;
+ aref[0] = 1;
+ acount = 1;
+## repeat retrieve (id = m.list_id, ref = m.ref_count)
+## where m.member_id = @lid and m.member_type = "LIST" {
+ aref[acount] = ref;
+ ancestors[acount++] = id;
+ if (acount >= MAXLISTDEPTH) {
+## endretrieve
+ }
+## }
+ if (ingres_errno) return(mr_errcode);
+ if (acount >= MAXLISTDEPTH) {
+ return(MR_INTERNAL);
+ }
+ descendants[0] = mid;
+ dtypes[0] = mtype;
+ dref[0] = 1;
+ dcount = 1;
+ error = 0;
+ if (!strcmp(mtype, "LIST")) {
+## repeat retrieve (id = m.member_id, dtype = m.member_type,
+## ref = m.ref_count)
+## where m.list_id = @mid {
+ switch (dtype[0]) {
+ case 'L':
+ dtypes[dcount] = "LIST";
+ break;
+ case 'U':
+ dtypes[dcount] = "USER";
+ break;
+ case 'S':
+ dtypes[dcount] = "STRING";
+ break;
+ case 'K':
+ dtypes[dcount] = "KERBEROS";
+ break;
+ default:
+ error++;
+## endretrieve
+ }
+ dref[dcount] = ref;
+ descendants[dcount++] = id;
+ if (dcount >= MAXLISTDEPTH) {
+ error++;
+## endretrieve
+ }
+## }
+ if (ingres_errno) return(mr_errcode);
+ if (error)
+ return(MR_INTERNAL);
+ }
+ for (a = 0; a < acount; a++) {
+ lid = ancestors[a];
+ for (d = 0; d < dcount; d++) {
+ mid = descendants[d];
+ mtype = dtypes[d];
+ if (mid == lid && !strcmp(mtype, "LIST")) {
+ return(MR_LISTLOOP);
+ }
+## repeat retrieve (exists = any(m.ref_count where m.list_id = @lid
+## and m.member_id = @mid
+## and m.member_type = @mtype))
+ ref = aref[a] * dref[d];
+ if (exists) {
+ if (a == 0 && d == 0)
+## replace m (ref_count = m.ref_count+ref, direct = 1)
+## where m.list_id = lid and m.member_id = mid and
+## m.member_type = mtype
+ else
+## replace m (ref_count = m.ref_count+ref)
+## where m.list_id = lid and m.member_id = mid and
+## m.member_type = mtype
+ } else {
+ incremental_clear_before();
+ if (a == 0 && d == 0)
+## append imembers (list_id=lid, member_id = mid, direct = 1,
+## member_type=mtype, ref_count = 1)
+ else
+## append imembers (list_id=lid, member_id = mid,
+## member_type=mtype, ref_count = ref)
+ iargv[0] = (char *)lid;
+ iargv[1] = mtype;
+ iargv[2] = (char *)mid;
+ incremental_after("members", 0, iargv);
+ }
+ }
+ }
+ lid = *(int *)argv[0];
+ entity = cl->entity;
+ who = cl->client_id;
+## repeat replace list (modtime = "now", modby = @who, modwith = @entity)
+## where list.#list_id = @lid
+ if (ingres_errno) return(mr_errcode);
+ return(MR_SUCCESS);
+##}
+
+
+/* Delete_member_from_list: do list flattening as we go!
+ */
+
+int delete_member_from_list(q, argv, cl)
+ struct query *q;
+ char **argv;
+ client *cl;
+##{
+## int id, lid, mid, cnt, exists, error, who, ref;
+## char *mtype, dtype[9], *entity;
+ int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
+ int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
+ char *dtypes[MAXLISTDEPTH];
+ char *iargv[3];
+
+## range of m is imembers
+ lid = *(int *)argv[0];
+ mtype = argv[1];
+ mid = *(int *)argv[2];
+ /* if the member is not a direct member of the list, punt */
+## repeat retrieve (exists = any(m.list_id where m.list_id=@lid and
+## m.member_id = @mid and m.member_type = @mtype
+## and m.direct = 1))
+ if (ingres_errno) return(mr_errcode);
+ if (!exists)
+ return(MR_NO_MATCH);
+ ancestors[0] = lid;
+ aref[0] = 1;
+ acount = 1;
+## repeat retrieve (id = m.list_id, ref = m.ref_count)
+## where m.member_id = @lid and m.member_type = "LIST" {
+ aref[acount] = ref;
+ ancestors[acount++] = id;
+ if (acount >= MAXLISTDEPTH)
+## endretrieve
+## }
+ if (ingres_errno) return(mr_errcode);
+ if (acount >= MAXLISTDEPTH)
+ return(MR_INTERNAL);
+ descendants[0] = mid;
+ dtypes[0] = mtype;
+ dref[0] = 1;
+ dcount = 1;
+ error = 0;
+ if (!strcmp(mtype, "LIST")) {
+## repeat retrieve (id = m.member_id, dtype = m.member_type,
+## ref = m.ref_count)
+## where m.list_id = @mid {
+ switch (dtype[0]) {
+ case 'L':
+ dtypes[dcount] = "LIST";
+ break;
+ case 'U':
+ dtypes[dcount] = "USER";
+ break;
+ case 'S':
+ dtypes[dcount] = "STRING";
+ break;
+ case 'K':
+ dtypes[dcount] = "KERBEROS";
+ break;
+ default:
+ error++;
+## endretrieve
+ }
+ dref[dcount] = ref;
+ descendants[dcount++] = id;
+ if (dcount >= MAXLISTDEPTH)
+## endretrieve
+## }
+ if (ingres_errno) return(mr_errcode);
+ if (error)
+ return(MR_INTERNAL);
+ }
+ for (a = 0; a < acount; a++) {
+ lid = ancestors[a];
+ for (d = 0; d < dcount; d++) {
+ mid = descendants[d];
+ mtype = dtypes[d];
+ if (mid == lid && !strcmp(mtype, "LIST")) {
+ return(MR_LISTLOOP);
+ }
+## repeat retrieve (cnt = m.ref_count)
+## where m.list_id = @lid and m.member_id = @mid
+## and m.member_type = @mtype
+ ref = aref[a] * dref[d];
+ if (cnt <= ref) {
+ iargv[0] = (char *)lid;
+ iargv[1] = mtype;
+ iargv[2] = (char *)mid;
+ incremental_before("members", 0, iargv);
+## delete m where m.list_id = lid and m.member_id = mid and
+## m.member_type = mtype
+ incremental_clear_after();
+ } else if (a == 0 && d == 0) {
+## replace m (ref_count = m.ref_count-ref, direct = 0)
+## where m.list_id = lid and m.member_id = mid and
+## m.member_type = mtype
+ } else {
+## replace m (ref_count = m.ref_count-ref)
+## where m.list_id = lid and m.member_id = mid and
+## m.member_type = mtype
+ }
+ }
+ }
+ lid = *(int *)argv[0];
+ entity = cl->entity;
+ who = cl->client_id;
+## repeat replace list (modtime = "now", modby = @who, modwith = @entity)
+## where list.#list_id = @lid
+ if (ingres_errno) return(mr_errcode);
+ return(MR_SUCCESS);