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