Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / programs / dtcm / dtcm / group_editor.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: group_editor.c /main/10 1999/02/23 09:42:27 mgreess $ */
24 /*
25  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26  *  (c) Copyright 1993, 1994 International Business Machines Corp.
27  *  (c) Copyright 1993, 1994 Novell, Inc.
28  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
29  */
30
31 #include <EUSCompat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <Xm/Xm.h>
37 #include <Xm/DialogS.h>
38 #include <Xm/Form.h>
39 #include <Xm/List.h>
40 #include <Xm/Frame.h>
41 #include <Xm/PushB.h>
42 #include <Xm/RowColumn.h>
43 #include <Xm/SeparatoG.h>
44 #include <Xm/ToggleBG.h>
45 #include <Xm/Text.h>
46 #include <Xm/LabelG.h>
47 #include <Xm/DragDrop.h>
48 #include <Dt/Dt.h>
49 #include <Dt/Dnd.h>
50 #include <Dt/HourGlass.h>
51 #include <Dt/Icon.h>
52 #include <Tt/tttk.h>
53 #include "group_editor.h"
54 #include "editor.h"
55 #include "calendar.h"
56 #include "browser.h"
57 #include "blist.h"
58 #include "datefield.h"
59 #include "deskset.h"
60 #include "getdate.h"
61 #include "format.h"
62 #include "timeops.h"
63 #include "props.h"
64 #include "props_pu.h"
65 #include "util.h"
66 #include "dnd.h"
67 #include "help.h"
68 #include "cm_tty.h"
69 #ifdef SVR4
70 #include <sys/param.h>
71 #endif /* SVR4 */
72
73 #define ACCESS_NAME_LEN 25
74 extern  int _csa_duration_to_iso8601(int, char *);
75 extern void scrub_attr_list(Dtcm_appointment *);
76 extern boolean_t compare_repeat_info(Dtcm_appointment *, RFP *, CSA_session_handle, int);
77 extern void change_rule_for_this_one_only(Calendar *, Dtcm_appointment *, Dtcm_appointment *);
78 static void ge_build_expand(GEditor *);
79
80
81 /* Absolute value macro */
82 #ifndef ABS
83 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
84 #endif
85
86 static void
87 ge_mail_proc(Widget w, XtPointer client_data, XtPointer data);
88 static Dtcm_appointment*
89 form_to_appt(GEditor *ge, Boolean no_reminders, int version);
90
91 extern int debug;
92
93 /*******************************************************************************
94 **
95 **  Functions static to group_editor.c
96 **
97 *******************************************************************************/
98 static void
99 ge_add_to_gappt_list(Access_data *ad, int idx, GEditor *ge, Boolean reset) {
100         int                     cnt = 1;
101         char                    buf[DEFAULT_GAPPT_LEN], *name1, *name2 = NULL;
102         Props                   *p = (Props *)ge->cal->properties;
103         XmString                str;
104         List_data               *step = NULL, *last = NULL;
105         CSA_return_code         stat;
106         DisplayType             dt = get_int_prop(p, CP_DEFAULTDISP);
107         Dtcm_appointment        *appt;
108         Tick                    start_tick;
109
110         /*
111         **  If the reset flag is true, the items have been deleted from the
112         **  scrolling list, so clear our internal buffer - otherwise prime the
113         **  linked list position pointer to find the correct entry point for
114         **  this appointment.
115         */
116         if (reset)
117                 CmDataListDeleteAll(ge->list_data, True);
118         else
119                 step = (List_data *)CmDataListGetData(ge->list_data, cnt);
120
121         /*
122         **  Get the necessary entry attributes
123         */
124         appt = allocate_appt_struct(appt_read,
125                                     ad->version,
126                                     CSA_ENTRY_ATTR_START_DATE_I,
127                                     CSA_ENTRY_ATTR_SUMMARY_I,
128                                     CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
129                                     NULL);
130         stat = query_appt_struct(ge->cal->cal_handle, ad->appt_head[idx], appt);
131         backend_err_msg(ge->frame, ge->cal->view->current_calendar, stat,
132                         ((Props_pu *)ge->cal->properties_pu)->xm_error_pixmap);
133         if (stat != CSA_SUCCESS) {
134                 free_appt_struct(&appt);
135                 return;
136         }
137
138         /*
139         **  Find the correct position for this appointment in the scrolling
140         **  list (mirrored by our internal linked list) and add the necessary
141         **  stuff to our internal list.
142         */
143         _csa_iso8601_to_tick(appt->time->value->item.date_time_value, &start_tick);
144         while (step && start_tick >= step->tick)
145                 step = (List_data *)CmDataListGetData(ge->list_data, ++cnt);
146
147         step = (List_data *)ckalloc(sizeof(List_data));
148         step->entry_idx = idx;
149         step->tick = start_tick;
150         step->ad = ad;
151         CmDataListAdd(ge->list_data, (void *)step, cnt);
152
153         /*
154         **  Now determine the formatting for the appointment - if it has the
155         **  same time as the last appt, leave off the time, and if it has the
156         **  same owner as the last one, leave the the owner.
157         */
158         step = (cnt <= 1) ?
159                 NULL : (List_data *)CmDataListGetData(ge->list_data, cnt - 1);
160         name1 = cm_target2name(ad->name);
161         if (step && step->ad)
162                 name2 = cm_target2name(step->ad->name);
163         if (!step || start_tick != step->tick || reset)
164                 format_gappt(appt, ad->name, buf, dt, DEFAULT_GAPPT_LEN);
165         else {
166
167
168                 /* Potentially nasty memory bug here.  The assumption is 
169                    that the buffer supplied for the time format is the 
170                    right size for the new format. */
171
172                 _csa_tick_to_iso8601(0, appt->time->value->item.date_time_value);
173                 if (!step || strcmp(ad->name, name2) != 0)
174                         format_gappt(appt, ad->name, buf, dt, DEFAULT_GAPPT_LEN);
175                 else
176                         format_gappt(appt, NULL, buf, dt, DEFAULT_GAPPT_LEN);
177         }
178
179         /*
180         **  Create the string, add it to the list, and clean up
181         */
182         str = XmStringCreateLocalized(buf);
183         XmListAddItem(ge->appt_list, str, cnt);
184         if (name1)
185                 free(name1);
186         if (name2)
187                 free(name2);
188         XmStringFree(str);
189         free_appt_struct(&appt);
190 }
191
192 /*
193 **  This function will take appointment values and stuff them into a form.
194 */
195 static void
196 appt_to_form(GEditor *ge, CSA_entry_handle a, char *name, int version) {
197         char                    buf[MAXNAMELEN];
198         Props_pu                *pu = (Props_pu *)ge->cal->properties_pu;
199         CSA_return_code         stat;
200         Dtcm_appointment        *appt;
201
202         if (!ge->rfp.rfp_form_mgr) {
203                 ge_build_expand(ge);
204                 set_rfp_defaults(&ge->rfp);
205         }
206
207         if (!dssw_appt_to_form(&ge->dssw, a))
208                 return;
209         ge->dsswFlags = 0;
210         if (!rfp_appt_to_form(&ge->rfp, a))
211                 return;
212         ge->rfpFlags = 0;
213
214         appt = allocate_appt_struct(appt_read, 
215                                         version,
216                                         CSA_ENTRY_ATTR_ORGANIZER_I, 
217                                         NULL);
218         stat = query_appt_struct(ge->cal->cal_handle, a, appt);
219         backend_err_msg(ge->frame, name, stat, pu->xm_error_pixmap);
220         if (stat == CSA_SUCCESS) {
221                 sprintf(buf, "%s:  %s",
222                         catgets(ge->cal->DT_catd, 1, 300, "Author"),
223                         appt->author->value->item.calendar_user_value->user_name);
224                 set_message(ge->message_text, buf);
225         } else
226                 set_message(ge->message_text, " ");
227
228         free_appt_struct(&appt);
229 }
230
231 /*
232 **  List selection procedure will get the correct appointment, then call
233 **  appt_to_form to load it into the UI.
234 */
235 static void
236 ge_list_select_proc(Widget w, XtPointer client_data, XtPointer data) {
237         int                     cnt;
238         GEditor                 *ge = (GEditor *)client_data;
239         CSA_entry_handle        a;
240         List_data               *ld;
241         Access_data             *ad, *step_ad;
242         XmListCallbackStruct    *cbs = (XmListCallbackStruct *)data;
243
244         if (a = geditor_nth_appt(ge, cbs->item_position, &ad))
245                 appt_to_form(ge, a, (ad && ad->name) ? ad->name : "\0", ad->version);
246         XmListDeselectAllItems(ge->access_list);
247         if (!ad || !ad->name)
248                 return;
249
250         cnt = 1;
251         step_ad = (Access_data *)CmDataListGetData(ge->access_data, cnt);
252         while (step_ad && strcmp(step_ad->name, ad->name) != 0)
253                 step_ad = (Access_data *)CmDataListGetData(ge->access_data,
254                                                            ++cnt);
255         if (step_ad)
256                 XmListSelectPos(ge->access_list, cnt, True);
257
258         XtVaSetValues(ge->change_button, XmNsensitive, True, NULL);
259         XtVaSetValues(ge->delete_button, XmNsensitive, True, NULL);
260 }
261
262 static void
263 ge_set_modify_buttons(GEditor *ge, int cnt) {
264         char    buf[MAXNAMELEN];
265         Boolean val;
266
267         if (cnt == 1)
268                 sprintf(buf, "%d %s.", cnt,
269                         catgets(ge->cal->DT_catd, 1, 633, "Calendar Selected"));
270         else
271                 sprintf(buf, "%d %s.", cnt,
272                         catgets(ge->cal->DT_catd, 1, 634, "Calendars Selected"));
273         set_message(ge->message_text, buf);
274
275 }
276
277 /*
278 **  List selection procedure will ensure that when more than one calendar name
279 **  is selected the change and delete buttons will be greyed.
280 */
281 static void
282 ge_access_select_proc(Widget w, XtPointer client_data, XtPointer data) {
283         GEditor                 *ge = (GEditor *)client_data;
284         XmListCallbackStruct    *cbs = (XmListCallbackStruct *)data;
285
286         ge_set_modify_buttons(ge, cbs->selected_item_count);
287 }
288
289 static Tt_message
290 reply_cb(Tt_message m, void *c_data, Tttk_op op, unsigned char *contents, int len, char *file)
291 {
292         char *client_procID = tt_message_handler(m);
293         if ( debug && (client_procID != NULL) ) {
294                 fprintf(stderr, "DEBUG: reply_cb():client_procID = %s\n", client_procID);
295                 fprintf(stderr, "DEBUG: reply_cb():message_op = %s\n", tt_message_op(m));
296         }
297         return(m);
298 }
299
300 static char *
301 get_mail_address_list(Calendar *c) {
302         int             i, *pos_list = NULL, pos_cnt;
303         GEditor         *ge = (GEditor *)c->geditor;
304         Access_data     *ad;
305         int             address_len;
306         char            *address;
307
308
309         XmListGetSelectedPos(ge->access_list, &pos_list, &pos_cnt);
310         for (i = 0, address_len = 0; i < pos_cnt; i++) {
311                 ad = (Access_data *)CmDataListGetData(ge->access_data,
312                                                     pos_list[i]);
313                 if (ad)
314                         address_len += strlen(ad->name) + 1;
315         }
316
317         address = calloc(address_len+1, 1);
318
319         for (i = 0; i < pos_cnt; i++) {
320                 ad = (Access_data *)CmDataListGetData(ge->access_data,
321                                                     pos_list[i]);
322                 if (ad) {
323                         strcat(address, ad->name);
324                         strcat(address, " ");
325                 }
326         }
327         if (pos_list)
328                 XtFree((XtPointer)pos_list);
329
330         return(address);
331 }
332
333 /*
334 **  Callback from the Mail... button will popup the compose window
335 */
336 static void
337 ge_mail_proc(Widget w, XtPointer client_data, XtPointer data) {
338         GEditor         *ge = (GEditor *)client_data;
339         Calendar        *c = ge->cal;
340         Props_pu        *p = (Props_pu *)ge->cal->properties_pu;
341         Tt_message      msg;
342         Tt_status       status;
343         char            *appointment_buf;
344         char            *mime_buf;
345         Dtcm_appointment        *appt;
346         char            *address = get_mail_address_list(c);
347         char            *address_list[1];
348  
349         /* Send ToolTalk message to bring up compose GUI with buffer as attachme
350 nt */
351
352         appt = form_to_appt(ge, False, DATAVER4);
353  
354         appointment_buf = parse_attrs_to_string(appt, (Props *) c->properties, attrs_to_string(appt->attrs, appt->count));
355
356
357         free_appt_struct(&appt);
358
359         address_list[0] = appointment_buf;
360
361         mime_buf = create_rfc_message(address, "message", address_list, 1);
362  
363         msg = ttmedia_load(0, (Ttmedia_load_msg_cb)reply_cb, NULL, TTME_MAIL_EDIT, "RFC_822_MESSAGE", (unsigned char *)mime_buf, strlen(mime_buf), NULL, "dtcm_appointment_attachment", 0);
364  
365         status = tt_ptr_error(msg);
366         if (tt_is_err(status))
367         {
368                 fprintf(stderr, "dtcm: ttmedia_load: %s\n",
369                         tt_status_message(status));
370         }
371         else
372         {
373             status = tt_message_send(msg);
374             if (tt_is_err(status))
375                 fprintf(stderr, "dtcm: tt_message_send: %s\n",
376                         tt_status_message(status));
377         }
378
379         free(appointment_buf);
380         free(mime_buf);
381         free(address);
382 }
383
384 /*
385 **  This function creates the expando stuff on a form manager.
386 */
387 static void
388 ge_build_expand(GEditor *ge) {
389         Props           *p = (Props *)ge->cal->properties;
390         XmString        xmstr;
391         Calendar        *c = ge->cal;
392         Widget          widgets[20];
393         WidgetList      children;
394         int             i = 0,
395                         j = 0,
396                         n;
397         /*
398         **  Build the rfp "widget"
399         */
400         ge->rfpFlags = 0;
401         build_rfp(&ge->rfp, ge->cal, ge->base_form_mgr);
402         XtVaSetValues(ge->rfp.rfp_form_mgr,
403                 XmNbottomAttachment, XmATTACH_WIDGET,
404                 XmNbottomWidget, ge->separator2,
405                 XmNbottomOffset, 5,
406                 XmNleftAttachment, XmATTACH_FORM,
407                 XmNleftOffset, 5,
408                 NULL);
409         XtVaGetValues(ge->rfp.rfp_form_mgr,
410                 XmNchildren,            &children,
411                 XmNnumChildren,         &n,
412                 NULL);
413
414         /* We don't want to manage the privacy widgets */
415         for (i = 0; i < n; i++) {
416                 if ((children[i] == ge->rfp.privacy_label) ||
417                     (children[i] == ge->rfp.privacy_menu))
418                     continue;
419                 widgets[j++] = children[i];
420         }
421         XtManageChildren(widgets, n - 2);
422
423         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 304, "Mail..."));
424         ge->mail_button = XtVaCreateWidget("mail",
425                 xmPushButtonWidgetClass, ge->base_form_mgr,
426                 XmNlabelString, xmstr,
427                 XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
428                 XmNbottomWidget, ge->rfp.rfp_form_mgr,
429                 XmNrightAttachment, XmATTACH_FORM,
430                 XmNrightOffset, 5,
431                 NULL);
432         XmStringFree(xmstr);
433         XtAddCallback(ge->mail_button, XmNactivateCallback, ge_mail_proc, ge);
434
435         XtSetSensitive(ge->mail_button, c->tt_procid == NULL ? False : True);
436 }
437
438 /*
439 **  Button action procedures manage and unmanage the "extra" stuff in the UI to
440 **  make it visible and invisible to the user.
441 */
442 static void
443 ge_expand_ui_proc(Widget w, XtPointer client_data, XtPointer data) {
444         GEditor         *ge = (GEditor *)client_data;
445         XmString        xmstr;
446         Dimension       h, height, width;
447         static Boolean  expand_state_closed = True;
448
449         /* This is really hokey.  There is a problem in the Motif code 
450            that figures out traversals.  In the case of the appointment 
451            editor, when the widgets are traversed, that the appointment 
452            editor is them expanded, the traversal list is left in an 
453            incorrect state.  The only way to straighten this out is 
454            to trick the traversal code into re-evaluating the traversal 
455            list.  We do this by setting one of the forms insensitive, 
456            and then back to sensitive.  There is no visual impact, and 
457            it seems to work.  Do *not* remove these calls to 
458            XtSetSensitive(), of the synlib tests will stop working. */
459
460         XtVaGetValues(ge->appt_list_sw, XmNheight, &height, NULL);
461         XtVaGetValues(ge->access_list_sw, XmNwidth, &width, NULL);
462
463         if (expand_state_closed) {
464                 Widget children[2];
465
466                 if (!ge->rfp.rfp_form_mgr) {
467                         ge_build_expand(ge);
468                         set_rfp_defaults(&ge->rfp);
469                 }
470
471                 XtSetSensitive(ge->rfp.rfp_form_mgr, False);
472                 XtRealizeWidget(ge->rfp.rfp_form_mgr);
473
474                 xmstr = XmStringCreateLocalized(
475                                 catgets(ge->cal->DT_catd, 1, 625, "Less"));
476                 XtVaSetValues(ge->expand_ui_button, 
477                         XmNlabelString, xmstr,
478                         NULL);
479                 XmStringFree(xmstr);
480
481                 XtVaGetValues(ge->rfp.rfp_form_mgr, XmNheight, &h, NULL);
482                 XtVaSetValues(ge->separator1, XmNbottomOffset, h + 10, NULL);
483                 
484                 children[0] = ge->rfp.rfp_form_mgr;
485                 children[1] = ge->mail_button;
486
487                 XtManageChildren(children, 2);
488
489                 expand_state_closed = False;
490         } else {
491                 XtSetSensitive(ge->rfp.rfp_form_mgr, False);
492                 xmstr = XmStringCreateLocalized(catgets(ge->cal->DT_catd, 1, 626,
493                                                         "More"));
494                 XtVaSetValues(ge->expand_ui_button, XmNlabelString, xmstr,
495                         NULL);
496                 XmStringFree(xmstr);
497                 XtVaSetValues(ge->separator1, XmNbottomOffset, 0, NULL);
498                 XtUnmanageChild(ge->rfp.rfp_form_mgr);
499                 XtUnmanageChild(ge->mail_button);
500                 expand_state_closed = True;
501         }
502         XtVaSetValues(ge->appt_list_sw, XmNheight, height, NULL);
503         XtVaSetValues(ge->access_list_sw, XmNwidth, width, NULL);
504         XtSetSensitive(ge->rfp.rfp_form_mgr, True);
505 }
506
507 static Tick
508 ge_reminder_val(Props *p, Props_op scope, Props_op unit) {
509         int     i_val = get_int_prop(p, unit);
510         char    *s_val = get_char_prop(p, scope);
511
512         switch (convert_time_scope_str(s_val)) {
513         case TIME_DAYS:
514                 return days_to_seconds(i_val);
515         case TIME_HRS:
516                 return hours_to_seconds(i_val);
517         case TIME_MINS:
518         default:
519                 return minutes_to_seconds(i_val);
520         }
521 }
522
523 /*
524 **  This function will consume form values and stuff them into an appointment.
525 */
526 static Dtcm_appointment*
527 form_to_appt(GEditor *ge, Boolean no_reminders, int version) {
528         Props                   *p = (Props *)ge->cal->properties;
529         boolean_t               all_ok;
530         Dtcm_appointment        *a = NULL;
531
532         if (no_reminders) {
533
534                 if (version <= DATAVER2)
535                 a = allocate_appt_struct(appt_write,
536                                          version,
537                                          CSA_ENTRY_ATTR_START_DATE_I,
538                                          CSA_ENTRY_ATTR_TYPE_I,
539                                          CSA_ENTRY_ATTR_SUBTYPE_I,
540                                          CSA_ENTRY_ATTR_CLASSIFICATION_I,
541                                          CSA_ENTRY_ATTR_END_DATE_I,
542                                          CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
543                                          CSA_ENTRY_ATTR_SUMMARY_I,
544                                          CSA_ENTRY_ATTR_STATUS_I,
545                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
546                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
547                                          NULL);
548                 else if (version == DATAVER3)
549                 a = allocate_appt_struct(appt_write,
550                                          version,
551                                          CSA_ENTRY_ATTR_START_DATE_I,
552                                          CSA_ENTRY_ATTR_TYPE_I,
553                                          CSA_ENTRY_ATTR_SUBTYPE_I,
554                                          CSA_ENTRY_ATTR_CLASSIFICATION_I,
555                                          CSA_ENTRY_ATTR_END_DATE_I,
556                                          CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
557                                          CSA_ENTRY_ATTR_SUMMARY_I,
558                                          CSA_ENTRY_ATTR_STATUS_I,
559                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
560                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
561                                          CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I,
562                                          CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I,
563                                          CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I,
564                                          NULL);
565                 else if (version == DATAVER4)
566                 a = allocate_appt_struct(appt_write,
567                                          version,
568                                          CSA_ENTRY_ATTR_START_DATE_I,
569                                          CSA_ENTRY_ATTR_TYPE_I,
570                                          CSA_ENTRY_ATTR_SUBTYPE_I,
571                                          CSA_ENTRY_ATTR_CLASSIFICATION_I,
572                                          CSA_ENTRY_ATTR_END_DATE_I,
573                                          CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
574                                          CSA_ENTRY_ATTR_SUMMARY_I,
575                                          CSA_ENTRY_ATTR_STATUS_I,
576                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
577                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
578                                          CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I,
579                                          CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I,
580                                          CSA_ENTRY_ATTR_RECURRENCE_RULE_I,
581                                          NULL);
582         }
583         else {
584
585                 if (version <= DATAVER2)
586                 a = allocate_appt_struct(appt_write,
587                                          version,
588                                          CSA_ENTRY_ATTR_START_DATE_I,
589                                          CSA_ENTRY_ATTR_TYPE_I,
590                                          CSA_ENTRY_ATTR_SUBTYPE_I,
591                                          CSA_ENTRY_ATTR_CLASSIFICATION_I,
592                                          CSA_ENTRY_ATTR_END_DATE_I,
593                                          CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
594                                          CSA_ENTRY_ATTR_SUMMARY_I,
595                                          CSA_ENTRY_ATTR_STATUS_I,
596                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
597                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
598                                          CSA_ENTRY_ATTR_AUDIO_REMINDER_I,
599                                          CSA_ENTRY_ATTR_FLASHING_REMINDER_I,
600                                          CSA_ENTRY_ATTR_MAIL_REMINDER_I,
601                                          CSA_ENTRY_ATTR_POPUP_REMINDER_I,
602                                          NULL);
603                 else if (version == DATAVER3)
604                 a = allocate_appt_struct(appt_write,
605                                          version,
606                                          CSA_ENTRY_ATTR_START_DATE_I,
607                                          CSA_ENTRY_ATTR_TYPE_I,
608                                          CSA_ENTRY_ATTR_SUBTYPE_I,
609                                          CSA_ENTRY_ATTR_CLASSIFICATION_I,
610                                          CSA_ENTRY_ATTR_END_DATE_I,
611                                          CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
612                                          CSA_ENTRY_ATTR_SUMMARY_I,
613                                          CSA_ENTRY_ATTR_STATUS_I,
614                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
615                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
616                                          CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I,
617                                          CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I,
618                                          CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I,
619                                          CSA_ENTRY_ATTR_AUDIO_REMINDER_I,
620                                          CSA_ENTRY_ATTR_FLASHING_REMINDER_I,
621                                          CSA_ENTRY_ATTR_MAIL_REMINDER_I,
622                                          CSA_ENTRY_ATTR_POPUP_REMINDER_I,
623                                          NULL);
624                 else if (version == DATAVER4)
625                 a = allocate_appt_struct(appt_write,
626                                          version,
627                                          CSA_ENTRY_ATTR_START_DATE_I,
628                                          CSA_ENTRY_ATTR_TYPE_I,
629                                          CSA_ENTRY_ATTR_SUBTYPE_I,
630                                          CSA_ENTRY_ATTR_CLASSIFICATION_I,
631                                          CSA_ENTRY_ATTR_END_DATE_I,
632                                          CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
633                                          CSA_ENTRY_ATTR_SUMMARY_I,
634                                          CSA_ENTRY_ATTR_STATUS_I,
635                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
636                                          CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
637                                          CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I,
638                                          CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I,
639                                          CSA_ENTRY_ATTR_AUDIO_REMINDER_I,
640                                          CSA_ENTRY_ATTR_FLASHING_REMINDER_I,
641                                          CSA_ENTRY_ATTR_MAIL_REMINDER_I,
642                                          CSA_ENTRY_ATTR_POPUP_REMINDER_I,
643                                          CSA_ENTRY_ATTR_RECURRENCE_RULE_I,
644                                          NULL);
645
646                 a->beep->value->item.reminder_value->lead_time = malloc(BUFSIZ);
647                 _csa_duration_to_iso8601(ge_reminder_val(p, CP_BEEPUNIT, CP_BEEPADV), 
648                                      a->beep->value->item.reminder_value->lead_time);
649                 a->beep->value->item.reminder_value->reminder_data.data = NULL;
650                 a->beep->value->item.reminder_value->reminder_data.size = 0;
651
652                 a->flash->value->item.reminder_value->lead_time = malloc(BUFSIZ);
653                 _csa_duration_to_iso8601(ge_reminder_val(p, CP_FLASHUNIT, CP_BEEPADV), 
654                                      a->flash->value->item.reminder_value->lead_time);
655                 a->flash->value->item.reminder_value->reminder_data.data = NULL;
656                 a->flash->value->item.reminder_value->reminder_data.size = 0;
657
658                 a->popup->value->item.reminder_value->lead_time = malloc(BUFSIZ);
659                 _csa_duration_to_iso8601(ge_reminder_val(p, CP_OPENUNIT, CP_BEEPADV), 
660                                      a->popup->value->item.reminder_value->lead_time);
661                 a->popup->value->item.reminder_value->reminder_data.data = NULL;
662                 a->popup->value->item.reminder_value->reminder_data.size = 0;
663
664                 a->mail->value->item.reminder_value->lead_time = malloc(BUFSIZ);
665                 _csa_duration_to_iso8601(ge_reminder_val(p, CP_MAILUNIT, CP_BEEPADV), 
666                                      a->mail->value->item.reminder_value->lead_time);
667                 a->mail->value->item.reminder_value->reminder_data.data =
668                         (CSA_uint8 *) cm_strdup(get_char_prop(p, CP_MAILTO));
669                 a->mail->value->item.reminder_value->reminder_data.size =
670                         strlen(get_char_prop(p, CP_MAILTO)) + 1;
671         }
672
673         all_ok = dssw_form_to_appt(&ge->dssw, a, ge->cal->view->current_calendar,
674                                    ge->cal->view->date);
675         if (all_ok)
676                 all_ok = rfp_form_to_appt(&ge->rfp, a,
677                                           ge->cal->view->current_calendar);
678
679         if (!all_ok) {
680                 free_appt_struct(&a);
681                 return NULL;
682         }
683
684         a->type->value->item.sint32_value = CSA_TYPE_EVENT;
685         a->subtype->value->item.string_value = strdup(CSA_SUBTYPE_APPOINTMENT);
686         a->state->value->item.sint32_value = CSA_X_DT_STATUS_ACTIVE;
687         a->private->value->item.sint32_value = CSA_CLASS_PUBLIC;
688
689         return(a);
690 }
691
692 /*
693 **  Action procedures
694 */
695 static void
696 ge_insert_proc(Widget w, XtPointer client_data, XtPointer data) {
697         int                     i, c_cnt, *c_list;
698         GEditor                 *ge = (GEditor *)client_data;
699         Props_pu                *p = (Props_pu *)ge->cal->properties_pu;
700         Calendar                *c = ge->cal;
701         CSA_entry_handle        new_a;
702         CSA_return_code         stat;
703         Access_data             *ad;
704         Dtcm_appointment        *appt;
705         XmListCallbackStruct    *lcb = (XmListCallbackStruct *)data;
706
707         _DtTurnOnHourGlass(ge->frame);
708         XmListGetSelectedPos(ge->access_list, &c_list, &c_cnt);
709         if (c_cnt <= 0) {
710                 char *title = XtNewString(catgets(c->DT_catd, 1, 305,
711                                 "Calendar : Error - Group Appointment Editor"));
712                 char *text = XtNewString(catgets(c->DT_catd, 1, 306,
713                                 "Select a calendar and INSERT again."));
714                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
715                 dialog_popup(ge->frame,
716                         DIALOG_TITLE, title,
717                         DIALOG_TEXT, text,
718                         BUTTON_IDENT, 1, ident1,
719                         DIALOG_IMAGE, p->xm_error_pixmap,
720                         NULL);
721                 XtFree(ident1);
722                 XtFree(text);
723                 XtFree(title);
724                 _DtTurnOffHourGlass(ge->frame);
725                 return;
726         } 
727
728
729         for(i = 0; i < c_cnt; i++) {
730                 ad = (Access_data *)
731                         CmDataListGetData(ge->access_data, c_list[i]);
732
733                 if(NULL == ad) {
734                         _DtTurnOffHourGlass(ge->frame);
735                         return;
736                 }
737
738                 /* it may seem a little odd to create this
739                    template appointment over and over again, but this 
740                    needs to be done because each connection may support 
741                    a different data model, and thus need the appointments 
742                    created differently. */
743
744                 if (same_user(ad->name, c->calname)) 
745                         appt = form_to_appt(ge, False, ad->version);
746                 else
747                         appt = form_to_appt(ge, True, ad->version);
748
749                 if (appt == NULL) {
750                         _DtTurnOffHourGlass(ge->frame);
751                         return;
752                 }
753
754                 if (!ad)
755                         stat = CSA_E_CALENDAR_NOT_EXIST;
756                 else {
757
758                         scrub_attr_list(appt);
759
760                         /* the gui does not support specifying the sequence
761                          * end date
762                          */
763                         if (appt->sequence_end_date &&
764                             appt->sequence_end_date->name) {
765                                 free(appt->sequence_end_date->name);
766                                 appt->sequence_end_date->name = NULL;
767                         }
768
769                         stat = csa_add_entry(ad->cal_handle,
770                                                appt->count, 
771                                                appt->attrs,
772                                                &new_a, NULL);
773                 }
774                 backend_err_msg(ge->frame, ad->name, stat,
775                                 p->xm_error_pixmap);
776                 if (stat != CSA_SUCCESS) {
777                         XtFree((XtPointer)c_list);
778                         free_appt_struct(&appt);
779                         add_all_gappt(ge);
780                         if (editor_showing((Editor *)c->editor))
781                                 add_all_appt((Editor*)c->editor);
782                         _DtTurnOffHourGlass(ge->frame);
783                         return;
784                 }
785                 csa_free((CSA_buffer)new_a);
786                 free_appt_struct(&appt);
787         }
788         XtFree((XtPointer)c_list);
789
790         add_all_gappt(ge);
791         if (editor_showing((Editor *)c->editor))
792                 add_all_appt((Editor*)c->editor);
793
794         reset_alarm(ge->cal);
795         invalidate_cache(ge->cal);
796         paint_canvas(ge->cal, NULL, RENDER_CLEAR_FIRST);
797         br_display(ge->cal);
798         _DtTurnOffHourGlass(ge->frame);
799 }
800
801 static void
802 ge_delete_proc(Widget w, XtPointer client_data, XtPointer data) {
803         int                     *item_list = NULL, item_cnt = 0, c_cnt, i;
804         GEditor                 *ge = (GEditor *)client_data;
805         Calendar                *c = ge->cal;
806         Props_pu                *p = (Props_pu *)ge->cal->properties_pu;
807         CSA_entry_handle        entry;
808         CSA_return_code         stat;
809         Access_data             *ad;
810         CSA_enum                scope;
811         Dtcm_appointment        *appt;
812         static int              answer;
813
814         _DtTurnOnHourGlass(ge->frame);
815         if (!XmListGetSelectedPos(ge->appt_list, &item_list, &item_cnt)) {
816                 char *title = XtNewString(catgets(c->DT_catd, 1, 305,
817                                 "Calendar : Error - Group Appointment Editor"));
818                 char *text = XtNewString(catgets(c->DT_catd, 1, 253,
819                                 "Select an appointment and DELETE again."));
820                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
821                 answer = dialog_popup(ge->frame,
822                         DIALOG_TITLE, title,
823                         DIALOG_TEXT, text,
824                         BUTTON_IDENT, 1, ident1,
825                         DIALOG_IMAGE, p->xm_error_pixmap,
826                         NULL);
827                 XtFree(ident1);
828                 XtFree(text);
829                 XtFree(title);
830                 _DtTurnOffHourGlass(ge->frame);
831                 return;
832         }
833
834         if (!(entry = geditor_nth_appt(ge, item_list[0], &ad))) {
835                 char *title = XtNewString(catgets(c->DT_catd, 1, 305,
836                                 "Calendar : Error - Group Appointment Editor"));
837                 char *text = XtNewString(catgets(c->DT_catd, 1, 256,
838                                 "Internal error selecting appointment.\nAppointment was not deleted."));
839                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 95,
840                                 "Continue"));
841                 answer = dialog_popup(ge->frame,
842                         DIALOG_TITLE, title,
843                         DIALOG_TEXT, text,
844                         BUTTON_IDENT, 1, ident1,
845                         BUTTON_HELP, RESELECT_ERROR_HELP,
846                         DIALOG_IMAGE, p->xm_error_pixmap,
847                         NULL);
848                 XtFree(ident1);
849                 XtFree(text);
850                 XtFree(title);
851                 XtFree((XtPointer)item_list);
852                 _DtTurnOffHourGlass(ge->frame);
853                 return;
854         }
855         XtFree((XtPointer)item_list);
856
857         XtVaGetValues(ge->access_list, XmNselectedItemCount, &c_cnt,
858                 NULL);
859         if (c_cnt <= 0) {
860                 char *title = XtNewString(catgets(c->DT_catd, 1, 305,
861                                 "Calendar : Error - Group Appointment Editor"));
862                 char *text = XtNewString(catgets(c->DT_catd, 1, 315,
863                                 "Select a calendar and DELETE again."));
864                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
865                 answer = dialog_popup(ge->frame,
866                         DIALOG_TITLE, title,
867                         DIALOG_TEXT, text,
868                         BUTTON_IDENT, 1, ident1,
869                         DIALOG_IMAGE, p->xm_error_pixmap,
870                         NULL);
871                 XtFree(ident1);
872                 XtFree(text);
873                 XtFree(title);
874                 _DtTurnOffHourGlass(ge->frame);
875                 return;
876         } 
877
878         answer = 0;
879         appt = allocate_appt_struct(appt_read, 
880                                         ad->version,
881                                         CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I, 
882                                         NULL);
883         stat = query_appt_struct(c->cal_handle, entry, appt);
884         backend_err_msg(ge->frame, c->view->current_calendar, stat,
885                         p->xm_error_pixmap);
886         if (stat != CSA_SUCCESS) {
887                 free_appt_struct(&appt);
888                 _DtTurnOffHourGlass(ge->frame);
889                 return;
890         }
891
892         if (appt->repeat_type->value) {
893                 if (appt->repeat_type->value->item.sint32_value !=
894                     CSA_X_DT_REPEAT_ONETIME) {
895                         char *title = XtNewString(catgets(c->DT_catd, 1, 314,
896                                         "Calendar : Group Appointment Editor - Delete"));
897                         char *text = XtNewString(catgets(c->DT_catd, 1, 274,
898                                         "This appointment is part of a repeating series.\nDo you want to delete ...?"));
899                         char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
900                         char *ident2 = XtNewString(catgets(c->DT_catd, 1, 270,
901                                         "This One Only"));
902                         char *ident3 = XtNewString(catgets(c->DT_catd, 1, 271, "Forward"));
903                         char *ident4 = XtNewString(catgets(c->DT_catd, 1, 272, "All"));
904                         answer = dialog_popup(ge->frame,
905                                 DIALOG_TITLE, title,
906                                 DIALOG_TEXT, text,
907                                 BUTTON_IDENT, 1, ident1,
908                                 BUTTON_IDENT, 2, ident2,
909                                 BUTTON_IDENT, 3, ident3,
910                                 BUTTON_IDENT, 4, ident4,
911                                 DIALOG_IMAGE, p->xm_question_pixmap,
912                                 NULL);
913                         XtFree(ident4);
914                         XtFree(ident3);
915                         XtFree(ident2);
916                         XtFree(ident1);
917                         XtFree(text);
918                         XtFree(title);
919                 }
920         }
921         else if (appt->recurrence_rule->value) {
922                 char *title = XtNewString(catgets(c->DT_catd, 1, 314,
923                                         "Calendar : Group Appointment Editor - Delete"));
924                 char *text = XtNewString(catgets(c->DT_catd, 1, 711,
925                                         "This appointment repeats in an unknown fashion.  All occurrences will be deleted\nDo you still wish to delete it?"));
926                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
927                 char *ident4 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
928                 answer = dialog_popup(c->frame,
929                                 DIALOG_TITLE, title,
930                                 DIALOG_TEXT, text,
931                                 BUTTON_IDENT, 1, ident1,
932                                 BUTTON_IDENT, 4, ident4,
933                                 DIALOG_IMAGE, p->xm_question_pixmap,
934                                 NULL);
935                 XtFree(ident4);
936                 XtFree(ident1);
937                 XtFree(text);
938                 XtFree(title);
939         }
940         free_appt_struct(&appt);
941
942         switch(answer) {
943         case 1:
944                 _DtTurnOffHourGlass(ge->frame);
945                 return;
946         case 2:
947                 scope = CSA_SCOPE_ONE;
948                 break;
949         case 3:
950                 scope = CSA_SCOPE_FORWARD;
951                 break;
952         case 4:
953         default:
954                 scope = CSA_SCOPE_ALL;
955                 break;
956         }
957
958         stat = csa_delete_entry(c->cal_handle, entry, scope, NULL);
959         backend_err_msg(ge->frame, c->view->current_calendar, stat,
960                         p->xm_error_pixmap);
961
962         add_all_gappt(ge);
963         reset_alarm(ge->cal);
964         invalidate_cache(ge->cal);
965         paint_canvas(ge->cal, NULL, RENDER_CLEAR_FIRST);
966         br_display(ge->cal);
967         _DtTurnOffHourGlass(ge->frame);
968 }
969
970 static void
971 ge_change_proc(Widget w, XtPointer client_data, XtPointer data) {
972         int                     *item_list = NULL, item_cnt = 0, c_cnt, i;
973         GEditor                 *ge = (GEditor *)client_data;
974         Calendar                *c = ge->cal;
975         Props_pu                *p = (Props_pu *)c->properties_pu;
976         CSA_entry_handle        old_a, new_entry;
977         CSA_return_code         stat;
978         Access_data             *ad;
979         CSA_enum                scope;
980         Dtcm_appointment        *new_a = NULL, *appt;
981         static int              answer;
982
983         _DtTurnOnHourGlass(ge->frame);
984         if (!XmListGetSelectedPos(ge->appt_list, &item_list, &item_cnt)) {
985                 char *title = XtNewString(catgets(c->DT_catd, 1, 305,
986                                 "Calendar : Error - Group Appointment Editor"));
987                 char *text = XtNewString(catgets(c->DT_catd, 1, 259,
988                                 "Select an appointment and CHANGE again."));
989                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
990                 answer = dialog_popup(ge->frame,
991                         DIALOG_TITLE, title,
992                         DIALOG_TEXT, text,
993                         BUTTON_IDENT, 1, ident1,
994                         DIALOG_IMAGE, p->xm_error_pixmap,
995                         NULL);
996                 XtFree(ident1);
997                 XtFree(text);
998                 XtFree(title);
999                 _DtTurnOffHourGlass(ge->frame);
1000                 return;
1001         } 
1002
1003         if (!(old_a = geditor_nth_appt(ge, item_list[0], &ad))) {
1004                 char *title = XtNewString(catgets(c->DT_catd, 1, 305,
1005                                 "Calendar : Error - Group Appointment Editor"));
1006                 char *text = XtNewString(catgets(c->DT_catd, 1, 1007,
1007                                 "Internal error selecting appointment.\nAppointment was not changed."));
1008                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
1009                 answer = dialog_popup(ge->frame,
1010                         DIALOG_TITLE, title,
1011                         DIALOG_TEXT, text,
1012                         BUTTON_IDENT, 1, ident1,
1013                         DIALOG_IMAGE, p->xm_error_pixmap,
1014                         NULL);
1015                 XtFree(ident1);
1016                 XtFree(text);
1017                 XtFree(title);
1018                 XtFree((XtPointer)item_list);
1019                 _DtTurnOffHourGlass(ge->frame);
1020                 return;
1021         }
1022         XtFree((XtPointer)item_list);
1023
1024         XtVaGetValues(ge->access_list, XmNselectedItemCount, &c_cnt,
1025                 NULL);
1026         if (c_cnt <= 0) {
1027                 char *title = XtNewString(catgets(c->DT_catd, 1, 329,
1028                                 "Calendar : Group Appointment Editor - Change"));
1029                 char *text = XtNewString(catgets(c->DT_catd, 1, 330,
1030                                 "Select a calendar and CHANGE again."));
1031                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
1032                 answer = dialog_popup(ge->frame,
1033                         DIALOG_TITLE, title,
1034                         DIALOG_TEXT, text,
1035                         BUTTON_IDENT, 1, ident1,
1036                         DIALOG_IMAGE, p->xm_error_pixmap,
1037                         NULL);
1038                 _DtTurnOffHourGlass(ge->frame);
1039                 XtFree(ident1);
1040                 XtFree(text);
1041                 XtFree(title);
1042                 return;
1043         } 
1044
1045         answer = 0;
1046         appt = allocate_appt_struct(appt_read,
1047                                     ad->version,
1048                                     CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
1049                                     CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
1050                                     CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I,
1051                                     CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I,
1052                                     CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I,
1053                                     CSA_ENTRY_ATTR_START_DATE_I,
1054                                     CSA_ENTRY_ATTR_RECURRENCE_RULE_I,
1055                                     NULL);
1056         stat = query_appt_struct(c->cal_handle, old_a, appt);
1057         backend_err_msg(ge->frame, ad->name, stat, p->xm_error_pixmap);
1058         if (stat != CSA_SUCCESS) {
1059                 free_appt_struct(&appt);
1060                 _DtTurnOffHourGlass(ge->frame);
1061                 return;
1062         }
1063
1064         if ((new_a = form_to_appt(ge, (same_user(ad->name, c->calname)) ? False : True, ad->version)) == NULL) {
1065                 free_appt_struct(&appt);
1066                 _DtTurnOffHourGlass(ge->frame);
1067                 return;
1068         }
1069
1070         if ((appt->repeat_type->value->item.sint32_value == CSA_X_DT_REPEAT_OTHER) ||
1071             (appt->repeat_type->value->item.sint32_value == CSA_X_DT_REPEAT_OTHER_WEEKLY) ||
1072             (appt->repeat_type->value->item.sint32_value == CSA_X_DT_REPEAT_OTHER_MONTHLY) ||
1073             (appt->repeat_type->value->item.sint32_value == CSA_X_DT_REPEAT_OTHER_YEARLY)) {
1074                 char *title = XtNewString(catgets(c->DT_catd, 1, 329,
1075                                         "Calendar : Group Appointment Editor - Change"));
1076                 char *text = XtNewString(catgets(c->DT_catd, 1, 708,
1077                                         "This appointment repeats in an unknown fashion.  All occurrences will be changed\nDo you still wish to change it?"));
1078                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
1079                 char *ident4 = XtNewString(catgets(c->DT_catd, 1, 95, "Continue"));
1080                 answer = dialog_popup(c->frame,
1081                                 DIALOG_TITLE, title,
1082                                 DIALOG_TEXT, text,
1083                                 BUTTON_IDENT, 1, ident1,
1084                                 BUTTON_IDENT, 4, ident4,
1085                                 DIALOG_IMAGE, p->xm_question_pixmap,
1086                                 NULL);
1087                 XtFree(ident4);
1088                 XtFree(ident1);
1089                 XtFree(text);
1090                 XtFree(title);
1091         }
1092
1093         else if (appt->repeat_type->value->item.sint32_value != 
1094                 CSA_X_DT_REPEAT_ONETIME) {
1095                 char *title = XtNewString(catgets(c->DT_catd, 1, 329,
1096                                 "Calendar : Group Appointment Editor - Change"));
1097                 char *text = XtNewString(catgets(c->DT_catd, 1, 268,
1098                                 "This appointment is part of a repeating series.\nDo you want to change ...?"));
1099                 char *ident1 = XtNewString(catgets(c->DT_catd, 1, 923, "Cancel"));
1100                 char *ident2 = XtNewString(catgets(c->DT_catd, 1, 270,
1101                                 "This One Only"));
1102                 char *ident3 = XtNewString(catgets(c->DT_catd, 1, 271, "Forward"));
1103                 char *ident4 = XtNewString(catgets(c->DT_catd, 1, 272, "All"));
1104                 answer = dialog_popup(ge->frame,
1105                         DIALOG_TITLE, title,
1106                         DIALOG_TEXT, text,
1107                         BUTTON_IDENT, 1, ident1,
1108                         BUTTON_IDENT, 2, ident2,
1109                         BUTTON_IDENT, 3, ident3,
1110                         (compare_repeat_info(appt, &(ge->rfp), ad->cal_handle, ad->version) ?
1111                                 BUTTON_IDENT : BUTTON_INSENSITIVE),
1112                                           4, ident4,
1113                         DIALOG_IMAGE, p->xm_question_pixmap,
1114                         NULL);
1115                 XtFree(ident4);
1116                 XtFree(ident3);
1117                 XtFree(ident2);
1118                 XtFree(ident1);
1119                 XtFree(text);
1120                 XtFree(title);
1121                 if (answer == 2) {
1122                         change_rule_for_this_one_only(c, new_a, appt);
1123                 }
1124         }
1125
1126         switch(answer) {
1127         case 1:
1128                 _DtTurnOffHourGlass(ge->frame);
1129                 free_appt_struct(&appt);
1130                 free_appt_struct(&new_a);
1131                 return;
1132         case 2:
1133                 scope = CSA_SCOPE_ONE;
1134                 break;
1135         case 3:
1136                 scope = CSA_SCOPE_FORWARD;
1137                 break;
1138         case 4:
1139         default:
1140                 scope = CSA_SCOPE_ALL;
1141                 break;
1142         }
1143
1144         /* We are not allowed to change the type of the entry, so we will
1145            remove that particular entry from the list for writing. */
1146  
1147         if (new_a->type) {
1148                 if (new_a->type->name){
1149                         free(new_a->type->name);
1150                         new_a->type->name = NULL;
1151                 }
1152         }
1153
1154         /* if the repeat type/times is changed, reset the sequence end date */
1155         if (ad->version == DATAVER3 &&
1156             appt->repeat_type->value->item.sint32_value !=
1157             CSA_X_DT_REPEAT_ONETIME &&
1158             (appt->repeat_type->value->item.sint32_value !=
1159              new_a->repeat_type->value->item.sint32_value ||
1160              appt->repeat_times->value->item.uint32_value !=
1161              new_a->repeat_times->value->item.uint32_value))
1162         {
1163                 if (new_a->sequence_end_date && new_a->sequence_end_date->value)
1164                 {
1165                         if (new_a->sequence_end_date->value->item.date_time_value)
1166                                 free(new_a->sequence_end_date->value->\
1167                                         item.date_time_value);
1168                         free(new_a->sequence_end_date->value);
1169                         new_a->sequence_end_date->value = NULL;
1170                 }
1171         } else {
1172                 if (new_a->sequence_end_date && new_a->sequence_end_date->name)
1173                 {
1174                         free (new_a->sequence_end_date->name);
1175                         new_a->sequence_end_date->name = NULL;
1176                 }
1177         }
1178
1179         stat = csa_update_entry_attributes(ad->cal_handle, old_a, scope, CSA_FALSE, new_a->count, new_a->attrs, &new_entry, NULL);
1180         backend_err_msg(ge->frame, ad->name, stat, p->xm_error_pixmap);
1181
1182         if (stat == CSA_SUCCESS)
1183                 csa_free((CSA_buffer)new_entry);
1184
1185         free_appt_struct(&appt);
1186         free_appt_struct(&new_a);
1187
1188         add_all_gappt(ge);
1189         reset_alarm(c);
1190         invalidate_cache(ge->cal);
1191         paint_canvas(c, NULL, RENDER_CLEAR_FIRST);
1192         br_display(c);
1193         _DtTurnOffHourGlass(ge->frame);
1194 }
1195
1196 static void
1197 ge_clear_proc(Widget w, XtPointer client_data, XtPointer data) {
1198         GEditor *ge = (GEditor *)client_data;
1199
1200         set_geditor_defaults(ge, 0, 0);
1201         XmListDeselectAllItems(ge->access_list);
1202         set_message(ge->message_text, " ");
1203         add_all_gappt(ge);
1204 }
1205
1206 static void
1207 ge_close_proc(Widget w, XtPointer client_data, XtPointer data) {
1208         GEditor *ge = (GEditor *)client_data;
1209
1210         geditor_clean_up(ge);
1211         XtPopdown(ge->frame);
1212         ge->geditor_is_up = False;
1213 }
1214
1215 static void
1216 ge_quit_handler(Widget w, XtPointer cdata, XtPointer data) {
1217         ge_close_proc(w, cdata, data);
1218 }
1219
1220 static void
1221 FormGroupApptDragMotionHandler(Widget dragInitiator, XtPointer clientData,
1222                                XEvent *event) {
1223         int             diffX, diffY;
1224         Calendar        *c = (Calendar *) clientData;
1225         GEditor         *ge = (GEditor *) c->geditor;
1226  
1227         if (!ge->doing_drag) {
1228                 /*
1229                  * If the drag is just starting, set initial button down coords
1230                  */
1231                 if (ge->initialX == -1 && ge->initialY == -1) {
1232                         ge->initialX = event->xmotion.x;
1233                         ge->initialY = event->xmotion.y;
1234                 }
1235                 /*
1236                  * Find out how far pointer has moved since button press
1237                  */
1238                 diffX = ge->initialX - event->xmotion.x;
1239                 diffY = ge->initialY - event->xmotion.y;
1240  
1241                 if ((ABS(diffX) >= DRAG_THRESHOLD) ||
1242                     (ABS(diffY) >= DRAG_THRESHOLD)) {
1243                         ge->doing_drag = True;
1244                         ApptDragStart(dragInitiator, event, c, GroupEditorIcon);
1245                         ge->initialX = -1;
1246                         ge->initialY = -1;
1247                 }
1248         }
1249 }
1250
1251 static void
1252 ge_make_editor(Calendar *c) {
1253         int             cnt;
1254         Arg             args[15];
1255         char            *buf;
1256         GEditor         *ge = (GEditor *)c->geditor;
1257         Props_pu        *p = (Props_pu *)c->properties_pu;
1258         XmString        xmstr;
1259         Dimension       label_height;
1260         XtTranslations  new_translations;
1261         Boolean         btn1_transfer;
1262         Widget          second_list_label;
1263         Widget          second_access_label;
1264         XFontSetExtents listfontextents;
1265         static char     translations[] = "\
1266                 ~c ~s ~m ~a <Btn1Down>:\
1267                  dtcm-process-press(ListBeginSelect,TranslationDragStart)\n\
1268                 c ~s ~m ~a <Btn1Down>:\
1269                  dtcm-process-press(ListBeginToggle,TranslationDragStart)";
1270         static char     btn2_translations[] = "\
1271                 ~c ~s ~m ~a <Btn2Down>:\
1272                  dtcm-process-press(ListBeginSelect,TranslationDragStart)\n\
1273                 c ~s ~m ~a <Btn2Down>:\
1274                  dtcm-process-press(ListBeginToggle,TranslationDragStart)\n\
1275                 <Btn2Motion>:ListButtonMotion()\n\
1276                 ~c ~s ~m ~a <Btn2Up>:ListEndSelect()\n\
1277                 c ~s ~m ~a <Btn2Up>:ListEndToggle()";
1278
1279         new_translations = XtParseTranslationTable(translations);
1280
1281         ge->cal = c;
1282
1283         CalFontExtents(c->fonts->userfont, &listfontextents);
1284
1285         /*
1286         **  Dialog shell
1287         */
1288         cnt = 0;
1289         XtSetArg(args[cnt], XmNdeleteResponse, XmDO_NOTHING); ++cnt;
1290         XtSetArg(args[cnt], XmNallowShellResize, True); ++cnt;
1291         XtSetArg(args[cnt], XmNmappedWhenManaged, False); ++cnt;
1292         ge->frame = XmCreateDialogShell(ge->cal->frame, "frame", args, cnt);
1293
1294         /*
1295         **  Base form
1296         */
1297         cnt = 0;
1298         XtSetArg(args[cnt], XmNautoUnmanage, False); ++cnt;
1299         XtSetArg(args[cnt], XmNfractionBase, 100); ++cnt;
1300         ge->base_form_mgr = XmCreateForm(ge->frame, "base_form_mgr", args, cnt);
1301
1302         /*
1303         **  Set title and quit handler
1304         */
1305         set_geditor_title(ge, c->view->current_calendar);
1306         setup_quit_handler(ge->frame, ge_quit_handler, (caddr_t)ge);
1307
1308         /*
1309         **  Message widget
1310         */
1311         cnt = 0;
1312         XtSetArg(args[cnt], XmNalignment, XmALIGNMENT_BEGINNING); ++cnt;
1313         XtSetArg(args[cnt], XmNbottomAttachment, XmATTACH_FORM); ++cnt;
1314         XtSetArg(args[cnt], XmNbottomOffset, 2); ++cnt;
1315         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_FORM); ++cnt;
1316         XtSetArg(args[cnt], XmNleftOffset, 2); ++cnt;
1317         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_FORM); ++cnt;
1318         XtSetArg(args[cnt], XmNrightOffset, 2); ++cnt;
1319         ge->message_text = XmCreateLabelGadget(ge->base_form_mgr, "message",
1320                                                args, cnt);
1321         /*
1322         **  Create insert, delete, change, and clear buttons in rc manager
1323         */
1324
1325         ge->button_rc_mgr = XtVaCreateWidget("button_rc_mgr",
1326                 xmFormWidgetClass, ge->base_form_mgr,
1327                 XmNautoUnmanage, False,
1328                 XmNleftAttachment, XmATTACH_FORM,
1329                 XmNrightAttachment, XmATTACH_FORM,
1330                 XmNbottomAttachment, XmATTACH_WIDGET,
1331                 XmNbottomWidget, ge->message_text,
1332                 XmNtopOffset, 10,
1333                 XmNbottomOffset, 5,
1334                 XmNhorizontalSpacing, 10,
1335                 XmNfractionBase, 8,
1336                 NULL);
1337
1338
1339         cnt = 0;
1340         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 342, "Insert"));
1341         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1342         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_POSITION); ++cnt;
1343         XtSetArg(args[cnt], XmNleftPosition, 1); ++cnt;
1344         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_POSITION); ++cnt;
1345         XtSetArg(args[cnt], XmNrightPosition, 2); ++cnt;
1346         ge->insert_button = XmCreatePushButton(ge->button_rc_mgr, "insert",
1347                                                args, cnt);
1348         XmStringFree(xmstr);
1349         XtAddCallback(ge->insert_button, XmNactivateCallback, ge_insert_proc,
1350                       ge);
1351
1352         cnt = 0;
1353         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 343, "Change"));
1354         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1355         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_POSITION); ++cnt;
1356         XtSetArg(args[cnt], XmNleftPosition, 2); ++cnt;
1357         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_POSITION); ++cnt;
1358         XtSetArg(args[cnt], XmNrightPosition, 3); ++cnt;
1359         ge->change_button = XmCreatePushButton(ge->button_rc_mgr, "change",
1360                                                args, cnt);
1361         XmStringFree(xmstr);
1362         XtAddCallback(ge->change_button, XmNactivateCallback, ge_change_proc,
1363                       ge);
1364
1365         cnt = 0;
1366         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 419, "Delete"));
1367         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1368         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_POSITION); ++cnt;
1369         XtSetArg(args[cnt], XmNleftPosition, 3); ++cnt;
1370         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_POSITION); ++cnt;
1371         XtSetArg(args[cnt], XmNrightPosition, 4); ++cnt;
1372         ge->delete_button = XmCreatePushButton(ge->button_rc_mgr, "delete",
1373                                                args, cnt);
1374         XmStringFree(xmstr);
1375         XtAddCallback(ge->delete_button, XmNactivateCallback, ge_delete_proc,
1376                       ge);
1377
1378         cnt = 0;
1379         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 803, "Clear"));
1380         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1381         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_POSITION); ++cnt;
1382         XtSetArg(args[cnt], XmNleftPosition, 4); ++cnt;
1383         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_POSITION); ++cnt;
1384         XtSetArg(args[cnt], XmNrightPosition, 5); ++cnt;
1385         ge->clear_button = XmCreatePushButton(ge->button_rc_mgr, "clear",
1386                                                args, cnt);
1387         XmStringFree(xmstr);
1388         XtAddCallback(ge->clear_button, XmNactivateCallback, ge_clear_proc,
1389                       ge);
1390
1391         cnt = 0;
1392         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 923, "Cancel"));
1393         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1394         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_POSITION); ++cnt;
1395         XtSetArg(args[cnt], XmNleftPosition, 5); ++cnt;
1396         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_POSITION); ++cnt;
1397         XtSetArg(args[cnt], XmNrightPosition, 6); ++cnt;
1398         ge->close_button = XmCreatePushButton(ge->button_rc_mgr, "close",
1399                                                args, cnt);
1400         XmStringFree(xmstr);
1401         XtAddCallback(ge->close_button, XmNactivateCallback, ge_close_proc,
1402                       ge);
1403
1404         cnt = 0;
1405         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 77, "Help"));
1406         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1407         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_POSITION); ++cnt;
1408         XtSetArg(args[cnt], XmNleftPosition, 6); ++cnt;
1409         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_POSITION); ++cnt;
1410         XtSetArg(args[cnt], XmNrightPosition, 7); ++cnt;
1411         ge->help_button = XmCreatePushButton(ge->button_rc_mgr, "help",
1412                                                args, cnt);
1413         XmStringFree(xmstr);
1414         XtAddCallback(ge->help_button, XmNactivateCallback,
1415                       (XtCallbackProc)help_cb, GROUP_APPT_EDITOR_HELP_BUTTON);
1416         XtAddCallback(ge->base_form_mgr, XmNhelpCallback,
1417                       (XtCallbackProc)help_cb, GROUP_APPT_EDITOR_HELP_BUTTON);
1418
1419         ManageChildren(ge->button_rc_mgr);
1420
1421         /*
1422         **  The separators
1423         */
1424         cnt = 0;
1425         XtSetArg(args[cnt], XmNbottomAttachment, XmATTACH_WIDGET); ++cnt;
1426         XtSetArg(args[cnt], XmNbottomWidget, ge->button_rc_mgr); ++cnt;
1427         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_FORM); ++cnt;
1428         XtSetArg(args[cnt], XmNleftOffset, 5); ++cnt;
1429         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_FORM); ++cnt;
1430         XtSetArg(args[cnt], XmNrightOffset, 5); ++cnt;
1431         ge->separator2 = XmCreateSeparatorGadget(ge->base_form_mgr,
1432                                                  "separator2", args, cnt);
1433
1434         cnt = 0;
1435         XtSetArg(args[cnt], XmNbottomAttachment, XmATTACH_WIDGET); ++cnt;
1436         XtSetArg(args[cnt], XmNbottomWidget, ge->separator2); ++cnt;
1437         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_FORM); ++cnt;
1438         XtSetArg(args[cnt], XmNleftOffset, 5); ++cnt;
1439         XtSetArg(args[cnt], XmNrightAttachment, XmATTACH_FORM); ++cnt;
1440         XtSetArg(args[cnt], XmNrightOffset, 5); ++cnt;
1441         ge->separator1 = XmCreateSeparatorGadget(ge->base_form_mgr,
1442                                                  "separator1", args, cnt);
1443
1444         /*
1445         **  The more button
1446         */
1447         cnt = 0;
1448         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 626, "More"));
1449         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1450         XtSetArg(args[cnt], XmNbottomAttachment, XmATTACH_WIDGET); ++cnt;
1451         XtSetArg(args[cnt], XmNbottomWidget, ge->separator1); ++cnt;
1452         XtSetArg(args[cnt], XmNbottomOffset, 3); ++cnt;
1453         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_FORM); ++cnt;
1454         XtSetArg(args[cnt], XmNleftOffset, 5); ++cnt;
1455         ge->expand_ui_button = XmCreatePushButton(ge->base_form_mgr,
1456                 "expand_ui_button", args, cnt);
1457         XmStringFree(xmstr);
1458         XtAddCallback(ge->expand_ui_button, XmNactivateCallback,
1459                 ge_expand_ui_proc, ge);
1460
1461         /*
1462         **  The appt list label
1463         */
1464         cnt = 0;
1465         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 971, "Time Calendar"));
1466         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1467         XtSetArg(args[cnt], XmNtopAttachment, XmATTACH_FORM); ++cnt;
1468         XtSetArg(args[cnt], XmNtopOffset, 5); ++cnt;
1469         ge->appt_list_label = XmCreateLabelGadget(ge->base_form_mgr,
1470                                                   "appt_list_label", args, cnt);
1471         XmStringFree(xmstr);
1472
1473         /*
1474         **  The appt list label
1475         */
1476         cnt = 0;
1477         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 972, "What"));
1478         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1479         XtSetArg(args[cnt], XmNtopAttachment, XmATTACH_FORM); ++cnt;
1480         XtSetArg(args[cnt], XmNtopOffset, 5); ++cnt;
1481         second_list_label = XmCreateLabelGadget(ge->base_form_mgr,
1482                                                   "second_list_label", args, cnt);
1483         XmStringFree(xmstr);
1484
1485         XtVaGetValues(ge->appt_list_label, XmNheight, &label_height, NULL);
1486
1487         /*
1488         **  The dssw widget
1489         */
1490         ge->dsswFlags = 0;
1491         build_dssw(&ge->dssw, c, ge->base_form_mgr, True, True);
1492         XtVaSetValues(ge->dssw.dssw_form_mgr,
1493                 XmNtopAttachment, XmATTACH_FORM,
1494                 XmNtopOffset, label_height + 5,
1495                 XmNbottomAttachment, XmATTACH_WIDGET,
1496                 XmNbottomWidget, ge->expand_ui_button,
1497                 XmNleftAttachment, XmATTACH_FORM,
1498                 XmNleftOffset, 5,
1499                 NULL);
1500
1501         /*
1502          * Add a drag source icon inside the dssw, lower right
1503          */
1504         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 627, "Drag Appt"));
1505         ge->drag_source = XtVaCreateWidget("drag_source",
1506                 dtIconGadgetClass, ge->dssw.dssw_form_mgr,
1507                 XmNpixmapPosition, XmPIXMAP_TOP,
1508                 XmNstringPosition, XmSTRING_BOTTOM,
1509                 XmNalignment, XmALIGNMENT_CENTER,
1510                 XmNstring, xmstr,
1511                 XmNbottomAttachment, XmATTACH_FORM,
1512                 XmNrightAttachment, XmATTACH_FORM,
1513                 XmNtraversalOn, False,
1514                 NULL);
1515         XmStringFree(xmstr);
1516
1517         XtAddEventHandler(XtParent(ge->drag_source), Button1MotionMask, False,
1518                 (XtEventHandler)FormGroupApptDragMotionHandler, (XtPointer) c);
1519
1520         XtVaGetValues((Widget)XmGetXmDisplay(XtDisplay(c->frame)), 
1521                         "enableBtn1Transfer",   &btn1_transfer, 
1522                         NULL); 
1523
1524         /* btn1_transfer is a tri-state variable - see 1195846 */ 
1525         if ((Boolean)btn1_transfer != True)
1526                 XtAddEventHandler(XtParent(ge->drag_source), 
1527                                 Button2MotionMask, False,
1528                                 (XtEventHandler)FormGroupApptDragMotionHandler,
1529                                 (XtPointer) c);
1530
1531         if (p->drag_icon_xbm)
1532                 XtVaSetValues(ge->drag_source,
1533                                 XmNpixmap, p->drag_icon_xbm,
1534                                 NULL);
1535
1536         XtVaSetValues(ge->dssw.what_scrollwindow, 
1537                         XmNrightAttachment,     XmATTACH_WIDGET,
1538                         XmNrightWidget,         ge->drag_source, 
1539                         NULL);
1540         
1541         ManageChildren(ge->dssw.dssw_form_mgr);
1542
1543         /*
1544         **  The access list
1545         */
1546
1547         cnt = 0;
1548         XtSetArg(args[cnt], XmNheight, 4 * listfontextents.max_logical_extent.height); ++cnt;
1549         XtSetArg(args[cnt], XmNlistSizePolicy, XmCONSTANT); ++cnt;
1550         XtSetArg(args[cnt], XmNselectionPolicy, XmMULTIPLE_SELECT); ++cnt;
1551         XtSetArg(args[cnt], XmNwidth, 23 * listfontextents.max_logical_extent.width); ++cnt;
1552         XtSetArg(args[cnt], XmNdoubleClickInterval, 5); ++cnt; 
1553         ge->access_list = XmCreateScrolledList(ge->base_form_mgr,
1554                                                "access_list", args, cnt);
1555         XtAddCallback(ge->access_list, XmNmultipleSelectionCallback,
1556                       ge_access_select_proc, (XtPointer)ge); 
1557
1558         ge->access_list_sw = XtParent(ge->access_list);
1559
1560         XtVaSetValues(ge->access_list_sw,
1561                 XmNleftAttachment, XmATTACH_WIDGET,
1562                 XmNleftWidget, ge->dssw.dssw_form_mgr,
1563                 XmNleftOffset, 5,
1564                 XmNrightAttachment, XmATTACH_FORM,
1565                 XmNrightOffset, 5,
1566                 XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET,
1567                 XmNbottomWidget, ge->dssw.dssw_form_mgr,
1568                 NULL);
1569         XtManageChild(ge->access_list);
1570         /*
1571         **  The access list label
1572         */
1573         cnt = 0;
1574         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 340, "Calendar"));
1575         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1576         XtSetArg(args[cnt], XmNbottomAttachment, XmATTACH_WIDGET); ++cnt;
1577         XtSetArg(args[cnt], XmNbottomWidget, ge->access_list_sw); ++cnt;
1578         XtSetArg(args[cnt], XmNbottomOffset, 5); ++cnt;
1579         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ++cnt;
1580         XtSetArg(args[cnt], XmNleftWidget, ge->access_list_sw); ++cnt;
1581         ge->access_list_label = XmCreateLabelGadget(ge->base_form_mgr,
1582                 "access_list_label", args, cnt);
1583         XmStringFree(xmstr);
1584
1585         xmstr = XmStringCreateLocalized(catgets(c->DT_catd, 1, 341, "Access"));
1586         XtSetArg(args[cnt], XmNlabelString, xmstr); ++cnt;
1587         XtSetArg(args[cnt], XmNbottomAttachment, XmATTACH_WIDGET); ++cnt;
1588         XtSetArg(args[cnt], XmNbottomWidget, ge->access_list_sw); ++cnt;
1589         XtSetArg(args[cnt], XmNbottomOffset, 5); ++cnt;
1590         XtSetArg(args[cnt], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); ++cnt;
1591         XtSetArg(args[cnt], XmNleftWidget, ge->access_list_sw); ++cnt;
1592         XtSetArg(args[cnt], XmNleftOffset, 23 * listfontextents.max_logical_extent.width); ++cnt;
1593         second_access_label = XmCreateLabelGadget(ge->base_form_mgr,
1594                 "second_access_label", args, cnt);
1595         XmStringFree(xmstr);
1596
1597         /*
1598         **  The appt list
1599         */
1600         cnt = 0;
1601         XtSetArg(args[cnt], XmNlistSizePolicy, XmCONSTANT); ++cnt;
1602         XtSetArg(args[cnt], XmNscrollBarDisplayPolicy, XmSTATIC); ++cnt;
1603         XtSetArg(args[cnt], XmNwidth, 200); ++cnt;
1604         XtSetArg(args[cnt], XmNdoubleClickInterval, 5); ++cnt; 
1605         ge->appt_list = XmCreateScrolledList(ge->base_form_mgr,
1606                                              "ge_appt_list", args, cnt);
1607
1608         XtOverrideTranslations(ge->appt_list, new_translations);
1609         /* Make btn 2 do dnd of appts */
1610         /* btn1_transfer is a tri-state variable - see 1195846 */ 
1611         if ((Boolean)btn1_transfer != True) {   
1612                 new_translations = XtParseTranslationTable(btn2_translations);
1613                 XtOverrideTranslations(ge->appt_list, new_translations);
1614         }
1615
1616         XtAddCallback(ge->appt_list, XmNbrowseSelectionCallback,
1617                       ge_list_select_proc, (XtPointer)ge); 
1618
1619         ge->appt_list_sw = XtParent(ge->appt_list);
1620
1621         XtVaSetValues(ge->appt_list_sw,
1622                 XmNtopAttachment, XmATTACH_FORM,
1623                 XmNtopOffset, label_height + 11,
1624                 XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
1625                 XmNleftWidget, ge->access_list_sw,
1626                 XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
1627                 XmNrightWidget, ge->access_list_sw,
1628                 XmNbottomAttachment, XmATTACH_WIDGET,
1629                 XmNbottomWidget, ge->access_list_label,
1630                 XmNbottomOffset, 10,
1631                 NULL);
1632         XtManageChild(ge->appt_list);
1633
1634         /*
1635         **  Move the label over to the top of the access list scrolling window
1636         */
1637         XtVaSetValues(ge->appt_list_label,
1638                 XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
1639                 XmNleftWidget, ge->appt_list_sw,
1640                 NULL);
1641
1642         XtVaSetValues(second_list_label,
1643                 XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET,
1644                 XmNleftWidget, ge->appt_list_sw,
1645                 XmNleftOffset, 17 * listfontextents.max_logical_extent.width,
1646                 NULL);
1647
1648         XtVaSetValues(ge->button_rc_mgr, XmNdefaultButton, ge->insert_button, NULL);
1649         XtVaSetValues(ge->button_rc_mgr, XmNcancelButton, ge->close_button, NULL);
1650         XmProcessTraversal(ge->dssw.what_text, XmTRAVERSE_CURRENT);
1651         XtVaSetValues(ge->base_form_mgr, XmNinitialFocus, ge->dssw.what_text, NULL);
1652
1653         /*
1654         **  Managed the base form, reset flags and set up initial X and Y
1655         **  values for the first dnd operation.
1656         */
1657         ManageChildren(ge->base_form_mgr);
1658         XtManageChild(ge->base_form_mgr);
1659
1660         rfp_init(&(ge->rfp), c, ge->base_form_mgr);
1661
1662         ge->access_data = CmDataListCreate();
1663         ge->list_data = CmDataListCreate();
1664         ge->initialX = -1;
1665         ge->initialY = -1;
1666         ge->doing_drag = False;
1667 }
1668
1669 /*******************************************************************************
1670 **
1671 **  External functions
1672 **
1673 *******************************************************************************/
1674 extern void
1675 add_to_gaccess_list(
1676         char                    *name,
1677         CSA_session_handle      cal_handle,
1678         unsigned int            user_access,
1679         int                     version,
1680         GEditor                 *ge,
1681         Boolean                 select_val)
1682 {
1683
1684         int             cnt = 1;
1685         char            access, *buf;
1686         XmString        xmstr;
1687         Calendar        *c;
1688         Props_pu        *p;
1689         Access_data     *new_data = NULL;
1690
1691         if (!ge)
1692                 return;
1693
1694         c = ge->cal;
1695         p = (Props_pu *)c->properties_pu;
1696
1697         while (ge->access_data && cnt <= ge->access_data->count) {
1698                 new_data = (Access_data *)
1699                         CmDataListGetData(ge->access_data, cnt);
1700                 if (new_data && strcmp(new_data->name, name) == 0) {
1701                         XmListDeselectPos(ge->access_list, cnt);
1702                         if (select_val)
1703                                 XmListSelectPos(ge->access_list, cnt, True);
1704                         return;
1705                 }
1706                 ++cnt;
1707         }
1708
1709         if (same_user(name, c->calname) ||  c->my_cal_handle == cal_handle) {
1710                 user_access = CSA_OWNER_RIGHTS;
1711                 access = 'Y';
1712         } else {
1713
1714                 if (version < DATAVER4) {
1715                         access = (user_access & (CSA_X_DT_INSERT_ACCESS |
1716                                 CSA_OWNER_RIGHTS)) ? 'Y' : 'N';
1717                 } else {
1718                         access = (user_access & (CSA_INSERT_PUBLIC_ENTRIES |
1719                                 CSA_INSERT_CONFIDENTIAL_ENTRIES |
1720                                 CSA_INSERT_PRIVATE_ENTRIES |
1721                                 CSA_OWNER_RIGHTS)) ? 'Y' : 'N';
1722                 }
1723         }
1724
1725         new_data = (Access_data *)ckalloc(sizeof(Access_data));
1726         new_data->appt_count = 0;
1727         new_data->appt_head = NULL;
1728         new_data->name = cm_strdup(name);
1729         new_data->cal_handle = cal_handle;
1730         new_data->version = version;
1731         new_data->entry_access = user_access;
1732         CmDataListAdd(ge->access_data, (void *)new_data, 0);
1733
1734         buf = (char *)ckalloc(ACCESS_NAME_LEN + cm_strlen(catgets(c->DT_catd,
1735                 1, 348, "Insert Permission")) + 5);
1736         sprintf(buf, "%-*s %c", ACCESS_NAME_LEN, name, access);
1737         xmstr = XmStringCreateLocalized(buf);
1738         free(buf);
1739         XmListAddItemUnselected(ge->access_list, xmstr, 0);
1740         if (select_val)
1741                 XmListSelectItem(ge->access_list, xmstr, True);
1742         XmStringFree(xmstr);
1743
1744         ge_set_modify_buttons(ge, ge->access_data->count);
1745 }
1746
1747 extern void
1748 add_all_gappt(GEditor *ge) {
1749         int             tick, i, j, range_count;
1750         CSA_uint32      entry_count = 0;
1751         char            *date;
1752         Props           *p;
1753         time_t          start, stop;
1754         Boolean         at_least_one;
1755         Props_pu        *pu;
1756         CSA_entry_handle*entry_list = NULL;
1757         CSA_return_code stat;
1758         Access_data     *step;
1759         OrderingType    o;
1760         SeparatorType   s;
1761         CSA_enum        *ops;
1762         CSA_attribute   *range_attr;
1763
1764         if (!geditor_showing(ge))
1765                 return;
1766
1767         /*
1768          * Bug in list widget - if it's empty and you select it, it core dumps.
1769          * So, make it insensitive - later, if we have any appointments, make
1770          * it sensitive.
1771          */
1772         XmListDeleteAllItems(ge->appt_list);
1773         XtSetSensitive(ge->appt_list, False);
1774
1775         p = (Props *)ge->cal->properties;
1776         pu = (Props_pu *)ge->cal->properties_pu;
1777         o = get_int_prop(p, CP_DATEORDERING);
1778         s = get_int_prop(p, CP_DATESEPARATOR);
1779         date = get_date_from_widget(ge->cal->view->date, ge->dssw.date_text,
1780                                     o, s);
1781         if (!date)
1782                 return;
1783
1784         if ((tick = cm_getdate(date, NULL)) <= 0)
1785                 return;
1786         start = lowerbound(tick);
1787         stop = next_ndays(tick, 1) - 1;
1788
1789         /*
1790          * For each calendar in the list of calendars pointed to by
1791          * access_data, look up that calendar's entries and add them to the
1792          * Access_data structure.
1793          */
1794         stat = CSA_SUCCESS;
1795         for (i = 1; i <= ge->access_data->count && stat == CSA_SUCCESS; i++) {
1796                 /*
1797                  * Get the individual calendar information and make sure we
1798                  * have browse access before attempting to get stuff.
1799                  */
1800                 step = (Access_data *)CmDataListGetData(ge->access_data, i);
1801                 if (!step || !step->cal_handle ||
1802                     !((step->version < DATAVER4 &&
1803                      step->entry_access & (CSA_OWNER_RIGHTS |
1804                      CSA_X_DT_BROWSE_ACCESS)) ||
1805                      (step->version >= DATAVER4 &&
1806                      step->entry_access & (CSA_OWNER_RIGHTS |
1807                      CSA_VIEW_PUBLIC_ENTRIES | CSA_VIEW_CONFIDENTIAL_ENTRIES |
1808                      CSA_VIEW_PRIVATE_ENTRIES))))
1809                         continue;
1810
1811                 setup_range(&range_attr, &ops, &range_count, start, stop,
1812                         CSA_TYPE_EVENT, 0, B_FALSE, step->version);
1813                 csa_list_entries(step->cal_handle, range_count, range_attr,
1814                         ops, &entry_count, &entry_list, NULL);
1815                 free_range(&range_attr, &ops, range_count);
1816
1817                 backend_err_msg(ge->frame, step->name, stat,
1818                                 pu->xm_error_pixmap);
1819                 if (stat != CSA_SUCCESS)
1820                         continue;
1821
1822                 if (step->appt_head && step->appt_count >= 0)
1823                         csa_free(step->appt_head);
1824                 step->appt_head = entry_list;
1825                 step->appt_count = entry_count;
1826         }
1827         if (stat != CSA_SUCCESS)
1828                 return;
1829
1830         /*
1831          * Everything is cool, add _all_ the appointments to the list
1832          */
1833         at_least_one = False;
1834         for (i = 1; i <= ge->access_data->count; i++) {
1835                 step = (Access_data *)CmDataListGetData(ge->access_data, i);
1836                 if (!step || step->appt_count <= 0 ||
1837                     !((step->version < DATAVER4 &&
1838                      step->entry_access & (CSA_OWNER_RIGHTS |
1839                      CSA_X_DT_BROWSE_ACCESS)) ||
1840                      (step->version >= DATAVER4 &&
1841                      step->entry_access & (CSA_OWNER_RIGHTS |
1842                      CSA_VIEW_PUBLIC_ENTRIES | CSA_VIEW_CONFIDENTIAL_ENTRIES |
1843                      CSA_VIEW_PRIVATE_ENTRIES))))
1844                         continue;
1845                 for (j = 0; j < step->appt_count; j++) {
1846                         ge_add_to_gappt_list(step, j, ge, !at_least_one);
1847                         at_least_one = True;
1848                 }
1849         }
1850
1851         /*
1852          * Make sure we have at least one appointment before sensitizing the
1853          * list widget (see comment above).
1854          */
1855         if (at_least_one)
1856                 XtSetSensitive(ge->appt_list, True);
1857
1858         XtVaSetValues(ge->change_button, XmNsensitive, False, NULL);
1859         XtVaSetValues(ge->delete_button, XmNsensitive, False, NULL);
1860 }
1861
1862 extern void
1863 geditor_clean_up(GEditor *ge) {
1864         remove_all_gaccess(ge);
1865 }
1866
1867 /*
1868 **  Return the nth appointment from the array
1869 */
1870 extern CSA_entry_handle
1871 geditor_nth_appt(GEditor *ge, int idx, Access_data **ad) {
1872         List_data       *ld;
1873
1874         ld = (List_data *)CmDataListGetData(ge->list_data, idx);
1875         if (ld && ld->entry_idx >= 0 && ld->entry_idx < ld->ad->appt_count) {
1876                 *ad = ld->ad;
1877                 return ld->ad->appt_head[ld->entry_idx];
1878         }
1879
1880         *ad = NULL;
1881         return 0;
1882 }
1883
1884 extern Boolean
1885 geditor_showing(GEditor *ge) {
1886         if (ge)
1887                 return ge->geditor_is_up;
1888         return False;
1889 }
1890
1891 /*
1892 extern void
1893 get_geditor_vals(GEditor *ge) {
1894         get_dssw_vals(&ge->dssw, ge->cal->view->date);
1895         get_rfp_vals(&ge->rfp);
1896 }
1897 */
1898
1899 extern void
1900 remove_all_gaccess_data(GEditor *ge) {
1901         int             i;
1902         Access_data     *step;
1903
1904         if (!ge->access_data)
1905                 return;
1906
1907         for (i = 1; i <= ge->access_data->count; i++) {
1908                 step = (Access_data *)CmDataListGetData(ge->access_data, i);
1909                 if (step && step->name)
1910                         free(step->name);
1911                 if (step && step->appt_head && step->appt_count >= 0)
1912                         csa_free(step->appt_head);
1913                 step->appt_head = NULL;
1914                 step->appt_count = 0;
1915         }
1916         CmDataListDeleteAll(ge->access_data, B_TRUE);
1917 }
1918
1919 extern void
1920 remove_all_gaccess(GEditor *ge) {
1921         remove_all_gaccess_data(ge);
1922         XmListDeleteAllItems(ge->access_list);
1923 }
1924
1925 extern void
1926 remove_from_gaccess_list(char *name, GEditor *ge) {
1927         int             cnt;
1928         List_data       *ld;
1929         Access_data     *ad;
1930
1931         for (cnt = ge->list_data->count; cnt > 0; cnt--) {
1932                 ld = (List_data *)CmDataListGetData(ge->list_data, cnt);
1933                 if (ld && strcmp(ld->ad->name, name) == 0) {
1934                         CmDataListDeletePos(ge->list_data, cnt, True);
1935                         XmListDeletePos(ge->appt_list, cnt);
1936                 }
1937         }
1938
1939         cnt = ge->access_data->count;
1940         ad = (Access_data *)CmDataListGetData(ge->access_data, cnt);
1941         while (ad && strcmp(ad->name, name) != 0)
1942                 ad = (Access_data *)CmDataListGetData(ge->access_data, --cnt);
1943         if (ad) {
1944                 if (ad->name)
1945                         free(ad->name);
1946                 if (ad->appt_head && ad->appt_count >= 0)
1947                         csa_free(ad->appt_head);
1948                 CmDataListDeletePos(ge->access_data, cnt, True);
1949                 XmListDeletePos(ge->access_list, cnt);
1950                 ge_set_modify_buttons(ge, ge->access_data->count);
1951         }
1952 }
1953
1954 extern void
1955 set_geditor_defaults(GEditor *ge, Tick start, Tick stop) {
1956         int     *list = NULL, cnt;
1957
1958         if (start > 0 || stop > 0) {
1959                 load_dssw_times(&ge->dssw, start, stop, False);
1960                 set_dssw_defaults(&ge->dssw, start, False);
1961         } else
1962                 set_dssw_defaults(&ge->dssw, ge->cal->view->date, True);
1963
1964         if (ge->rfp.rfp_form_mgr) 
1965                 set_rfp_defaults(&ge->rfp);
1966
1967         XmListGetSelectedPos(ge->access_list, &list, &cnt);
1968         ge_set_modify_buttons(ge, cnt);
1969         if (list)
1970                 XtFree((XtPointer)list);
1971
1972         ge->dsswFlags = ge->rfpFlags = 0;
1973 }
1974
1975 extern void
1976 set_geditor_title(GEditor *ge, char *name) {
1977         char            buf[MAXNAMELEN];
1978         Calendar        *c = ge->cal;
1979
1980         if (ge->frame) {
1981                 sprintf(buf, "%s - %s", catgets(c->DT_catd, 1, 349,
1982                         "Calendar : Group Appointment Editor"), name);
1983                 XtVaSetValues(ge->frame, XmNtitle, buf,
1984                         NULL);
1985         }
1986 }
1987
1988 extern void
1989 set_geditor_vals(GEditor *ge, Tick start, Tick stop) {
1990         if (start > 0 || stop > 0) {
1991                 load_dssw_times(&ge->dssw, start, stop, False);
1992                 set_dssw_vals(&ge->dssw, start);
1993         } else
1994                 set_dssw_vals(&ge->dssw, ge->cal->view->date);
1995
1996         set_rfp_vals(&ge->rfp);
1997
1998         ge->dsswFlags = ge->rfpFlags = 0;
1999 }
2000
2001 extern void
2002 show_geditor(Calendar *c, Tick start, Tick stop) {
2003         GEditor         *ge = (GEditor *)c->geditor;
2004
2005         if (!ge->frame)
2006                 ge_make_editor(c);
2007
2008         if (!geditor_showing(ge)) {
2009                 ds_position_popup(c->frame, ge->frame, DS_POPUP_LOR);
2010                 XmProcessTraversal(ge->dssw.what_text, XmTRAVERSE_CURRENT);
2011                 XtVaSetValues(ge->base_form_mgr, 
2012                         XmNinitialFocus, ge->dssw.what_text, 
2013                         NULL);
2014         }
2015
2016         XtPopup(ge->frame, XtGrabNone);
2017         ge->geditor_is_up = True;
2018         set_geditor_defaults(ge, start, stop);
2019         add_all_gappt(ge);
2020 }