]> git.sur5r.net Git - openldap/blob - clients/ud/mod.c
The world compiles and links....
[openldap] / clients / ud / mod.c
1 /*
2  * Copyright (c) 1991,1993  Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/ctype.h>
18 #include <ac/string.h>
19 #include <ac/time.h>
20
21 #include <lber.h>
22 #include <ldap.h>
23 #include "ud.h"
24
25 extern struct entry Entry; 
26 extern int verbose;
27 extern LDAP *ld;
28
29 extern LDAPMessage *find();
30
31 #ifdef DEBUG
32 extern int debug;
33 #endif
34
35 modify(who)
36 char *who;
37 {
38 #ifdef UOFM
39         void set_updates();     /* routine to modify noBatchUpdates */
40 #endif
41         LDAPMessage *mp;        /* returned from find() */
42         char *dn;               /* distinguished name */
43         char **rdns;            /* for fiddling with the DN */
44         char name[MED_BUF_SIZE];        /* entry to modify */
45         int displayed_choices = 0;
46         static char ans[SMALL_BUF_SIZE];        /* for holding user input */
47 #ifdef UOFM
48         static char printed_warning = 0;        /* for use with the */
49         struct attribute no_batch_update_attr;
50         extern char * fetch_boolean_value();
51 #endif
52         int is_a_group;         /* TRUE if it is; FALSE otherwise */
53         extern void Free();
54         extern int bind_status;
55
56 #ifdef DEBUG
57         if (debug & D_TRACE)
58                 printf("->modify(%s)\n", who);
59 #endif
60         /*
61          *  Require them to bind first if the are modifying a group.
62          */
63         if (bind_status == UD_NOT_BOUND) {
64                 if (auth((char *) NULL, 1) < 0)
65                         return;
66         }
67
68         /*
69          *  First, decide what entry we are going to modify.  If the
70          *  user has not included a name on the modify command line,
71          *  we will use the person who was last looked up with a find
72          *  command.  If there is no value there either, we don't know
73          *  who to modify.
74          *
75          *  Once we know who to modify, be sure that they exist, and
76          *  parse out their DN.
77          */
78         if (who == NULL) {
79                 if (verbose) {
80                         printf("  Enter the name of the person or\n");
81                         printf("  group whose entry you want to modify: ");
82                 }
83                 else
84                         printf("  Modify whose entry? ");
85                 fflush(stdout);
86                 fetch_buffer(name, sizeof(name), stdin);
87                 if (name[0] != '\0')
88                         who = name;
89                 else
90                         return;
91         }
92         if ((mp = find(who, TRUE)) == NULL) {
93                 (void) ldap_msgfree(mp);
94                 printf("  Could not locate \"%s\" in the Directory.\n", who);
95                 return;
96         }
97         dn = ldap_get_dn(ld, ldap_first_entry(ld, mp));
98         rdns = ldap_explode_dn(dn, TRUE);
99         if (verbose)
100                 printf("\n  Modifying Directory entry of \"%s\"\n", *rdns);
101
102 #ifdef UOFM
103         /*
104          *  If verbose mode is turned on and the user has not set a value
105          *  for noBatchUpdates, warn them that what they are about to do
106          *  may be overwritten automatically by that Stinkbug.
107          */
108         no_batch_update_attr.quipu_name = "noBatchUpdates";
109         (void) fetch_boolean_value(dn, no_batch_update_attr);
110         if (verbose && !printed_warning && (ld->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)) {
111                 printed_warning = 1;
112                 printf("\n  WARNING!\n");
113                 printf("  You are about to make a modification to an LDAP entry\n");
114                 printf("  that has its \"automatic updates\" field set to ON.\n");
115                 printf("  This means that the entry will be automatically updated\n");
116                 printf("  each month from official University sources like the\n");
117                 printf("  Personnel Office.  With \"automatic updates\" set to ON,\n");
118                 printf("  the following fields will be overwritten each month:\n");
119                 printf("         Title, home address and phone,\n");
120                 printf("         business address and phone\n");
121                 printf("  If you modify any of these fields, you may want to change\n");
122                 printf("  the \"automatic updates\" field to OFF so that your\n");
123                 printf("  changes will not be overwritten.  You may change this\n");
124                 printf("  setting by choosing \"u\" at the \"Modify what?\" prompt\n");
125         }
126 #endif
127
128         /*
129          *  Current values for user 'who' are being held in 'mp'. We
130          *  should parse up that buffer and fill in the Entry structure.
131          *  Once we're done with that, we can find out which fields the
132          *  user would like to modify.
133          */
134         parse_answer(mp);
135         is_a_group = isgroup();
136         (void) ldap_msgfree(mp);
137         printf("  You now need to specify what field you'd like to modify.\n");
138         for (;;) {
139                 if ( verbose || !displayed_choices ) {
140                         printf("\n  Choices are:\n");
141                         printf("  -----------------------\n");
142                         print_mod_list(is_a_group);
143                         printf("\n  Pressing Return will cancel the process.\n");
144                         displayed_choices = 1;
145                 }
146                 printf("\n  Modify what? ");
147                 fflush(stdout);
148                 fetch_buffer(ans, sizeof(ans), stdin);
149                 if (ans[0] == '\0')
150                         break;
151                 perform_action(ans, dn, is_a_group);
152                 if ((mp = find(*rdns, TRUE)) == NULL)
153                         break;
154                 parse_answer(mp);
155                 (void) ldap_msgfree(mp);
156         }
157         (void) Free(dn);
158         ldap_value_free(rdns);
159         return;
160 }
161
162 /* generic routine for changing any field */
163 void change_field(who, attr)
164 char *who;                      /* DN of entry we are changing */
165 struct attribute attr;          /* attribute to change */
166 {
167
168 #define IS_MOD(x)       (!strncasecmp(resp, (x), strlen(resp)))
169                                 
170         char *get_value();              /* routine to extract values */
171         static char buf[MED_BUF_SIZE];  /* for printing things */
172         static char resp[SMALL_BUF_SIZE];       /* for user input */
173         char *prompt, *prompt2, *more;
174         register int i;                         /* for looping thru values */
175         static LDAPMod mod;
176         static LDAPMod *mods[2] = { &mod };     /* passed to ldap_modify */
177         static char *values[MAX_VALUES];        /* passed to ldap_modify */
178         extern void Free();
179
180 #ifdef DEBUG
181         if (debug & D_TRACE)
182                 printf("->change_field(%x, %s)\n", attr, who);
183 #endif
184         /*
185          *  If there is no current value associated with the attribute,
186          *  then this is the easy case.  Collect one (or more) attributes
187          *  from the user, and then call ldap_modify_s() to write the changes
188          *  to the LDAP server.
189          */
190         for (i = 0; i < MAX_VALUES; i++)
191                 values[i] = NULL;
192         if (attr.values == (char **) NULL) {
193                 printf("\n  No current \"%s\"\n", attr.output_string);
194                 values[0] = get_value(attr.quipu_name, "Enter a value");
195                 if ( values[0] == NULL )
196                         return;
197                 mod.mod_op = LDAP_MOD_REPLACE;
198                 mod.mod_type = attr.quipu_name;
199                 mod.mod_values = values;
200                 for (i = 1; i < MAX_VALUES; i++) {
201                         printf("  Do you wish to add an additional value? ");
202                         fflush(stdout);
203                         fetch_buffer(resp, sizeof(resp), stdin);
204                         if ((resp[0] == 'y') || (resp[0] == 'Y'))
205                                 values[i] = get_value(attr.quipu_name, "Enter an additional value");
206                         else
207                                 break;
208                 }
209 #ifdef DEBUG
210                 if (debug & D_MODIFY) {
211                         printf("  ld = 0x%x\n", ld);
212                         printf("  who = [%s]\n", who);
213                         printf("  mods[0]->mod_op = %1d\n", mods[0]->mod_op);
214                         printf("  mods[0]->mod_type = %s\n", mods[0]->mod_type);
215                         for (i = 0; mods[0]->mod_values[i] != NULL; i++)
216                                 printf("  mods[0]->mod_values[%1d] = %s\n", i, mods[0]->mod_values[i]);
217                 }
218 #endif
219                 if (ldap_modify_s(ld, who, mods)) {
220                         mod_perror(ld);
221                         return;
222                 }
223                 else if (verbose)
224                         printf("  Modification of '%s' complete.\n", attr.output_string);
225                 ldap_uncache_entry( ld, who );
226                 for (i--; i > 0; i--)
227                         (void) Free(values[i]);
228         }
229         /*
230          *  There are values for this attribute already.  In this case,
231          *  we want to allow the user to delete all existing values,
232          *  add additional values to the ones there already, or just
233          *  delete some of the values already present.  DIXIE does not
234          *  handle modifications where the attribute occurs on the LHS
235          *  more than once.  So to delete entries and add entries, we
236          *  need to call ldap_modify() twice.
237          */
238         else {
239                 /*
240                  *  If the attribute holds values which are DNs, print them
241                  *  in a most pleasant way.
242                  */
243                 sprintf(buf, "%s:  ", attr.output_string);
244                 if (!strcmp(attr.quipu_name, "owner"))
245                         (void) print_DN(attr);
246                 else
247                         (void) print_values(attr);
248
249                 if (verbose) {
250                         printf("  You may now:\n");
251                         printf("    Add additional values to the existing ones, OR\n");
252                         printf("    Clear all values listed above, OR\n");
253                         printf("    Delete one of the values listed above, OR\n");
254                         printf("    Replace all of the values above with new ones.\n");
255                 }
256                 printf("\n  Add, Clear, Delete, or Replace? ");
257                 fflush(stdout);
258                 fetch_buffer(resp, sizeof(resp), stdin);
259
260                 /*
261                  *  Bail if they just hit the RETURN key.
262                  */
263                 if (resp[0] == '\0') {
264                         if (verbose)
265                                 printf("\n  No changes made.\n");
266                         return;
267                 }
268
269                 /*
270                  *  If the want to clear the values, just do it.
271                  */
272                 mod.mod_type = attr.quipu_name;
273                 mod.mod_values = values;
274                 if (IS_MOD("clear")) {
275                         mod.mod_op = LDAP_MOD_DELETE;
276                         mod.mod_values = NULL;
277                         if ( verbose && !confirm_action( "All existing values will be removed." )) {
278                                 printf("  Modification halted.\n");
279                                 return;
280                         }
281 #ifdef DEBUG
282                         if (debug & D_MODIFY) {
283                                 printf("Clearing attribute '%s'\n", attr.quipu_name);
284                                 printf("who = [%s]\n", who);
285                                 printf("mod = [%d] [%s] [%x]\n", mod.mod_op,
286                                         mod.mod_type, mod.mod_values);
287                         }
288 #endif
289                         if (ldap_modify_s(ld, who, mods)) {
290                                 mod_perror(ld);
291                                 return;
292                         }
293                         else if (verbose)
294                                 printf("  '%s' has been cleared.\n", attr.output_string);
295                         ldap_uncache_entry( ld,  who );
296                         return;
297                 }
298
299                 if (IS_MOD("add")) {
300                         prompt = "Enter the value you wish to add";
301                         more = "  Add an additional value? ";
302                         prompt2 = "Enter another value you wish to add";
303                         mod.mod_op = LDAP_MOD_ADD;
304                 }
305                 else if (IS_MOD("delete")) {
306                         prompt = "Enter the value you wish to delete";
307                         more = "  Delete an additional value? ";
308                         prompt2 = "Enter another value you wish to delete";
309                         mod.mod_op = LDAP_MOD_DELETE;
310                 }
311                 else if (IS_MOD("replace")) {
312                         prompt = "Enter the new value";
313                         more = "  Add an additional value? ";
314                         prompt2 = "Enter another value you wish to add";
315                         mod.mod_op = LDAP_MOD_REPLACE;
316                         if ( verbose && !confirm_action( "All existing values will be overwritten with the new values you are about to enter." )) {
317                                 printf("  Modification halted.\n");
318                                 return;
319                         }
320
321                 }
322                 else {
323                         printf("  No changes made.\n");
324                         return;
325                 }
326
327                 values[0] = get_value(attr.quipu_name, prompt);
328                 for (i = 1; i < MAX_VALUES; i++) {
329                         printf(more);
330                         fflush(stdout);
331                         fetch_buffer(resp, sizeof(resp), stdin);
332                         if ((resp[0] == 'y') || (resp[0] == 'Y'))
333                                 values[i] = get_value(attr.quipu_name, prompt2);
334                         else
335                                 break;
336                 }
337
338                 /* if the first value in the value-array is NULL, bail */
339                 if (values[0] == NULL) {
340                         if (verbose)
341                                 printf("  No modification made.\n");
342                         return;
343                 }
344 #ifdef DEBUG
345                 if (debug & D_MODIFY) {
346                         printf("  ld = 0x%x\n", ld);
347                         printf("  who = [%s]\n", who);
348                         printf("  mods[0]->mod_op = %1d\n", mods[0]->mod_op);
349                         printf("  mods[0]->mod_type = %s\n", mods[0]->mod_type);
350                         for (i = 0; mods[0]->mod_values[i] != NULL; i++)
351                                 printf("  mods[0]->mod_values[%1d] = %s\n", i, mods[0]->mod_values[i]);
352                 }
353 #endif
354                 if (ldap_modify_s(ld, who, mods)) {
355                         mod_perror(ld);
356                         return;
357                 }
358                 else if (verbose)
359                         printf("  Modifications to '%s' complete.\n", attr.output_string);
360                 ldap_uncache_entry( ld, who );
361                 for (i--; i > 0; i--)
362                         (void) Free(values[i]);
363         }
364         return;
365 }
366
367 /*
368  *  These are used to size the buffers we use when collecting values that
369  *  can cross more than one line.
370  */
371 #define LINE_SIZE       80
372 #define MAX_LINES        6
373 #define MAX_DESC_LINES  24
374 #define INTL_ADDR_LIMIT 30
375
376 char *get_value(id, prompt)
377 char *id, *prompt;
378 {
379         char *cp;               /* for the Malloc() */
380         int count;              /* line # of new value -- if multiline */
381         int multiline = 0;      /* 1 if this value is multiline */
382         static char line[LINE_SIZE];    /* raw line from user */
383         static char buffer[MAX_DESC_LINES * LINE_SIZE]; /* holds ALL of the 
384                                                            lines we get */
385         extern void * Malloc();
386         static char * get_URL();
387
388 #ifdef DEBUG
389         if (debug & D_TRACE)
390                 printf("->get_value(%s, %s)\n", id, prompt);
391 #endif
392         /* if this is a URL, have another routine handle this */
393         if (!strcmp(id, "labeledURL"))
394                 return(get_URL());
395
396         /*
397          *  To start with, we have one line of input from the user.
398          *
399          *  Addresses and multiline description can span multiple lines.
400          *  Other attributes may not.
401          */
402         count = 1;
403         (void) memset(buffer, 0, sizeof(buffer));
404 #ifdef UOFM
405         if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress") || !strcmp(id, "multiLineDescription") || !strcmp(id, "vacationMessage")) 
406 #else
407         if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress"))
408 #endif
409                 multiline = 1;
410         printf("\n  %s:\n", prompt);
411
412         /* fetch lines */
413         for (;;) {
414                 if (multiline)
415                         printf(" %1d: ", count);
416                 else
417                         printf("  > ");
418                 fflush(stdout);
419                 fetch_buffer(line, sizeof(line), stdin);
420
421                 if (line[0] == '\0')
422                         break;
423 #ifdef UOFM
424                 /*
425                  *  Screen out dangerous e-mail addresses of the form:
426                  *
427                  *              user@umich.edu
428                  *
429                  * and addresses that have no '@' symbol at all.
430                  */
431                 if (!strcmp(id, "mail")) {
432                         int i;
433                         char *tmp, *tmp2;
434
435                         /* if this is a group, don't worry */
436                         if (isgroup())
437                                 goto mail_is_good;
438
439                         /* if this address is not @umich.edu, don't worry */
440                         /* ...unless there is no '@' at all! */
441                         tmp = strdup(line);
442                         if ((tmp2 = strrchr(tmp, '@')) == NULL) {
443                         printf("\n");
444                         format("The address you entered is not a valid e-mail address.  E-mail addresses should be of the form \"local@domain\", e.g. bjensen@b.imap.itd.umich.edu", 75, 2 );
445                                 goto mail_is_bad;
446                         }
447                         
448                         *tmp2 = '\0';
449                         tmp2++;
450                         if (strcasecmp(tmp2, "umich.edu"))
451                                 goto mail_is_good;
452
453                         /* if not of the form uid@umich.edu, don't worry */
454                         if ((i = attr_to_index("uid")) < 0)
455                                 goto mail_is_good;
456                         if (strcasecmp(tmp, *(Entry.attrs[i].values)))
457                                 goto mail_is_good;
458                         printf("\n");
459                         format("An e-mail address of the form uniqname@umich.edu is not the form that you want registered in the Directory.  This form is the one to use on business cards, for example, but the Directory should contain your real e-mail address; that is, the address where you really read your mail.", 75, 2);
460
461 mail_is_bad:
462                         printf("\n");
463                         printf("  Please enter a legal e-mail address (or press RETURN to stop)\n");
464                         continue;
465                 }
466 mail_is_good:
467 #endif
468
469                 /*
470                  *  If the attribute which we are gathering is a "owner"
471                  *  then we should lookup the name.  The user is going to
472                  *  either have to change the search base before doing the
473                  *  modify, or the person is going to have to be within the
474                  *  scope of the current search base, or they will need to
475                  *  type in a UFN.
476                  */
477                 if (!strcmp(id, "owner")) {
478                         LDAPMessage *lmp, *elmp;
479                         char *tmp;
480                         
481                         lmp = find(line, FALSE);
482                         if (lmp == (LDAPMessage *) NULL) {
483                                 printf("  Could not find \"%s\" in the Directory\n", line);
484                                 if (verbose) 
485                                         format("Owners of groups must be valid entries in the LDAP Directory.  The name you have typed above could not be found in the LDAP Directory.", 72, 2);
486                                 return(NULL);
487                         }
488                         elmp = ldap_first_entry(ld, lmp);
489                         if (lmp == (LDAPMessage *) NULL) {
490                                 ldap_perror(ld, "ldap_first_entry");
491                                 return(NULL);
492                         }
493                         tmp = ldap_get_dn(ld, elmp);
494                         strcpy(buffer, tmp);
495                         (void) ldap_msgfree(lmp);
496                         break;
497                 }
498
499                 if (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress")) {
500                         if (strlen(line) > INTL_ADDR_LIMIT) {
501                                 printf("  The international standard for addresses only allows for 30-character lines\n");
502                                 printf("  Please re-enter your last line.\n");
503                                 continue;
504                         }
505                 }
506
507                 /*
508                  *  Separate lines of multiline attribute values with
509                  *  dollar signs.  Copy this line into the buffer we
510                  *  use to collect up all of the user-supplied input
511                  *  lines.  If this is not a multiline attribute, we
512                  *  are done.
513                  */
514                 if (count++ > 1)
515                         (void) strcat(buffer, "$");
516                 (void) strcat(buffer, line);
517                 if (!multiline)
518                         break;
519                 if ((count > MAX_LINES) && (!strcmp(id, "postalAddress") || !strcmp(id, "homePostalAddress"))) {
520                         printf("  The international standard for addresses only allows for six lines\n");
521                         break;
522                 }
523 #ifdef UOFM
524                 if ((count > MAX_DESC_LINES) && !strcmp(id, "multiLineDescription")) {
525                         printf("  We only allow %d lines of description\n", MAX_DESC_LINES);
526                         break;
527                 }
528 #endif
529         }
530         if (buffer[0] == '\0')
531                 return(NULL);
532 #ifdef DEBUG
533         if (debug & D_MODIFY)
534                 printf("  Value is [%s]\n", buffer);
535 #endif
536         cp = (char *) Malloc((unsigned) (strlen(buffer) + 1));
537         strcpy(cp, buffer);
538         return(cp);
539 }
540
541 void set_boolean(who, attr)
542 char *who;                      /* DN of entry we are changing */
543 struct attribute attr;          /* boolean attribute to change */
544 {
545         char *cp, *s;
546         extern char * fetch_boolean_value();
547         static char response[16];
548         static char *newsetting[2] = { NULL, NULL };
549         LDAPMod mod, *mods[2];
550
551 #ifdef DEBUG
552         if (debug & D_TRACE)
553                 printf("->set_boolean(%s, %s)\n", who, attr.quipu_name);
554 #endif
555         mods[0] = &mod;
556         mods[1] = (LDAPMod *) NULL;
557         mod.mod_op = LDAP_MOD_REPLACE;
558         mod.mod_type = attr.quipu_name;
559         mod.mod_values = newsetting;
560
561         /* fetch the current setting */
562         if ((cp = fetch_boolean_value(who, attr)) == NULL)
563                 return;
564         if (!strcmp(cp, "TRUE"))
565                 newsetting[0] = "FALSE";
566         else if (!strcmp(cp, "FALSE"))
567                 newsetting[0] = "TRUE";
568         else {
569                 printf("  This field needs to be set to either TRUE or to FALSE.\n");
570                 printf("  \"%s\" is not a legal value.  Please set this field to either TRUE or to FALSE.\n", cp);
571                 newsetting[0] = "FALSE";
572         }
573
574         /* see if they want to change it */
575         printf("\n");
576         printf("  The current value of this field is %s.\n", cp);
577         printf("  Should I change the value of this field to %s?\n", 
578                                                         newsetting[0]);
579         printf("  Please enter Y for yes, N for no, or RETURN to cancel:  ");
580         fflush(stdout);
581         (void) fetch_buffer(response, sizeof(response), stdin);
582         for (s = response; isspace(*s); s++)
583                         ;
584         if ((*s == 'y') || (*s == 'Y')) {
585                 if (ldap_modify_s(ld, who, mods)) {
586                         mod_perror(ld);
587                         return;
588                 }
589                 else if (verbose)
590                         printf("  Setting has been changed\n");
591                 ldap_uncache_entry(ld, who);
592                 return;
593         }
594         if (verbose)
595                 printf("  Setting has not been changed\n");
596 }
597
598 #ifdef UOFM
599
600 void set_updates(who)
601 char *who;
602 {
603         char *cp, *s;
604         extern char * fetch_boolean_value();
605         static char response[16];
606         static char value[6];
607         static char *newsetting[2] = { value, NULL };
608         LDAPMod mod, *mods[2];
609         struct attribute attr;
610
611 #ifdef DEBUG
612         if (debug & D_TRACE)
613                 printf("->set_updates(%s)\n", who);
614 #endif
615         mods[0] = &mod;
616         mods[1] = (LDAPMod *) NULL;
617         mod.mod_op = LDAP_MOD_REPLACE;
618         mod.mod_type = "noBatchUpdates";
619         mod.mod_values = newsetting;
620         /* explain what the implications are */
621         if (verbose) {
622                 printf("\n  By default, updates that are received from the Personnel\n");
623                 printf("  Office and the Office of the Registrar are applied to all\n");
624                 printf("  entries in the LDAP database each month.  Sometimes this\n");
625                 printf("  feature is undesirable.  For example, if you maintain your\n");
626                 printf("  entry in the LDAP database manually, you may not want to\n");
627                 printf("  have these updates applied to your entry, possibly overwriting\n");
628                 printf("  correct information with out-dated information.\n\n");
629         }
630
631         /* fetch the current setting */
632         attr.quipu_name = "noBatchUpdates";
633         if ((cp = fetch_boolean_value(who, attr)) == NULL)
634                 return;
635         if (!strcmp(cp, "TRUE"))
636                 printf("  Automatic updates are currently turned OFF\n");
637         else if (!strcmp(cp, "FALSE"))
638                 printf("  Automatic updates are currently turned ON\n");
639         else {
640                 fprintf(stderr, "  Unknown update flag -> [%s]\n", cp);
641                 return;
642         }
643
644         /* see if they want to change it */
645         printf("\n  Change this setting [no]? ");
646         fflush(stdout);
647         (void) fetch_buffer(response, sizeof(response), stdin);
648         for (s = response; isspace(*s); s++)
649                         ;
650         if ((*s == 'y') || (*s == 'Y')) {
651                 if (!strcmp(cp, "TRUE"))
652                         strcpy(value, "FALSE");
653                 else
654                         strcpy(value, "TRUE");
655                 if (ldap_modify_s(ld, who, mods)) {
656                         mod_perror(ld);
657                         return;
658                 }
659                 else if (verbose)
660                         printf("  Setting has been changed\n");
661                 ldap_uncache_entry( ld, who );
662                 return;
663         }
664         if (verbose)
665                 printf("  Setting has not been changed\n");
666 }
667
668 #endif
669
670 print_mod_list(group)
671 int group;
672 {
673         register int i, j = 1;
674         extern struct attribute attrlist[];
675
676         if (group == TRUE) {
677             for (i = 0; attrlist[i].quipu_name != NULL; i++) {
678                 if (attrlist[i].flags & ATTR_FLAG_GROUP_MOD) {
679                         printf("  %2d ->  %s\n", j, attrlist[i].output_string);
680                         j++;
681                 }
682             }
683         } else {
684             for (i = 0; attrlist[i].quipu_name != NULL; i++) {
685                 if (attrlist[i].flags & ATTR_FLAG_PERSON_MOD) {
686                         printf("  %2d ->  %s\n", j, attrlist[i].output_string);
687                         j++;
688                 }
689             }
690         }
691         printf("   ? ->  Print this list\n\n");
692         printf("  Press the RETURN key without typing a number to quit.\n");
693 #ifdef UOFM
694         if (group == FALSE)
695                 printf("  To add nicknames, send mail to x500-nicknames@umich.edu\n");
696 #endif
697 }
698                         
699 perform_action(choice, dn, group)
700 char choice[];
701 char *dn;
702 int group;
703 {
704         int selection;
705         register int i, j = 1;
706         extern struct attribute attrlist[];
707         extern void mod_addrDN(), change_field(), set_boolean();
708
709         selection = atoi(choice);
710         if (selection < 1) {
711                 printf("\n  Choices are:\n");
712                 printf("  -----------------------\n");
713                 print_mod_list(group);
714                 return(1);
715                 /* NOTREACHED */
716         }
717
718         if (group == TRUE) {
719             for (i = 0; attrlist[i].quipu_name != NULL; i++) {
720                 if (attrlist[i].flags & ATTR_FLAG_GROUP_MOD) {
721                         if (j == selection)
722                                 break;
723                         j++;
724                 }
725             }
726         } else {
727             for (i = 0; attrlist[i].quipu_name != NULL; i++) {
728                 if (attrlist[i].flags & ATTR_FLAG_PERSON_MOD) {
729                         if (j == selection)
730                                 break;
731                         j++;
732                 }
733             }
734         }
735
736         if (attrlist[i].quipu_name == NULL) {
737                 printf("\n  Choices are:\n");
738                 printf("  -----------------------\n");
739                 print_mod_list(group);
740                 return(1);
741                 /* NOTREACHED */
742         }
743         if (attrlist[i].mod_func == change_field)
744                 (*attrlist[i].mod_func)(dn, Entry.attrs[attr_to_index(attrlist[i].quipu_name)]);
745         else if (attrlist[i].mod_func == mod_addrDN)
746                 (*attrlist[i].mod_func)(dn, i);
747         else if (attrlist[i].mod_func == set_boolean)
748                 (*attrlist[i].mod_func)(dn, Entry.attrs[attr_to_index(attrlist[i].quipu_name)]);
749         else
750                 (*attrlist[i].mod_func)(dn);
751         return(0);
752 }
753
754 static char * get_URL()
755 {
756         char *rvalue, label[MED_BUF_SIZE], url[MED_BUF_SIZE];
757         static int check_URL();
758         extern void * Malloc();
759
760         if (verbose) {
761                 printf("  First, enter the URL.  (Example: http://www.us.itd.umich.edu/users/).\n");
762                 printf("  The URL may be up to %d characters long.\n", MED_BUF_SIZE);
763         }
764         for (;;) {
765                 printf("  URL: ");
766                 fflush(stdout);
767                 (void) fetch_buffer(url, sizeof(url), stdin);
768                 if (*url == '\0')
769                         continue;
770                 if (check_URL(url) == 0)
771                         break;
772                 printf("  A URL may not have any spaces or tabs in it.  Please re-enter your URL.\n\n");
773         }
774         if (verbose)
775                 printf("\n  Now please enter a descriptive label for this URL\n");
776         do {
777                 printf("  Label: ");
778                 fflush(stdout);
779                 (void) fetch_buffer(label, sizeof(label), stdin);
780         } while (label[0] == '\0');
781         rvalue = (char *) Malloc((unsigned) (strlen(url) + 2 + strlen(label)));
782         sprintf(rvalue, "%s %s", url, label);
783         return((char *) rvalue);
784 }
785
786 static check_URL(url)
787 char *url;
788 {
789         register char *cp;
790
791         for (cp = url; *cp != '\n' && *cp != '\0'; cp++) {
792                 if (isspace(*cp))
793                         return(-1);
794                         /*NOTREACHED*/
795         }
796         *cp = '\0';
797         return(0);
798 }
799
800
801 mod_perror( LDAP *ld )
802 {
803         if ( ld == NULL || ( ld->ld_errno != LDAP_UNAVAILABLE &&
804             ld->ld_errno != LDAP_UNWILLING_TO_PERFORM )) {
805                 ldap_perror( ld, "modify" );
806                 return;
807         }
808
809         fprintf( stderr, "\n  modify: failed because part of the online directory is not able\n" );
810         fprintf( stderr, "  to be modified right now" );
811         if ( ld->ld_errno == LDAP_UNAVAILABLE ) {
812                 fprintf( stderr, " or is temporarily unavailable" );
813         }
814         fprintf( stderr, ".\n  Please try again later.\n" );
815 }