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