dtmail: resolve coverity warnings related to uninitialised members in C++ classes
[oweals/cde.git] / cde / programs / dtmail / dtmail / FindDialog.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 /*
24  *+SNOTICE
25  *
26  *      $TOG: FindDialog.C /main/7 1998/07/23 17:59:06 mgreess $
27  *
28  *      RESTRICTED CONFIDENTIAL INFORMATION:
29  *      
30  *      The information in this document is subject to special
31  *      restrictions in a confidential disclosure agreement between
32  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
33  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
34  *      Sun's specific written approval.  This document and all copies
35  *      and derivative works thereof must be returned or destroyed at
36  *      Sun's request.
37  *
38  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
39  *
40  *+ENOTICE
41  */
42
43 #include <assert.h>
44 #include <X11/Intrinsic.h>
45 #include <Xm/Form.h>
46 #include <Xm/RowColumn.h>
47 #include <Xm/MessageB.h>
48 #include <Xm/TextF.h>
49 #include <Xm/Label.h>
50 #include <Xm/PushB.h>
51 #include <Xm/DialogS.h>
52 #include <Xm/PanedW.h>
53 #include <Xm/LabelG.h>
54 #include <Xm/Text.h>
55 #include <Xm/SeparatoG.h>
56 #include <DtMail/DtMail.h>
57 #include <DtMail/DtMail.hh>
58 #include "FindDialog.h"
59 #include "RoamApp.h"
60 #include "RoamMenuWindow.h"
61 #include "RoamCmds.h"
62 #include "Help.hh"
63 #include "MailMsg.h"
64 #include <EUSCompat.h>
65 #include "str_utils.h"
66
67
68 //
69 // Clear out the data. After this function is complete the
70 // data should look as if the constructor was just called and
71 // before initialize().
72 //
73 void
74 FindDialog::clear()
75 {
76   register unsigned int         offset;
77
78   //
79   if (_text_labels != NULL) {
80     for (offset = 0; offset < _num_text_fields; offset++) {
81       if (_text_labels[offset] != NULL) {
82         free(_text_labels[offset]);
83       }
84     }
85     delete _text_labels;
86   }
87
88   //
89   if (_text_values != NULL) {
90     for (offset = 0; offset < _num_text_fields; offset++) {
91       if (_text_values[offset] != NULL) {
92         free(_text_values[offset]);
93       }
94     }
95     delete _text_values;
96   }
97
98   //
99   if (_text_abstract_name != NULL) {
100     for (offset = 0; offset < _num_text_fields; offset++) {
101       if (_text_abstract_name[offset] != NULL) {
102         free(_text_abstract_name[offset]);
103       }
104     }
105     delete _text_abstract_name;
106   }
107
108
109   //
110   if (_buttonData != NULL) {
111     for (offset = 0; offset < _num_buttons; offset++) {
112       if (_buttonData[offset].label != NULL) {
113         free(_buttonData[offset].label);
114       }
115     }
116     delete _buttonData;
117   }
118
119   if (_text_fields != NULL) {
120     delete _text_fields;
121   }
122
123   if (_text_names != NULL) {
124     delete _text_names;
125   }
126 }
127
128 //
129 // The only constructor.
130 //
131 FindDialog::FindDialog(RoamMenuWindow *parent) : Dialog("find", parent)
132 {
133   _roamWindow = parent;
134   _num_text_fields = 4;
135   _num_buttons = 5;
136   _status_text = NULL;
137
138   //
139   // Allocate storage for labels, widgets, and data.
140   //
141   _text_labels = new char *[_num_text_fields];
142   _text_names = new char *[_num_text_fields];
143   _text_values = new char *[_num_text_fields];
144   _text_abstract_name = new char *[_num_text_fields];
145   _text_fields = new Widget[_num_text_fields];
146   _buttonData = new ActionAreaItem[_num_buttons];
147   _searchForward = TRUE;
148
149   //
150   // Initialize the buttons.
151   //
152   _buttonData[0].label = strdup(GETMSG(DT_catd, 1, 183, "Find"));
153   _buttonData[0].callback = findCallback;
154   _buttonData[0].data = (caddr_t) this;
155
156 #ifdef NL_OBSOLETE
157   /*
158    * NL_COMMENT
159    * This is an obsolete message.  Replaced by message 220 in set 1
160    */
161   _buttonData[1].label = strdup(GETMSG(DT_catd, 1, 184, "Find & Select All"));
162 #endif
163    /*
164     * NL_COMMENT
165     * This message replaces message 184 in set 1
166     */
167   _buttonData[1].label = strdup(GETMSG(DT_catd, 1, 220, "Select All"));
168   _buttonData[1].callback = findSelectAllCallback;
169   _buttonData[1].data = (caddr_t) this;
170
171   _buttonData[2].label = strdup(GETMSG(DT_catd, 1, 185, "Clear"));
172   _buttonData[2].callback = clearCallback;
173   _buttonData[2].data = (caddr_t) this;
174
175   _buttonData[3].label = strdup(GETMSG(DT_catd, 1, 186, "Close"));
176   _buttonData[3].callback = closeCallback;
177   _buttonData[3].data = (caddr_t) this;
178
179   _buttonData[4].label = strdup(GETMSG(DT_catd, 1, 187, "Help"));
180   _buttonData[4].callback = HelpCB;
181   _buttonData[4].data = (caddr_t) DTMAILFINDDIALOG;
182
183   _text_labels[0] = strdup(GETMSG(DT_catd, 1, 188, "To:"));
184   _text_labels[1] = strdup(GETMSG(DT_catd, 1, 189, "From:"));
185   _text_labels[2] = strdup(GETMSG(DT_catd, 1, 190, "Subject:"));
186   _text_labels[3] = strdup(GETMSG(DT_catd, 1, 191, "Cc:"));
187
188   // These strings should not be translated.  They are
189   // the Motif names for the widgets that will be created (they are
190   // not the labels).
191   _text_names[0] = "To";
192   _text_names[1] = "From";
193   _text_names[2] = "Subject";
194   _text_names[3] = "Cc";
195
196   //
197   // Initialize the names of the fields to the abstract
198   // names used by libDtMail.
199   //
200   _text_abstract_name[0] = strdup(DtMailMessageTo);
201   _text_abstract_name[1] = strdup(DtMailMessageSender);
202   _text_abstract_name[2] = strdup(DtMailMessageSubject);
203   _text_abstract_name[3] = strdup(DtMailMessageCc);
204 }
205
206 //
207 // Print a string in the status line of the find dialog.
208 //
209 void
210 FindDialog::setStatus(const char * str)
211 {
212     char *tmpstr = strdup(str);
213     XmString label = XmStringCreateLocalized(tmpstr);
214  
215     XtVaSetValues(_status_text,
216                   XmNlabelString, label,
217                   NULL);
218  
219     XmUpdateDisplay(baseWidget());
220     XmStringFree(label);
221 }
222
223 //
224 // Clear the status line of the find dialog.
225 //
226 void
227 FindDialog::clearStatus(void)
228 {
229     setStatus(" ");
230 }
231
232 //
233 // Create the guts of the dialog
234 //
235 Widget
236 FindDialog::createWorkArea(Widget dialog)
237 {
238   // TODO - CHECK ERROR!!!
239   Widget *label = new Widget[_num_text_fields]; 
240
241
242   register unsigned int         offset;
243
244   _name = GETMSG(DT_catd, 1, 192, "Mailer - Find");
245
246   title(_name);
247
248         // make this a modal dialog
249         /*
250         XtVaSetValues (dialog,
251                         XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL,
252                         NULL);
253         */
254
255         printHelpId("dialog", dialog);
256
257   /* add help callback */
258   // XtAddCallback(dialog, XmNhelpCallback, HelpCB, helpId);
259
260         Widget fd_pane = XtVaCreateWidget ("fd_pane",
261                                 xmPanedWindowWidgetClass,
262                                 dialog,
263                                 XmNsashWidth,   1,
264                                 XmNsashHeight,  1,
265                                 NULL);
266
267         printHelpId ("fd_pane", fd_pane);
268         // add help callback
269         // XtAddCallback (fd_pane, XmNhelpCallback, HelpCB, helpId);
270
271         Widget  fd_form = XtVaCreateWidget ("fd_form",
272                                 xmFormWidgetClass,
273                                 fd_pane,
274                                 XmNfractionBase,        100,
275                                 NULL);
276
277         printHelpId ("fd_form", fd_form);
278         // add help callback
279         // XtAddCallback (fd_form, XmNhelpCallback, HelpCB, helpId);
280
281
282         Widget _fd_labelbox = XtVaCreateManagedWidget ("_fd_labelbox",
283                                 xmRowColumnWidgetClass,
284                                 fd_form,
285                                 XmNtopAttachment,       XmATTACH_FORM,
286                                 XmNleftAttachment,      XmATTACH_POSITION,
287                                 XmNrightAttachment,     XmATTACH_POSITION,
288                                 XmNleftPosition,        5,
289                                 XmNrightPosition,       95,
290                                 XmNpacking,             XmPACK_COLUMN,
291                                 XmNnumColumns,          2,
292                                 XmNorientation,         XmVERTICAL,
293                                 XmNisAligned,           True,
294                                 XmNentryAlignment,      XmALIGNMENT_END,
295                                 XmNentryVerticalAlignment,      XmALIGNMENT_CENTER,
296                                 NULL); 
297         printHelpId ("_fd_labelbox", _fd_labelbox);
298         // add help callback
299         // XtAddCallback (_fd_labelbox, XmNhelpCallback, HelpCB, helpId);
300
301
302         Widget  *_fd_labels = new Widget [_num_text_fields];
303
304         int     _fd_i = 0;
305         for (_fd_i = 0; _fd_i < _num_text_fields; _fd_i++)
306         {
307                 _fd_labels [_fd_i] = XtVaCreateManagedWidget (
308                                         _text_labels [_fd_i],
309                                         xmLabelGadgetClass,
310                                         _fd_labelbox,
311                                         NULL);
312
313                 printHelpId ("_fd_labels [%s]", _fd_labels [_fd_i]);
314                 // naturally, this is bogus --must be fixed to return proper label
315                 // add help callback
316                 // XtAddCallback(_fd_labels [_fd_i], XmNhelpCallback, HelpCB, helpId);
317         }
318
319         for (_fd_i = 0; _fd_i < _num_text_fields; _fd_i++)
320         {
321                 _text_fields [_fd_i] = XtVaCreateManagedWidget (
322                                         _text_names [_fd_i],
323                                         xmTextFieldWidgetClass,
324                                         _fd_labelbox,
325                                         NULL);
326                 printHelpId ("_text_fields [%s]", _text_fields [_fd_i]);
327                 // naturally, this is bogus --must be fixed to return proper label
328                 // add help callback
329                 // XtAddCallback(_text_fields [_fd_i], XmNhelpCallback, HelpCB, helpId);
330
331                 XtAddCallback(_text_fields [_fd_i], XmNactivateCallback,
332                         (XtCallbackProc)textFieldCallback, (XtPointer)this);
333         }
334
335
336   XmString      strForward = XmStringCreateLocalized(GETMSG(DT_catd, 1, 193, "Forward"));
337   XmString      strBackward = XmStringCreateLocalized(GETMSG(DT_catd, 1, 194, "Backward"));
338
339   Widget fd_direction
340         = XmVaCreateSimpleRadioBox(fd_form,
341                                 "Direction",
342                                0,               // Initial selection
343                                directionCallback,
344                                 //NULL,
345                                XmVaRADIOBUTTON, strForward, NULL, NULL, NULL,
346                                XmVaRADIOBUTTON, strBackward, NULL, NULL, NULL,
347                                XmNuserData,     this,
348                                 XmNsensitive,   True,
349                                 XmNtopAttachment,       XmATTACH_WIDGET,
350                                 XmNtopWidget,           _fd_labelbox,
351                                 XmNorientation, XmHORIZONTAL,
352                                 XmNleftAttachment,      XmATTACH_POSITION,
353                                 XmNleftPosition,        33,
354                                NULL);
355          printHelpId ("fd_direction", fd_direction);
356         // add help callback
357         //XtAddCallback (fd_direction, XmNhelpCallback, HelpCB, helpId);
358
359   XmStringFree(strForward);
360   XmStringFree(strBackward);
361
362   //
363   // Now create the Action Area.
364   //
365 #define TIGHTNESS       20
366
367   register Widget               widget;
368
369   Widget fd_action = XtVaCreateWidget("actionArea",
370                                  xmFormWidgetClass,
371                                  fd_pane,
372                                  XmNleftAttachment,     XmATTACH_FORM,
373                                  XmNrightAttachment,    XmATTACH_FORM,
374                                  XmNfractionBase, TIGHTNESS * _num_buttons-1,
375                                  NULL);
376          printHelpId ("actionArea", fd_action);
377         // add help callback
378         //XtAddCallback (fd_action, XmNhelpCallback, HelpCB, helpId);
379
380   for (offset = 0; offset < _num_buttons; offset++) 
381   {  widget = XtVaCreateManagedWidget(_buttonData[offset].label,
382                                      xmPushButtonWidgetClass,   fd_action,
383
384                                      XmNleftAttachment,
385                                      offset ? XmATTACH_POSITION:XmATTACH_FORM,
386
387                                      XmNleftPosition,   TIGHTNESS * offset,
388                                      XmNtopAttachment,  XmATTACH_FORM,
389
390                                      XmNrightAttachment,
391                                      offset != _num_buttons - 1 ? XmATTACH_POSITION : XmATTACH_FORM,
392
393                                      XmNrightPosition,
394                                      TIGHTNESS * offset + (TIGHTNESS - 1),
395
396                                      XmNshowAsDefault,  offset == 0,
397                                      NULL);
398
399         // again, bogus -- doesn't each one need a unique tag?
400          printHelpId ("widget", widget);
401         // add help callback
402         //XtAddCallback (widget, XmNhelpCallback, HelpCB, helpId);
403
404     if (_buttonData[offset].callback != NULL) {
405       XtAddCallback(widget, XmNactivateCallback,
406                     _buttonData[offset].callback,
407                     _buttonData[offset].data);
408     }
409
410
411     if (offset == 0) {
412       Dimension         height;
413       Dimension         margin;
414
415       XtVaGetValues(fd_action, XmNmarginHeight, &margin, NULL);
416       XtVaGetValues(widget, XmNheight, &height, NULL);
417       height +=2 * margin;
418       XtVaSetValues(fd_action,
419                     XmNdefaultButton,   widget,
420                     XmNpaneMaximum,     height,
421                     XmNpaneMinimum,     height,
422                     NULL);
423
424     }
425   }
426
427   _status_text = XtVaCreateManagedWidget("StatusLabel",
428                                            xmLabelWidgetClass, fd_pane,
429                                            XmNrightAttachment, XmATTACH_FORM,
430                                            XmNleftAttachment, XmATTACH_FORM,
431                                            XmNalignment, XmALIGNMENT_BEGINNING,
432                                            NULL);
433             
434   Dimension height;
435   XtWidgetGeometry size;
436
437   size.request_mode = CWHeight;
438   XtQueryGeometry(_status_text, NULL, &size);
439   XtVaSetValues(_status_text,
440                 XmNpaneMaximum, size.height,
441                 XmNpaneMinimum, size.height,
442                 NULL);
443  
444   clearStatus();
445
446   XtManageChild (fd_form);
447   XtManageChild (fd_direction);
448   XtManageChild(fd_action);
449   XtManageChild(fd_pane);
450
451   XtManageChild(dialog);
452
453   // Make sure get the height of the dialog after it has been
454   // managed.
455   XtVaGetValues(dialog, XmNheight, &height, NULL);
456   XtVaSetValues(dialog, 
457                 XmNmappedWhenManaged, True,
458                 XmNminHeight, height,
459                 NULL);
460   XtRealizeWidget(dialog);
461
462   return (fd_pane);
463 }
464
465
466 //
467 // Look for all matching messages.
468 //
469 Boolean
470 FindDialog::findMatching(Boolean findAll)
471 {
472   // TODO - CHECK ERROR!!!
473   DtMailEnv             error;
474   unsigned int          matchCount = 0;
475
476   /* NL_COMMENT
477    * This string is displayed on the find dialog status line
478    * when searching for a matching message.
479    */
480
481   setStatus(GETMSG(DT_catd, 1, 231, "Searching..."));
482   busyCursor();
483   theRoamApp.busyAllWindows(NULL);
484
485   //
486   // Get the active list.
487   //
488   MsgScrollingList      * displayList = _roamWindow->list();
489
490   //
491   // Find  the max. number of messages that we are to find matching.
492   //
493   int                     numberMessages = displayList->get_num_messages();
494
495   //
496   // Are there any messages?
497   //
498   if (numberMessages > 0) {
499
500     //
501     // A pointer to the currently interesting message.
502     //
503     register DtMailMessageHandle          currentHandle = NULL;
504
505     //
506     // The offset of the currentHandle in the MsgScrollingList.
507     //
508     register int                  handleOffset;
509
510     //
511     // Find the current message. We would always start from the
512     // currently selected message.
513     //
514     // Get the handle to the currently displaied message.
515     //
516     DtMailMessageHandle   initialHandle = displayList->current_msg_handle();
517
518     //
519     // Get the list of DtMailMessageHandle's.
520     
521     MsgHndArray         * msgHandles = displayList->get_messages();
522
523     //
524     // Up to all of them can match, allocate and clear the list.
525     //
526     DtMailMessageHandle * matchList = NULL;
527     if (findAll) {
528       matchList = new DtMailMessageHandle[numberMessages+1];
529     }
530     unsigned int         matchOffset = 0;
531
532     //
533     // Deselect all messages.
534     //
535     XmListDeselectAllItems(displayList->baseWidget());
536
537     //
538     // Start the search from the initially displaied message (+1).
539     //
540     handleOffset = displayList->position(initialHandle) - 1;
541     if (_searchForward) {
542       handleOffset++;
543       if (handleOffset >= numberMessages) {
544         handleOffset = 0;
545       }
546     } else {
547       handleOffset--;
548       if (handleOffset < 0) {
549         handleOffset = numberMessages - 1;
550       }
551     }
552
553     for (; handleOffset < numberMessages;) {
554       currentHandle = msgHandles->at(handleOffset)->message_handle;
555     
556       //
557       // See if this message is a match, if it is...
558       //
559       if (compareMessage(currentHandle)) {
560         matchCount++;
561
562         //
563         // If we are finding all, then add to the list.
564         // If not, then display this message and we are done.
565         //
566         if (findAll) {
567           matchList[matchOffset++] = currentHandle;
568         } else {
569           XmListDeselectAllItems(displayList->baseWidget());
570           //displayList->set_selected_item_position(handleOffset);
571           displayList->display_and_select_message(error, currentHandle);
572           break;                        // Only one.
573         }
574       }
575
576       //
577       // If we have looped back to the initial
578       // message (handle), then we are done.
579       //
580       if (currentHandle == initialHandle) {
581         break;
582       }
583
584       //
585       // Get the next message.
586       //
587       // If we have reached the end, start over.
588       // (as if the list was a circular list)
589       //
590       // We loop forward (_searchForward == TRUE) else we loop backward.
591       //
592       if (_searchForward) {
593         handleOffset++;
594         if (handleOffset >= numberMessages) {
595           handleOffset = 0;
596         }
597       } else {
598         handleOffset--;
599         if (handleOffset < 0) {
600           handleOffset = numberMessages - 1;
601         }
602       }
603       currentHandle = msgHandles->at(handleOffset)->message_handle;
604     }
605
606     //
607     // Select all the messages that match, and display the last
608     // one in the list.
609     //
610     if (findAll) {
611       
612       displayList->select_all_and_display_last(error, matchList, matchCount);
613       if (matchCount > 0) {
614         char *line = new char[80];
615         /* NL_COMMENT
616          * These strings are displayed on the find dialog status line
617          * when one or more matching messages are found.  The first
618          * string is displayed when there is one matching message,
619          * and the second string is displayed when there is more than
620          * one.  The %d is the number of messages that matched.
621          */
622         if (matchCount == 1) {
623             strcpy(line, GETMSG(DT_catd, 1, 232, "1 message selected"));
624         } else {
625             sprintf(line, GETMSG(DT_catd, 1, 233, "%d messages selected"), 
626                             matchCount);
627         }
628         setStatus(line);
629         delete [] line;
630       }
631
632       // Clean up.
633       delete matchList;
634       matchList = NULL;
635     }
636   }
637
638   normalCursor();
639   theRoamApp.unbusyAllWindows();
640   if (error.isNotSet()) {
641     if (matchCount > 0) {
642         if (!findAll) {
643             clearStatus();
644         }
645         return(TRUE);
646     }
647   }
648   /* NL_COMMENT
649    * This string is displayed on the find dialog status line when
650    * no matching messages were found.
651    */
652   setStatus(GETMSG(DT_catd, 1, 234, "No matches were found"));
653   return(False);
654 }
655
656 Boolean
657 FindDialog::compareMessage(DtMailMessageHandle    handle)
658 {
659   Boolean                               found = False;
660   register unsigned int         offset;
661
662   //
663   // Check for something to do.
664   //
665   for (offset = 0; offset < _num_text_fields; offset++) {
666     if (_text_values[offset] != NULL) {
667       break;
668     }
669   }
670
671   // If all fields are empty then we match anything
672   if (offset >= _num_text_fields) {
673         return TRUE;
674   }
675
676   if (offset < _num_text_fields && handle != NULL) {
677
678     // TODO - CHECK ERROR!!!
679     DtMailEnv           error;
680
681     //
682     // Get the mail box.
683     //
684     DtMail::MailBox     * mbox = _roamWindow->mailbox();
685
686     //
687     // Get the DtMail::Message and Envelope for this handle.
688     //
689     DtMail::Message     * message = mbox->getMessage(error, handle);
690     DtMail::Envelope    * envelope = message->getEnvelope(error);
691
692     //
693     // Get the meassage header.
694     //
695     DtMailValueSeq        header;
696
697     for (offset = 0; offset < _num_text_fields; offset++) {
698       if (_text_values[offset] != NULL) {
699         if (_text_abstract_name[offset] != NULL) {
700           envelope->getHeader(error, _text_abstract_name[offset],
701                               DTM_TRUE, header);
702           found = TRUE;
703         } else {
704           envelope->getHeader(error, _text_names[offset],
705                               DTM_FALSE, header);
706           found = TRUE;
707         }
708         if (!compareHeader(error, header, _text_values[offset])) {
709           found = False;
710           break;
711         }
712         else {
713           // Problem: if we have multiple search fields ... and use
714           // the same "header" array ... "compareHeader" looks for
715           // each "find" field in each (available) header field.
716           // So, make sure only one is available for searching.
717           // Really "offset" should be passed to "compareHeader" ...
718           // That way, correct comparison can be done and the
719           // memory for this array can be released correctly via the
720           // destructor .... since "remove" fails to do so.
721           header.remove(0);
722         }
723       }
724     }
725     if (offset > _num_text_fields) {
726       found = TRUE;
727     }
728   }
729   return(found);
730 }
731
732 #if !defined(CSRG_BASED) && !defined(linux) && !defined(sun)
733 //
734 // See if string 'toFind' is anyware in string 'str'.
735 // A case-insensitive version of strstr().
736 //
737 static const char       *
738 strcasestr(const char *str, const char *toFind)
739 {
740   const char    *result = NULL;         // Default to not found.
741
742   if (str && toFind) {          // Sanity check
743     register int        offset = 0;
744     register int        lenToFind = strlen(toFind);
745     register int        lenStr = strlen(str);
746
747     //
748     // If toFind == "", then return the entire string (like strstr()).
749     //
750     if (lenToFind == 0) {
751       result = str;
752     } else {
753       //
754       // Start at each position in the string and look for
755       // toFind - ignore case.
756       //
757       for (offset = 0; offset + lenToFind <= lenStr; offset++) {
758         if (strncasecmp(&str[offset], toFind, lenToFind) == 0) {
759           result = &str[offset];
760           break;
761         }
762       }
763     }
764   }
765   return(result);
766 }
767 #endif
768
769 Boolean
770 FindDialog::compareHeader(DtMailEnv             & error,
771                           DtMailValueSeq        & header,
772                           const char            * cmpToString)
773 {
774   register int          headerOffset = header.length() - 1;
775
776   error.clear();
777
778   while(headerOffset >= 0) {
779     if ((strcasestr(*(header[headerOffset]), cmpToString)) != NULL) {
780       return(TRUE);
781     }
782     headerOffset--;
783   }
784   return(False);
785 }
786
787 //
788 // Pull all fields out of the dialog and store in the class.
789 //
790 void
791 FindDialog::getAllFields()
792 {
793   register unsigned int         offset;
794
795   for (offset = 0; offset < _num_text_fields; offset++) {
796     if (_text_fields[offset] != NULL) {
797       _text_values[offset] = XmTextFieldGetString(_text_fields[offset]);
798
799       // Ignore zero length strings.
800       if (_text_values[offset] != NULL) {
801         if (strlen(_text_values[offset]) == 0) {
802           _text_values[offset] = NULL;
803         }
804       }
805     }
806   }
807
808   return;
809 }
810
811 void
812 FindDialog::textFieldCallback(
813         Widget          field,
814         XtPointer       data,
815         XtPointer)
816 {
817         char *s;
818         FindDialog    *findData = (FindDialog *)data;
819
820         if (*(s = XmTextGetString(field)) == '\0') {
821                 // Empty field.  Traverse
822                 (void) XmProcessTraversal(field, XmTRAVERSE_NEXT_TAB_GROUP);
823         } else {
824                 // Field not empty. Do search
825                 findData->getAllFields();
826                 if (!findData->findMatching(False)) {
827                         XBell(XtDisplay(field), 0);
828                 }
829         }
830
831         return;
832 }       
833
834 void
835 FindDialog::directionCallback(Widget    widget,
836                               XtPointer closure,
837                               XtPointer)
838 {
839   int          which = (int) ((long) closure);  // closure contains button #
840   FindDialog    *find; 
841   
842   // Client data is actually on the @!$?@* parent, not the toggle item
843   XtVaGetValues(XtParent(widget), XmNuserData, &find, NULL);
844
845   if (which == 0) {
846     find->setSearchForward(TRUE);
847   } else {
848     find->setSearchForward(False);
849   }
850
851   return;
852 }
853
854 void
855 FindDialog::findCallback(Widget         /*button*/,
856                          XtPointer      closure,
857                          XtPointer      /*call_data*/)
858 {
859   FindDialog    *findData = (FindDialog *)closure;
860
861   findData->getAllFields();
862   findData->findMatching(False);
863   return;
864 }
865
866
867 void
868 FindDialog::findSelectAllCallback(Widget        /*button*/,
869                                   XtPointer     closure,
870                                   XtPointer     /*call_data*/)
871 {
872   FindDialog    *findData = (FindDialog *)closure;
873
874   findData->getAllFields();
875   findData->findMatching(TRUE);
876   return;
877 }
878
879 void
880 FindDialog::clearCallback(Widget        /*button*/,
881                           XtPointer     closure,
882                           XtPointer     /*call_data*/)
883 {
884   FindDialog    *findData = (FindDialog *)closure;
885   register unsigned int         offset;
886
887   for (offset = 0; offset < findData->_num_text_fields; offset++) {
888     if (findData->_text_fields[offset] != NULL) {
889       XmTextFieldSetString(findData->_text_fields[offset], "");
890     }
891   }
892   return;
893 }
894
895 void
896 FindDialog::closeCallback(Widget        /*button*/,
897                           XtPointer     closure,
898                           XtPointer     /*call_data*/)
899 {
900   FindDialog    *findData = (FindDialog *)closure;
901   
902   findData->popdown();
903   return;
904 }