Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtmail / libDtMail / Common / DtMailError.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: DtMailError.C /main/18 1999/02/08 09:32:25 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 <string.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <assert.h>
47 #include <errno.h>
48 #include <DtMail/DtMail.hh>
49 #include <DtMail/DtMailError.hh>
50 #include <DtMail/Common.h>
51 #include <Dt/MsgCatP.h>
52
53 #include <syslog.h>
54
55 #if defined(HPUX) && !defined(hpV4)
56 // HP-UX 9.* syslog.h does not define these.
57 //
58 extern "C" int syslog(int, const char *, ...);
59 extern "C" int openlog(const char *, int, int);
60 #endif
61
62 #include <EUSDebug.hh>
63
64 // Provide interface to the DtSvc function DtSimpleError
65 // When this interface is better defined, this can be removed
66 // and replaced with the appropriate include file
67
68 typedef enum {
69   DtIgnore,
70   DtInformation,
71   DtWarning,
72   DtError,
73   DtFatalError,
74   DtInternalError
75 } DtSeverity;
76
77 extern "C" void _DtSimpleError( 
78                         char *progName,
79                         DtSeverity severity,
80                         char *help,
81                         char *format,
82                         ...) ;
83
84 int                     DtMailDebugLevel = 0;
85 DtMailBoolean           DtMailEnv::_syslog_open = DTM_FALSE;
86 nl_catd                 DtMailEnv::_errorCatalog = (nl_catd) -1;  
87 const char *            DtMailEnv::DtMailCatalogDataFile = "libDtMail";
88 nl_catd                 DtMailMsgCat = DtMailEnv::_errorCatalog;// COMPATIBILITY
89
90
91 //
92 // NOTE - IMPORTANT -- READ ME
93 //
94 // The order of the strings below must match the
95 // entries in DtMail/MailError.h.
96 //
97 static const char * error_strings[] = {
98
99   // - DTME_NoError
100   "No error occurred.",
101
102   // - DTME_AlreadyLocked
103   "The mailbox is locked by another session.",
104
105   // - DTME_BadArg
106   "A bad argument was passed as a parameter to the operation.",
107
108   // - DTME_BadMailAddress
109   "The specified mail address could not be processed.",
110   
111   // - DTME_BadRunGroup
112   "The dtmail program is not running as group \"mail\".",
113
114   // - DTME_FileCreateFailed
115   "The requested file could not be created.",
116
117   // - DTME_FolderNotSet
118   "The mailbox to incorporate was not set.",
119
120   // - DTME_GetLockRefused
121   "The user refused to take the lock of a locked mailbox.",
122
123   // - DTME_ImplFailure
124   "The specified implementation could not perform the requested operation.",
125
126   // - DTME_InitializationFailed
127   "The instance could not be initialized.",
128
129   // - DTME_InternalFailure
130   "An internal failure occurred while performing the operation.",
131
132   // - DTME_InvalidError
133   "The error structure is invalid.",
134
135   // - DTME_InvalidOperationSequence
136   "An operation was attempted before the instance was initialized.",
137
138   // - DTME_MD5ChecksumFailed
139   "The MD5 signature did not match the message contents.",
140
141   // - DTME_MailTransportFailed
142   "Unable to communicate with the mail transport.",
143
144   // - DTME_NoDataType
145   "There is no data type that matches the transport type.",
146
147   // - DTME_NoImplementations
148   "No implementations were found for the mail library.",
149
150   // - DTME_NoMailBox
151   "The mailbox was uninitialized at load time.",
152
153   // - DTME_NoMemory
154   "No memory available for operation.",
155
156   // - DTME_NoMsgCat
157   "No message catalog exists for DtMail.",
158
159   // - DTME_NoNewMail
160   "There is no new mail to incorporate.",
161
162   // - DTME_NoObjectValue
163   "No value for the object could be found.",
164
165   // - DTME_NoSuchFile
166   "The mailbox does not exist and creation was not requested.",
167
168   // - DTME_NoSuchImplementation
169   "The specified implementation does not exist.",
170
171   // - DTME_NoSuchType
172   "The data type is not known to the library.",
173
174   // - DTME_NoUser
175   "The user for this session could not be identified.",
176
177   // - DTME_NotInbox
178   "The file specified is not a mailbox.",
179
180   // - DTME_NotLocked
181   "The mailbox is not locked for access.",
182
183   // - DTME_NotMailBox
184   "The requested file is not a mailbox in any format recognized by this implementation.",
185
186   // - DTME_NotSupported
187   "The operation is not supported by the current implementation.",
188
189   // - DTME_ObjectAccessFailed
190   "Unable to access an object required to complete the operation.",
191
192   // - DTME_ObjectCreationFailed
193   "Unable to create an object required to complete the operation.",
194
195   // - DTME_ObjectInUse
196   "An attempt was made to initialize an object that was already initialized.",
197
198   // - DTME_ObjectInvalid
199   "An invalid object was referenced.",
200
201   // - DTME_OpenContainerInterrupted
202   "The user interrupted the process of opening a mailbox.",
203
204   // - DTME_OperationInvalid
205   "An internal error occurred while performing the operation.",
206
207   // - DTME_OtherOwnsWrite
208   "Another mail program owns the write access to the mailbox.",
209
210   // - DTME_RequestDenied
211   "The other session denied the request for lock or copy.",
212
213   // - DTME_TTFailure
214   "A ToolTalk message could not be processed.",
215
216   // - DTME_TransportFailed
217   "The mail delivery transport failed.",
218
219   // - DTME_UnknownFormat
220   "The message is not in one of the supported formats.",  
221
222   // - DTME_UnknownOpenError
223   "An unknown error occurred when opening a mailbox.",
224
225   // - DTME_UserAbort
226   "The user aborted the operation.",
227
228   // - DTME_UserInterrupted
229   "The user interrupted the operation.",
230
231   // - DTME_ObjectReadOnly
232   "The mailbox permissions only allow read access.",
233
234   // - DTME_NoPermission,
235   "The user does not have access to the mailbox.",
236
237   // - DTME_IsDirectory,
238   "The specified path is a directory.",
239
240   // - DTME_CannotRemoveStaleMailboxLockFile
241   "Cannot lock mailbox (could not remove stale lock file).\nStale lock file: %s\nReason: %s",
242
243   // - DTME_CannotCreateMailboxLockFile
244   "Cannot lock mailbox (could not create lock file).\nMailbox lock file: %s\nReason: %s",
245
246   // - DTME_CannotCreateMailboxLockFile_NoPermission
247   "Cannot create lock file and lock mailbox because the user does not have\naccess to either the mailbox or the directory containing the mailbox.",
248
249   // - DTME_CannotCreateMailboxLockFile_IsDirectory
250   "Cannot create lock file and lock mailbox because the name for the\nmailbox lock file already exists and is a directory.",
251     
252   // - DTME_CannotCreateMailboxLockFile_NoSuchFile
253   "Cannot create lock file and lock mailbox because a component of the\npath name of the lock file is not a directory.",
254   
255   // - DTME_CannotCreateMailboxLockFile_RemoteAccessLost
256   "Cannot create lock file and lock mailbox because the remote system on\nwhich the lock file was to be created is no longer accessible.",
257   
258   // - DTME_CannotObtainInformationOnOpenMailboxFile
259   "Cannot obtain information on current mailbox file.\nMailbox file: %s\nReason: %s",
260
261   // - DTME_CannotCreateTemporaryMailboxFile
262   "Cannot create temporary mailbox file.\nTemporary Mailbox file: %s\nReason: %s",
263
264   // - DTME_CannotCreateTemporaryMailboxFile_NoPermission
265   "Cannot create temporary mailbox file because the user does not have\naccess to either the mailbox or the directory containing the mailbox.",
266
267   // - DTME_CannotCreateTemporaryMailboxFile_IsDirectory
268   "Cannot create temporary mailbox file because the name for the\ntemporary mailbox already exists and is a directory.",
269     
270   // - DTME_CannotCreateTemporaryMailboxFile_NoSuchFile
271   "Cannot create temporary mailbox file because a component of the\npath name of the temporary file is not a directory.",
272   
273   // - DTME_CannotCreateTemporaryMailboxFile_RemoteAccessLost
274   "Cannot create temporary mailbox file because the remote system on\nwhich the file was to be created is no longer accessible.",
275   
276   // - DTME_CannotSetPermissionsOfTemporaryMailboxFile
277   "Cannot set permissions on temporary mailbox file.\nTemporary Mailbox file: %s\nPermissions requested: %o\nReason: %s",
278
279   // - DTME_CannotSetOwnerOfTemporaryMailboxFile
280   "Cannot set owner of temporary mailbox file.\nTemporary Mailbox file: %s\nOwner uid requested: %d\nReason: %s",
281   
282   // - DTME_CannotSetGroupOfTemporaryMailboxFile
283   "Cannot set group of temporary mailbox file.\nTemporary Mailbox file: %s\nGroup gid requested: %d\nReason: %s",
284
285   // - DTME_CannotWriteToTemporaryMailboxFile
286   "Cannot write to temporary mailbox file.\nTemporary Mailbox file: %s\nReason: %s",
287
288   // - DTME_CannotWriteToTemporaryMailboxFile_ProcessLimitsExceeded
289   "Cannot write to temporary mailbox file because the process's file\nsize limit or the maximum file size has been reached.",
290   
291   // - DTME_CannotWriteToTemporaryMailboxFile_RemoteAccessLost
292   "Cannot write to temporary mailbox file because the remote system on\nwhich the file was created is no longer accessible.",
293   
294   // - DTME_CannotWriteToTemporaryMailboxFile_NoFreeSpaceLeft
295   "Cannot write to temporary mailbox file because there is no free\nspace left on the device on which the file was created.",
296   
297   // - DTME_CannotReadNewMailboxFile
298   "Cannot read new mailbox file\nReason: %s",
299
300   // - DTME_CannotReadNewMailboxFile_OutOfMemory
301   "Cannot read new mailbox file because no memory is available for the operation.",
302   
303   // - DTME_CannotRemoveMailboxLockFile
304   "Cannot unlock mailbox (could not remove lock file).\nMailbox lock file: %s\nReason: %s",
305
306   // - DTME_CannotRenameNewMailboxFileOverOld
307   "Cannot rename new mailbox file over old mailbox file.\nOld mailbox file still exists but complete and correct contents\nof mailbox contents have been saved in the new mailbox file.\nThis problem must be corrected manually as soon as possible.\nOld Mailbox file: %s\nNew Mailbox file: %s\nReason: %s",
308   
309   // - DTME_InternalAssertionFailure
310 "An internal error has occurred within this application.\nThere is no way to recover and continue from this error.\nError condition: %s\n",
311
312   // - DTME_ResourceParsingNoEndif
313 "An error occurred while parsing the .mailrc resource file.\nThere is a conditional if statement that does not have a corresponding endif statement.\n",
314   
315   // - DTME_AlreadyOpened,
316    "This mail folder is already opened.",
317
318   // - DTME_OutOfSpace,
319    "No Space on Temporary Filesystem.",
320
321   // - DTME_CannotCreateMailboxDotDtmailLockFile
322   "Mailer has detected a mailbox lockfile:\n%s",
323
324   // - DTME_MailboxInodeChanged
325   "Mailer can no longer access this mailbox.\nIt would be best to close and reopen it.",
326
327   // - DTME_MailServerAccess_AuthorizationFailed
328   "Cannot retrieve mail for '%s@%s' using '%s'.\nAuthorization failed.",
329   
330   // - DTME_MailServerAccess_Error
331   "Cannot retrieve mail for '%s@%s' using '%s'.\nThe server returned:\n     %s",
332   
333   // - DTME_MailServerAccess_MissingPassword
334   "Please enter a password for '%s@%s' using '%s'",
335   
336   // - DTME_MailServerAccess_ProtocolViolation
337   "Cannot retrieve mail for '%s@%s' using '%s'.\nClient/server protocol error.",
338   
339   // - DTME_MailServerAccess_ServerTimeoutError
340   "Cannot retrieve mail for '%s@%s' using '%s'.\nTimed out waiting for server.",
341   
342   // - DTME_MailServerAccess_SocketIOError
343   "Cannot retrieve mail for '%s@%s' using '%s'.\n%s.",
344   
345   // - DTME_AppendMailboxFile_Error
346   "Cannot append to mailbox",
347   
348   // - DTME_AppendMailboxFile_FileTooBig
349   "Cannot append to mailbox:  %s\nSYSERROR(%d):  %s.",
350   
351   // - DTME_AppendMailboxFile_LinkLost
352   "Cannot append to mailbox:  %s\nSYSERROR(%d):  %s.",
353   
354   // - DTME_AppendMailboxFile_NoSpaceLeft
355   "Cannot append to mailbox:  %s\nSYSERROR(%d):  %s.",
356   
357   // - DTME_AppendMailboxFile_SystemError
358   "Cannot append to mailbox:  %s\nSYSERROR(%d):  %s.",
359
360   // - DTME_GetmailCommandRetrieval_SystemError
361   "Getmail command failed:  %s\nSYSERROR(%d):  %s.",
362
363   // - DTME_GetmailCommandRetrieval_AbnormalExit
364   "Getmail command exited abnormally:  %s.",
365
366   // - DTME_PathElementPermissions
367   "Search permission denied on a component of the path prefix,\n'%s'.",
368
369   // - DTME_PathElementNotDirectory
370   "A component of the path prefix is not a directory,\n'%s'.",
371
372   // - DTME_PathElementDoesNotExist
373   "A component of the path prefix does not exist,\n'%s'.",
374
375   // - DTME_MailServerAccessInfo_SocketOpen
376   "Opening connection for '%s@%s'.",
377   
378   // - DTME_MailServerAccessInfo_NoMessages
379   "No messages for '%s@%s'.",
380   
381   // - DTME_MailServerAccessInfo_RetrievingMessage
382   "Retrieving message %d of %d for '%s@%s'.",
383   
384   // - DTME_MailServerAccessInfo_MessageTooLarge
385   "Skipping oversized message (%d bytes).",
386   
387   // - DTME_MAXDTME
388   NULL
389 };
390
391 DtMailEnv::DtMailEnv()
392 {
393   setCPP(NULL,NULL,NULL);
394   _error = DTME_NoError;
395   _message = NULL;
396   _tt_message = NULL;
397   _client = NULL;
398   _implClearFunc = NULL;
399   _fatal = DTM_FALSE;
400 }
401
402 #ifdef hpV4
403 #define GETMSG(catd, set, msg, dft) _DtCatgetsCached(catd, set, msg, dft)
404 #else
405 #define GETMSG(catd, set, msg, dft) catgets(catd, set, msg, dft)
406 #endif
407
408 char *
409 DtMailEnv::getMessageText(int set, int msg, char *dft)
410 {
411     static int oneTimeFlag = 0; // Only attempt to open message catalog once
412     char *message;
413     
414     if ((oneTimeFlag == 0) && (_errorCatalog == (nl_catd) -1))
415     {
416         oneTimeFlag++;
417         _errorCatalog = catopen((char*) DtMailCatalogDataFile, NL_CAT_LOCALE);
418     }
419     if (_errorCatalog != (nl_catd) -1)
420       message = GETMSG(_errorCatalog, set, msg, dft);
421
422     return message;
423 }
424
425 void
426 DtMailEnv::getErrorMessageText()
427 {
428     if (_message == NULL)
429     {
430         if (_error_minor_code >= DTME_MAXDTME)
431           _error_minor_code = DTME_InvalidError;
432
433         _message = getMessageText(
434                         MailErrorSet, _error_minor_code + 1,
435                         (char*) error_strings[_error_minor_code]);
436     }
437     if (_message == NULL)
438     {
439         _error = DTME_NoMemory;
440         _message = strdup(error_strings[_error_minor_code]);
441     }
442     else
443       _message = strdup(_message);
444 }
445
446 void
447 DtMailEnv::clear()
448 {
449   _error = DTME_NoError;
450
451   if (_message != NULL) {
452     free((char *)_message);
453     _message = NULL;
454   }
455
456   if (_tt_message != NULL) {
457     tt_message_destroy(_tt_message);
458     _tt_message = NULL;
459   }
460
461   if (_client != NULL && _implClearFunc != NULL) {
462     implClear();
463   }
464   _fatal = DTM_FALSE;
465 }
466
467 void
468 DtMailEnv::setError(const DTMailError_t minor_code, 
469                     DtMailBoolean fatal,
470                     Tt_message msg)
471 {
472   clear();                              // Clear out and free any old storage.
473
474   _error_minor_code = minor_code;       // Remember original error number
475   
476   if (minor_code != DTME_NoError ) {
477     _error = minor_code;
478     if (minor_code >= DTME_MAXDTME) {
479       _error = DTME_InvalidError;
480     }
481   }
482   _tt_message = msg;    // Save the new one.
483
484   _fatal = fatal;
485   return;
486 }
487
488 // given system error number, include that string into the given message,
489 // which must have a %s embedded within it
490 //
491
492 // DtMailEnv::errnoMessage -- convert current system error number to readable text
493 // Description:
494 //  Take the current system error number (in the global errno), and
495 //  return a pointer to a readable string that describes the error.
496 // Arguments:
497 //  <none>
498 // Outputs:
499 //  <none>
500 // Returns:
501 //  const char * -- pointer to ascii text describing current system error
502 //                      that is safe to refer to in an MT-hot environment
503 //
504 const char *
505 DtMailEnv::errnoMessage(void)
506 {
507   return(errnoMessage(errno));
508 }
509
510 // DtMailEnv::errnoMessage -- convert system error number to readable text
511 // Description:
512 //  Given a valid system error number (as returned in the global errno),
513 //  return a pointer to a readable string that describes the error.
514 // Arguments:
515 //  systemErrorNumber - errno value
516 // Outputs:
517 //  <none>
518 // Returns:
519 //  const char * -- pointer to ascii text describing system error
520 //                      that is safe to refer to in an MT-hot environment
521 //
522 const char *
523 DtMailEnv::errnoMessage(int systemErrorNumber)
524 {
525   // Get the system error message for the given system error
526   //
527   const char *syserrstr = strerror(systemErrorNumber);
528   if (!syserrstr)
529     syserrstr = (const char *)"?";
530   return(syserrstr);
531 }
532
533 // allow variable arguments at end and call vsprintf to process the
534 // error message string
535 //
536 void
537 DtMailEnv::vSetError(const DTMailError_t minor_code, 
538                     DtMailBoolean fatal,
539                     Tt_message msg,
540                     ... )
541 {
542   const int MessageBufferSize = 4096;
543   char *messageBuffer = new char[MessageBufferSize+1];
544   
545   // allow error to come up with the final translated error message
546   //
547   setError(minor_code, fatal, msg);
548   if (_message == NULL)
549     getErrorMessageText();
550
551   // Use the current error message as a format to vsprintf to
552   // construct the final message
553   //
554   va_list       var_args;
555
556   va_start(var_args, msg);
557   (void) vsprintf(messageBuffer, _message, var_args);
558   assert(strlen(messageBuffer) < MessageBufferSize);
559   va_end(var_args);
560   free((char *)_message);
561   _message = (const char *)strdup(messageBuffer);
562   delete [] messageBuffer;
563 }
564
565 #ifdef DEAD_WOOD
566 const char *
567 DtMailEnv::implGetMessage()
568 {
569   if (_client != NULL && _implMessageFunc != NULL) {
570         return((*_implMessageFunc)(_client));
571   }
572  return(NULL);
573 }
574
575 int
576 DtMailEnv::implGetError()
577 {
578   if (_client != NULL && _implErrorFunc != NULL) {
579         return((*_implErrorFunc)(_client));
580   }
581  return(0);
582 }
583 #endif /* DEAD_WOOD */
584
585 void
586 DtMailEnv::logError(DtMailBoolean criticalError, const char *format, ...) const
587 {
588   const int MessageBufferSize = 8192;
589   char *messageBuffer = new char[MessageBufferSize+1];
590   
591   if (!_syslog_open) {
592     //
593     // Open the log device and:
594     // LOG_PIG - log the pid number of process.
595     // LOG_CONS - log to the console, if the log device can not be opened.
596     // LOG_NOWAIT - Do not wait for syslog to finish, avoids the use of SIGCHLD
597     //
598     openlog("libDtMail", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_MAIL);
599   }
600
601   va_list       var_args;
602
603   va_start(var_args, format);
604   (void) vsprintf(messageBuffer, format, var_args);
605   assert(strlen(messageBuffer) < MessageBufferSize);
606   va_end(var_args);
607
608   syslog(criticalError == DTM_TRUE ? LOG_CRIT|LOG_ERR : LOG_ERR,
609          messageBuffer);
610   
611   _DtSimpleError("libDtMail", criticalError  == DTM_TRUE ? DtError : DtWarning,
612                 NULL, messageBuffer);
613   delete [] messageBuffer;
614 }
615
616 #ifdef DEAD_WOOD
617 void
618 DtMailEnv::logFatalError(DtMailBoolean criticalError, const char *format, ...)
619 {
620   _fatal = DTM_TRUE;
621
622   va_list       var_args;
623
624   va_start(var_args, format);
625   logError(criticalError, format, var_args);
626   va_end(var_args);
627 }
628 #endif /* DEAD_WOOD */