]> andersk Git - moira.git/blob - server/qsupport.qc
Changes by mike prior to "appends" fix.
[moira.git] / server / qsupport.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  *      $Log$
9  *      Revision 1.3  1987-07-30 00:26:11  wesommer
10  *      Changes by mike prior to "appends" fix.
11  *
12 Revision 1.2  87/07/29  16:00:39  wesommer
13 Fixed add_locker.
14
15 Revision 1.1  87/07/29  15:13:57  wesommer
16 Initial revision
17
18  */
19
20 #ifndef lint
21 static char *rcsid_qsupport_qc = "$Header$";
22 #endif lint
23
24 #include "query.h"
25 #include "sms_server.h"
26 #include <ctype.h>
27
28 #define SMS_SUCCESS 0
29
30 extern char *whoami;
31
32 /* Specialized Access Routines */
33
34 /**
35  ** access_user - verify that client name equals specified login name
36  **
37  ** Used by: update_user_shell
38  **          update_finger_by_login
39  **
40  **  - since field validation routines are called first, a users_id is
41  **    now in argv[0] instead of the login name.  Therefore, we must 
42  **    convert the client name to a users_id.
43  **/
44
45 access_user(q, argv, cl)
46     struct query *q;
47     char *argv[];
48     client *cl;
49 ##{
50     register struct krbname *krb;
51 ##  int client_id;
52 ##  char *client_name;
53 ##  int rowcount;
54
55     client_name = cl->kname.name;
56 ##  repeat retrieve (client_id = users.users_id) 
57 ##         where users.login = @client_name
58 ##  inquire_equel (rowcount = "rowcount")
59     if (rowcount != 1) return(SMS_PERM);
60     if (client_id != *(int *)argv[0]) return(SMS_PERM);
61
62     return(SMS_SUCCESS);
63 ##}
64     
65 /**
66  ** access_pop - same as access_user plus verifies that a user has only one
67  **              mailbox of type "POP"
68  **
69  ** Inputs:
70  **   argv[0] - users_id
71  **   argv[1] - type
72  **   argv[2] - mach_id
73  **   argv[3] - box
74  **
75  ** Description:
76  **   - if q->name = "add_pobox" and type = "POP", 
77  **        verify that no POP box already exists for user
78  **   - call access_user
79  **
80  **/
81
82 access_pop(q, argv, cl)
83     struct query *q;
84     char *argv[];
85     client *cl;
86 ##{
87 ##  int users_id;
88 ##  int mach_id;
89 ##  char *box;
90 ##  int exists;
91
92     if (!bcmp(q->name, "add_pobox", 10) && !bcmp(argv[1], "POP", 4)) {
93         users_id = *(int *)argv[0];
94         mach_id = *(int *)argv[2];
95         box = argv[3];
96 ##      range of p is pobox
97 ##      repeat retrieve (exists = any(p.#box where p.#users_id = @users_id
98 ##                                    and p.type = "POP" 
99 ##                                    and p.#mach_id = @mach_id
100 ##                                    and p.#box = @box))
101         if (exists) return(SMS_EXISTS);
102     }
103
104     return(access_user(q, argv, cl));
105 ##}
106
107 /**
108  ** access_list - check access for adding or deleting list members
109  **
110  ** Inputs: argv[0] - list_id
111  **         cl->krb.name - client name
112  **
113  ** - check that client is a member of the access control list
114  ** - OR, if q->shortname == {amtl | dfml} and
115  **       if list.flags & LF_PUBLIC, allow access if client = member
116  **
117  **/ 
118
119 access_list(q, argv, cl)
120     struct query *q;
121     char *argv[];
122     client *cl;
123 ##{
124 ##  int list_id;
125 ##  int acl_id;
126 ##  int flags;
127     int member_id;
128     char *client_type;
129     int client_id;
130     int status;
131     int exists;
132
133     list_id = *(int *)argv[0];
134 ##  repeat retrieve (acl_id = list.#acl_id, flags = list.#flags) 
135 ##         where list.#list_id = @list_id
136
137     /* parse client structure */
138     status = get_client(cl, &client_type, &client_id);
139     if (status != SMS_SUCCESS) return(status);
140
141     /* if amtl or dmfl and list is public allow client to add or delete self */
142     if (!bcmp("amtl", q->shortname, 4) || !bcmp("dmfl", q->shortname, 4)) {
143         if ((flags & LF_PUBLIC) && !bcmp("USER", argv[1], 4)) {
144             member_id = *(int *)argv[2];
145             if (member_id == client_id) return(SMS_SUCCESS);
146         }
147     }
148
149     /* check for client in access control list */
150     exists = find_member(acl_id, client_type, client_id, 0);
151     if (!exists) return(SMS_PERM);
152
153     return(SMS_SUCCESS);
154 ##}
155 \f
156 /**
157  ** Setup routine for add_user
158  **
159  ** Inputs: argv[0] - login
160  **         argv[1] - uid
161  **
162  ** Description:
163  **
164  ** - if argv[1] == "#" then set argv[1] = next(uid)
165  ** - if argv[0] == "#" then set argv[0] = "#<uid>"
166  **
167  **/
168
169 setup_add_user(q, argv, cl, access_check)
170     struct query *q;
171     register char *argv[];
172     client *cl;
173     int access_check;
174 ##{
175 ##  int nuid;
176 ##  int exists;
177
178     if (access_check) return(SMS_SUCCESS);
179
180     if (!bcmp(argv[1], "#", 2)) {
181 ##      range of u is users
182 ##      range of v is values
183 ##      repeat retrieve (nuid = v.value) where v.name = "uid"
184         exists = 1;
185         while (exists) {
186             nuid++;
187 ##          repeat retrieve (exists = any(u.#uid where u.#uid = @nuid))
188         }
189 ##      repeat replace v (value = @nuid) where v.name = "uid"
190         sprintf(argv[1], "%d", nuid);
191     }
192
193     if (!bcmp(argv[0], "#", 2)) {
194         sprintf(argv[0], "#%s", argv[1]);
195     }
196
197     return(SMS_SUCCESS);
198 ##}
199
200 /**
201  ** Setup routine for add_group
202  **
203  ** Inputs: none
204  **
205  ** Description: allocate next gid and store in values table
206  **
207  **/
208
209 setup_add_group(q, argv, cl, access_check)
210     struct query *q;
211     char *argv[];
212     client *cl;
213     int access_check;
214 ##{
215 ##  int ngid;
216 ##  int exists;
217
218     if (access_check) return(SMS_SUCCESS);
219
220 ##  range of g is groups
221 ##  range of v is values
222 ##  repeat retrieve (ngid = v.value) where v.name = "gid"
223     exists = 1;
224     while (exists) {
225         ngid++;
226 ##      repeat retrieve (exists = any(g.#gid where g.#gid = @ngid))
227     }
228
229 ##  repeat replace v (value = @ngid) where v.name = "gid"
230     return(SMS_SUCCESS);
231 ##}
232 \f
233 /* Followup Routines */
234
235 set_user_modtime(q, argv)
236     struct query *q;
237     char *argv[];
238 ##{
239 ##  char *login;
240
241     login = argv[0];
242 ##  repeat replace u (modtime = "now") where u.#login = @login
243     return(SMS_SUCCESS);
244 ##}
245
246 set_user_modtime_by_id(q, argv)
247     struct query *q;
248     char *argv[];
249 ##{
250 ##  int users_id;
251
252     users_id = *(int *)argv[0];
253 ##  repeat replace users (modtime = "now") where users.#users_id = @users_id
254     return(SMS_SUCCESS);
255 ##}
256
257 set_list_modtime(q, argv)
258     struct query *q;
259     char *argv[];
260 ##{
261 ##  char *list_name;
262
263     list_name = argv[0];
264 ##  repeat replace list (modtime = "now") where list.name = @list_name
265     return(SMS_SUCCESS);
266 ##}
267
268 set_list_modtime_by_id(q, argv)
269     struct query *q;
270     char *argv[];
271 ##{
272 ##  int list_id;
273
274     list_id = *(int *)argv[0];
275 ##  repeat replace list (modtime = "now") where list.#list_id = @list_id
276     return(SMS_SUCCESS);
277 ##}
278
279 set_finger_modtime(q, argv)
280     struct query *q;
281     char *argv[];
282 ##{
283 ##  int users_id;
284
285     users_id = *(int *)argv[0];
286 ##  repeat replace f (modtime = "now") where f.#users_id = @users_id
287     return(SMS_SUCCESS);
288 ##}
289
290 /**
291  ** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
292  **
293  ** Inputs:
294  **   q->name - "add_pobox" or "delete_pobox"
295  **   argv[2] - mach_id
296  **
297  ** Description:
298  **   - incr/decr value field in serverhosts table for pop/mach_id
299  **
300  **/
301
302 set_pop_usage(q, argv)
303     struct query *q;
304     char *argv[];
305 ##{
306 ##  int mach_id;
307
308     mach_id = *(int *)argv[2];
309 ##  range of sh is serverhosts
310
311     if (!bcmp(q->name, "add_pobox", 10)) {
312 ##      repeat replace sh (value1 = sh.value1 + 1)
313 ##             where sh.service = "pop" and sh.#mach_id = @mach_id
314     } else if (!bcmp(q->name, "delete_pobox", 13)) {
315 ##      repeat replace sh (value1 = sh.value1 - 1)
316 ##             where sh.service = "pop" and sh.#mach_id = @mach_id
317     }
318
319     return(SMS_SUCCESS);
320 ##}
321
322 /**
323  ** delete_list_members - called after the delete_list query to clean up
324  **                       members table.
325  **
326  ** Inputs: argv[0] - list_id
327  **
328  ** Description:
329  **   - foreach string member: decr string refc; ifzero, delete string
330  **   - delete all members entries for this list_id
331  **
332  **/
333
334 delete_list_members(q, argv)
335     struct query *q;
336     register char *argv[];
337 ##{
338 ##  int list_id;
339 ##  int string_id;
340 ##  int refc;
341 ##  int rowcount;
342     struct save_queue *sq;
343     struct save_queue *sq_create();
344
345     list_id = *(int *)argv[0];
346     sq = sq_create();
347
348 ##  range of m is members
349 ##  repeat retrieve (string_id = m.member_id)
350 ##         where m.#list_id = @list_id and m.member_type = "STRING"
351 ##  {
352          sq_save_data(sq, string_id);
353 ##  }
354
355     while (sq_get_data(sq, &string_id)) {
356 ##      range of s is strings
357 ##      repeat retrieve (refc = s.#refc) where s.#string_id = @string_id
358 ##      inquire_equel (rowcount = "rowcount")
359         if (rowcount == 0) continue;
360         if (--refc == 0) {
361 ##          repeat delete s where s.#string_id = @string_id
362         } else {
363 ##          repeat replace s (#refc = @refc) where s.#string_id = @string_id
364         }
365     }
366     sq_destroy(sq);
367
368 ##  repeat delete m where m.#list_id = @list_id
369
370     return(SMS_SUCCESS);
371 ##}
372
373 /**
374  ** grvd_support - Support routine for get_rvd_servers query
375  **
376  ** Inputs:
377  **    q     - grvd query structure
378  **    sq    - save_queue struture: contains list of {machine, oper_acl_id,
379  **            admin_acl_id, shutdown_acl_id} records.
380  **    v     - validate structure (not used)
381  **    action - action routine
382  **    actarg - action routine argument
383  **
384  ** Description:
385  **   - translate acl_ids to list names
386  **
387  **/
388
389 grvd_support(q, sq, v, action, actarg)
390     struct query *q;
391     struct save_queue *sq;
392     struct validate *v;
393     int (*action)();
394     int actarg;
395 ##{
396     char **argv;
397     char *targv[4];
398 ##  char oper[33];
399 ##  char admin[33];
400 ##  char shutdown[33];
401 ##  int list_id;
402
403     targv[0] = oper;
404     targv[1] = admin;
405     targv[2] = shutdown;
406
407 ##  range of l is list
408
409     while (sq_get_data(sq, &argv)) {
410         sscanf(argv[0], "%d", &list_id);
411 ##      repeat retrieve (oper = l.name) where l.#list_id = @list_id
412         sscanf(argv[1], "%d", &list_id);
413 ##      repeat retrieve (admin = l.name) where l.#list_id = @list_id
414         sscanf(argv[2], "%d", &list_id);
415 ##      repeat retrieve (shutdown = l.name) where l.#list_id = @list_id
416         
417         (*action)(3, targv, actarg);
418         free(argv[0]);
419         free(argv[1]);
420         free(argv[2]);
421     }
422
423     sq_destroy(sq);
424     return(SMS_SUCCESS);
425 ##}
426
427 /**
428  ** set_next_object_id - set next object id in values table
429  **
430  ** Inputs: object - object name in values table
431  **
432  ** - called before an APPEND operation to set the next object id to
433  **   be used for the new record
434  **
435  **/
436
437 set_next_object_id(object)
438     char *object;
439 ##{
440 ##  char *name;
441
442     name = object;
443 ##  range of v is values
444 ##  repeat replace v (value = v.value + 1) where v.#name = @name
445     return(SMS_SUCCESS);
446 ##}
447
448 /**
449  ** get_query_need - check modtime of query's associated table against given
450  **                  time and return true if greater (false if not)
451  **
452  ** Inputs:
453  **   argv[0] - query name
454  **   argv[1] - time to compare against
455  **
456  **/
457
458 get_query_need(q, argv, action, actarg)
459     struct query *q;
460     register char *argv[];
461     int (*action)();
462 ##{
463     struct query *q1;
464 ##  char *last_get_time;
465 ##  char *table;
466 ##  int need;
467     char *result;
468     struct query *get_query_by_name();
469
470     q1 = get_query_by_name(argv[0]);
471
472     last_get_time = argv[1];
473     table = q1->rtable;
474
475     if (q1->type != RETRIEVE || table == (char *)0) return(SMS_NO_MATCH);
476
477 ##  range of tbs is tblstats
478 ##  repeat retrieve (need = any(tbs.modtime where tbs.#table = @table and
479 ##                              tbs.modtime > @last_get_time))
480     
481     result = (need) ? "true" : "false";
482     (*action)(1, &result, actarg);
483     return(SMS_SUCCESS);
484 ##}
485
486 \f
487 /**
488  ** add_locker - special query routine for creating a user locker
489  **
490  ** Inputs:
491  **   argv[0] - users_id
492  **   argv[1] - machine_id
493  **   argv[2] - device
494  **   argv[3] - initial quota
495  ** 
496  ** Description:
497  **   - get prefix directory (dir) for mount point on specified machine/device
498  **   - create filesys entry (label=<login>, type=NFS, machine=<machine>,
499  **     mount=<dir>/<login>, access=w, acl=dbadmin)
500  **   - increment allocated in nfsphys by quota
501  **   - create nfsquota entry
502  **
503  ** Errors:
504  **   - SMS_NFSPHYS - machine/device does not exist in nfsphys
505  **   - SMS_FILESYS_EXISTS - file system already exists
506  ** 
507  **/
508
509 add_locker(q, argv)
510     register struct query *q;
511     char *argv[];
512 ##{
513 ##  int users_id;
514 ##  int mach_id;
515 ##  char *device;
516 ##  int quota;
517 ##  int rowcount;
518 ##  char login[9];
519 ##  char dir[32];
520 ##  int allocated;
521 ##  char locker[64];
522 ##  char mount[64];
523 ##  int user_acl;
524
525     /* copy arguments */
526     users_id = *(int *)argv[0];
527     mach_id = *(int *)argv[1];
528     device = argv[2];
529     sscanf(argv[3], "%d", &quota);
530
531 ##  range of u is users
532 ##  range of f is filesys
533 ##  range of np is nfsphys
534 ##  range of tbs is tblstats
535
536     /* get login name */
537 ##  repeat retrieve (login = u.#login) where u.#users_id = @users_id
538
539     /* get user's acl id */
540 ##  repeat retrieve (user_acl = list.list_id) where list.name = @login
541
542     /* get filesystem directory prefix; give error if machine/device
543        pair not in nfsphys table */
544 ##  repeat retrieve (dir = np.#dir, allocated = np.#allocated) 
545 ##         where np.#mach_id = @mach_id and np.#device = device
546 ##  inquire_equel (rowcount = "rowcount")
547     if (rowcount == 0) return(SMS_NFSPHYS);
548
549     /* make sure a filesys with user's name does not already exist */
550 ##  repeat retrieve (rowcount = any(f.label where f.label = @login))
551     if (rowcount != 0) return(SMS_FILESYS_EXISTS);
552
553     /* create a new filesys */
554     sprintf(locker, "%s/%s", dir, login);
555     sprintf(mount, "/mit/%s", login);
556 ##  repeat append filesys 
557 ##             (#label = @login, type = "NFS", #mach_id = @mach_id,
558 ##              name = @locker, access = "w", order = 1, #mount = @mount,
559 ##              acl_id = @user_acl)
560 ##  repeat replace tbs (appends = tbs.appends + 1, modtime = "now")
561 ##             where tbs.table = "filesys"
562
563     /* increment usage count in nfsphys table */
564     allocated += quota;
565 ##  replace np (#allocated = allocated) 
566 ##          where np.#mach_id = mach_id and np.#device = device
567 ##  repeat replace tbs (updates = tbs.updates + 1, modtime = "now")
568 ##             where tbs.table = "nfsphys"
569
570     /* create nfsquota entry */
571 ##  append nfsquota (#users_id = users_id, #mach_id = mach_id,
572 ##                   #device = device, #quota = quota)
573 ##  repeat replace tbs (appends = appends + 1, modtime = "now")
574 ##             where tbs.table = "nfsquota"
575
576     return(SMS_SUCCESS);
577 ##}
578
579 /**
580  ** delete_locker - special query routine for deleting a user locker
581  **
582  ** Inputs:
583  **   argv[0] - users_id
584  **   argv[1] - machine_id
585  **   argv[2] - device
586  **   argv[3] - quota
587  ** 
588  ** Description:
589  **   - delete filesys entry (label=<login>)
590  **   - decrement allocated in nfsphys by quota
591  **   - delete nfsquota entry
592  **
593  ** Errors:
594  **   - SMS_FILESYS - no filesys exists for user
595  ** 
596  **/
597
598 delete_locker(q, argv)
599     register struct query *q;
600     register char *argv[];
601 ##{
602 ##  int users_id;
603 ##  int mach_id;
604 ##  char *device;
605 ##  int quota;
606 ##  int rowcount;
607 ##  char login[9];
608
609     /* copy arguments */
610     users_id = *(int *)argv[0];
611     mach_id = *(int *)argv[1];
612     device = argv[2];
613     sscanf(argv[3], "%d", &quota);
614
615 ##  range of u is users
616 ##  range of f is filesys
617 ##  range of np is nfsphys
618 ##  range of nq is nfsquota
619 ##  range of tbs is tblstats
620
621     /* get login name */
622 ##  repeat retrieve (login = u.#login) where u.#users_id = @users_id
623
624     /* delete the filesys entry */
625 ##  repeat delete f where f.label = @login
626 ##  inquire_equel (rowcount = "rowcount")
627     if (rowcount == 0) return(SMS_FILESYS);
628 ##  repeat replace tbs (deletes = tbs.deletes + 1, modtime = "now")
629 ##             where tbs.table = "filesys"
630
631     /* decrement usage count in nfsphys table */
632 ##  replace np (#allocated = np.#allocated - quota) 
633 ##          where np.#mach_id = mach_id and np.#device = device
634 ##  repeat replace tbs (updates = tbs.updates + 1, modtime = "now")
635 ##             where tbs.table = "nfsphys"
636
637     /* delete nfsquota entry */
638 ##  delete nq where nq.#users_id = users_id and nq.#mach_id = mach_id and
639 ##                  nq.#device = device
640 ##  repeat replace tbs (deletes = tbs.deletes + 1, modtime = "now")
641 ##             where tbs.table = "nfsquota"
642
643     return(SMS_SUCCESS);
644 ##}
645 \f
646 /* Validation Routines */
647
648 validate_row(q, argv, v)
649     register struct query *q;
650     char *argv[];
651     register struct validate *v;
652 ##{
653 ##  char *rvar;
654 ##  char *table;
655 ##  char *name;
656 ##  char qual[128];
657 ##  int rowcount;
658
659     /* build where clause */
660     build_qual(v->qual, v->argc, argv, qual);
661
662     /* setup ingres variables */
663     rvar = q->rvar;
664     table = q->rtable;
665     name = v->field;
666
667     /* tell the logfile what we're doing */
668     com_err(whoami, 0, "validating row");
669     com_err(whoami, 0, qual);
670
671     /* look for the record */
672 ##  range of rvar is table
673 ##  retrieve (rowcount = count(rvar.name where qual))
674     com_err(whoami, 0, "row validated");
675     if (rowcount == 0) return(SMS_NO_MATCH);
676     if (rowcount > 1) return(SMS_NOT_UNIQUE);
677     return(SMS_EXISTS);
678 ##}
679
680 validate_fields(q, argv, vo, n)
681     struct query *q;
682     register char *argv[];
683     register struct valobj *vo;
684     register int n;
685 {
686     register int status;
687     char buf[64];
688
689     while (--n >= 0) {
690         switch (vo->type) {
691         case V_NAME:
692             sprintf(buf, "validating %s in %s: %s", 
693                     vo->namefield, vo->table, argv[vo->index]);
694             com_err(whoami, 0, buf);
695             status = validate_name(argv, vo);
696             break;
697
698         case V_ID:
699             sprintf(buf, "validating %s in %s: %s", 
700                     vo->idfield, vo->table, argv[vo->index]);
701             com_err(whoami, 0, buf);
702             status = validate_id(argv, vo);
703             break;
704
705         case V_TYPE:
706             sprintf(buf, "validating %s type: %s",
707                     vo->table, argv[vo->index]);
708             com_err(whoami, 0, buf);
709             status = validate_type(argv, vo);
710             break;
711
712         case V_TYPEDATA:
713             sprintf(buf, "validating type-specific data: %s",
714                     argv[vo->index]);
715             com_err(whoami, 0, buf);
716             status = validate_typedata(q, argv, vo);
717             break;
718
719         case V_FOLLOWUP:
720             status = SMS_EXISTS;
721             break;
722
723         }
724
725         if (status != SMS_EXISTS) return(status);
726         vo++;
727     }
728
729     return(SMS_SUCCESS);
730 }
731
732 validate_id(argv, vo)
733     char *argv[];
734     register struct valobj *vo;
735 ##{
736 ##  char *name;
737 ##  char *table;
738 ##  char *namefield;
739 ##  char *idfield;
740 ##  int id;
741 ##  int rowcount;
742
743     name = argv[vo->index];
744     table = vo->table;
745     namefield = vo->namefield;
746     idfield = vo->idfield;
747 ##  retrieve (id = table.idfield) where table.namefield = name
748 ##  inquire_equel (rowcount = "rowcount")
749     if (rowcount != 1) return(vo->error);
750     *(int *)argv[vo->index] = id;
751     return(SMS_EXISTS);
752 ##}
753
754 validate_name(argv, vo)
755     char *argv[];
756     register struct valobj *vo;
757 ##{
758 ##  char *name;
759 ##  char *table;
760 ##  char *namefield;
761 ##  int rowcount;
762
763     name = argv[vo->index];
764     table = vo->table;
765     namefield = vo->namefield;
766 ##  retrieve (rowcount = countu(table.namefield 
767 ##            where table.namefield = name))
768     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
769 ##}
770
771 validate_type(argv, vo)
772     char *argv[];
773     register struct valobj *vo;
774 ##{
775 ##  char *typename;
776 ##  char *value;
777 ##  int rowcount;
778     register char *c;
779
780     typename = vo->table;
781     value = argv[vo->index];
782
783     /* uppercase type fields */
784     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
785
786 ##  range of a is alias
787 ##  repeat retrieve (rowcount = count(a.trans where a.name = @typename and
788 ##                                    a.type = "TYPE" and
789 ##                                    a.trans = @value))
790     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
791 ##}
792
793 /* validate member or type-specific data field */
794
795 validate_typedata(q, argv, vo)
796     register struct query *q;
797     register char *argv[];
798     register struct valobj *vo;
799 ##{
800 ##  char *name;
801 ##  char *field_type;
802 ##  char data_type[17];
803 ##  int id;
804 ##  int refc;
805 ##  int rowcount;
806
807     /* get named object */
808     name = argv[vo->index];
809
810     /* get field type string (known to be at index-1) */
811     field_type = argv[vo->index-1];
812
813     /* get corresponding data type associated with field type name */
814 ##  repeat retrieve (data_type = alias.trans) 
815 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
816 ##  inquire_equel (rowcount = "rowcount")
817     if (rowcount != 1) return(SMS_TYPE);
818
819     /* now retrieve the record id corresponding to the named object */
820
821     if (!strcmp(data_type, "user")) {
822         /* USER */
823 ##      repeat retrieve (id = users.users_id) where users.login = @name
824 ##      inquire_equel (rowcount = "rowcount")
825         if (rowcount != 1) return(SMS_USER);
826
827     } else if (!strcmp(data_type, "list")) {
828         /* LIST */
829 ##      repeat retrieve (id = list.list_id) where list.#name = @name
830 ##      inquire_equel (rowcount = "rowcount")
831         if (rowcount != 1) return(SMS_LIST);
832
833     } else if (!strcmp(data_type, "machine")) {
834         /* MACHINE */
835 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
836 ##      inquire_equel (rowcount = "rowcount")
837         if (rowcount != 1) return(SMS_MACHINE);
838
839     } else if (!strcmp(data_type, "string")) {
840         /* STRING */
841 ##      range of s is strings
842 ##      repeat retrieve (id = s.string_id, refc = s.#refc) 
843 ##             where s.string = @name
844 ##      inquire_equel (rowcount = "rowcount")
845         if (rowcount == 0) {
846             if (q->type != APPEND) return(SMS_STRING);
847 ##          range of v is values
848 ##          retrieve (id = v.value) where v.#name = "strings_id"
849             id++;
850 ##          replace v (value = id) where v.#name = "strings_id"
851 ##          append to strings (string_id = id, string = name, #refc = 1)
852         } else if (rowcount == 1) {
853             if (q->type == APPEND || q->type == DELETE) {
854                 refc += (q->type == APPEND) ? 1 : -1;
855                 if (refc > 0) {
856 ##                  replace s (#refc = refc) where s.string_id = id
857                 } else {
858 ##                  delete s where s.string_id = id
859                 }
860             }
861         }
862     } else {
863         return(SMS_TYPE);
864     }
865
866     /* now set value in argv */
867     *(int *)argv[vo->index] = id;
868     
869     return (SMS_EXISTS);
870 ##}
871
872 \f
873 translate_ids(q, sq, v, action, actarg)
874     register struct query *q;
875     register struct save_queue *sq;
876     register struct validate *v;
877     register int (*action)();
878     int actarg;
879 ##{
880 ##  char *name;
881 ##  char *field_type;
882 ##  char data_type[17];
883 ##  int id;
884 ##  int rowcount;
885     register int i;
886     struct valobj *vo;
887     char **argv;
888
889     for (i = 0; i < v->objcnt; i++) {
890         vo = &v->valobj[i];
891         if (vo->type == V_FOLLOWUP) break;
892     }
893
894     /* for each row */
895     while (sq_get_data(sq, &argv)) {
896
897         /* get object id */
898         i = vo->index;
899         sscanf(argv[i], "%d", &id);
900         free(argv[i]);
901         name = (char *)malloc(129);
902         argv[i] = name;
903
904         /* get field type string (known to be at index-1) */
905         field_type = argv[vo->index-1];
906
907         /* get corresponding data type associated with field type name */
908 ##      repeat retrieve (data_type = alias.trans) 
909 ##             where alias.#name = @field_type and alias.type = "TYPEDATA"
910 ##      inquire_equel (rowcount = "rowcount")
911         if (rowcount != 1) {
912             sprintf(name, "%d", id);
913             (*action)(q->vcnt, argv, actarg);
914             continue;
915         }
916
917         /* retrieve object name */
918
919         if (!strcmp(data_type, "user")) {
920             /* USER */
921 ##          repeat retrieve (name = users.login) where users.users_id = @id
922 ##          inquire_equel (rowcount = "rowcount")
923
924         } else if (!strcmp(data_type, "list")) {
925             /* LIST */
926 ##          repeat retrieve (name = list.#name) where list.list_id = @id
927 ##          inquire_equel (rowcount = "rowcount")
928
929         } else if (!strcmp(data_type, "machine")) {
930             /* MACHINE */
931 ##          repeat retrieve (name = machine.#name) where machine.mach_id = @id
932 ##          inquire_equel (rowcount = "rowcount")
933
934         } else if (!strcmp(data_type, "string")) {
935             /* STRING */
936 ##          repeat retrieve (name = strings.string) 
937 ##                 where strings.string_id = @id
938 ##          inquire_equel (rowcount = "rowcount")
939
940         } else {
941             rowcount = 0;
942         }
943
944         /* if there wasn't a corresponding object name, then use the id */
945         if (rowcount != 1) sprintf(name, "%d", id);
946
947         /* send the data */
948         (*action)(q->vcnt, argv, actarg);
949
950         /* free saved data */
951         for (i = 0; i < q->vcnt; i++) 
952             free(argv[i]);
953         free(argv);
954     }
955
956     sq_destroy(sq);
957     return (SMS_SUCCESS);
958 ##}
959 \f
960 /*
961  * Local Variables:
962  * mode: c
963  * c-indent-level: 4
964  * c-continued-statement-offset: 4
965  * c-brace-offset: -4
966  * c-argdecl-indent: 4
967  * c-label-offset: -4
968  * End:
969  */
This page took 0.116171 seconds and 5 git commands to generate.