Fix typo in license headers
[oweals/cde.git] / cde / programs / dtmail / libDtMail / Common / DtMailServer.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  *+SNOTICE
25  *
26  *      $TOG: DtMailServer.C /main/23 1999/01/29 14:46:18 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, 1995, 1995 Sun Microsystems, Inc.  All rights reserved.
39  *
40  *+ENOTICE
41  */
42
43 #include <ctype.h>
44 #include <errno.h>
45 #include <pwd.h>
46 #include <setjmp.h>
47 #include <signal.h>
48 #include <stdio.h>
49 #include <stdarg.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <sys/types.h>
53 #include <sys/time.h>
54 #include <time.h>
55 #include <unistd.h>
56
57 #include <DtMail/DtMailError.hh>
58 #include <DtMail/DtMailServer.hh>
59 #include <DtMail/IO.hh>
60
61 #if defined(USE_ITIMER_REAL)
62 #define SIGNAL_TYPE     SIGALRM
63 #define ITIMER_TYPE     ITIMER_REAL
64 #else
65 #define SIGNAL_TYPE     SIGVTALRM
66 #define ITIMER_TYPE     ITIMER_VIRTUAL
67 #endif
68
69 #define dtmasTAGCLR()   *_transtag = '\0'; _transnum=0;
70 #define dtmasTAGGEN()   (sprintf(_transtag, "a%04d", ++_transnum), _transtag)
71 #define dtmasTAGGET()   (_transtag)
72
73 static jmp_buf  restart;
74
75 DtMailServer::DtMailServer(
76                 char                    *folder,
77                 DtMail::Session         *session,
78                 DtMail::MailBox         *mailbox,
79                 DtMailAppendCallback    append_mailbox_cb,
80                 void                    *append_mailbox_cb_data)
81 {
82     struct passwd       pw;
83
84     GetPasswordEntry(pw);
85
86     if (folder)
87       _folder           = strdup(folder);
88     else
89       _folder           = "INBOX";
90     _session            = session;
91     _mailbox            = mailbox;
92
93     _append_mailbox_cb  = append_mailbox_cb;
94     _append_mailbox_cb_data
95                         = append_mailbox_cb_data;
96     _protologging       = get_mailrc_value(
97                                         _session, _folder,
98                                         DTMAS_PROPKEY_PROTOLOGGING,
99                                         (Boolean) False);
100     _protologgingplus   = get_mailrc_value(
101                                         _session, _folder,
102                                         DTMAS_PROPKEY_PROTOLOGGINGPLUS,
103                                         (Boolean) False);
104     _errorstring        = NULL;
105     _password           = get_mailrc_value(
106                                         _session, _folder,
107                                         DTMAS_PROPKEY_PASSWORD,
108                                         NULL, DTM_TRUE);
109     _removeafterdelivery
110                         = get_mailrc_value(
111                                         _session, _folder,
112                                         DTMAS_PROPKEY_REMOVEAFTERDELIVERY,
113                                         True);
114     _retrieveold        = get_mailrc_value(
115                                         _session, _folder,
116                                         DTMAS_PROPKEY_RETRIEVEOLD,
117                                         True);
118     _retrieveerrors     = 0;
119     _servername         = get_mailrc_value(
120                                         _session, _folder,
121                                         DTMAS_PROPKEY_SERVERNAME,
122                                         DTMAS_PROPDFLT_SERVERNAME);
123     _shroud             = NULL;
124     _sizelimit          = 0;
125     _sockfp             = NULL;
126     dtmasTAGCLR();
127     _transnum           = 0;
128     _timeout            = get_mailrc_value(
129                                         _session, _folder,
130                                         DTMAS_PROPKEY_TIMEOUT,
131                                         DTMAS_TIMEOUT);
132     _username           = get_mailrc_value(
133                                         _session, _folder,
134                                         DTMAS_PROPKEY_USERNAME,
135                                         pw.pw_name);
136 }
137
138 DtMailServer::~DtMailServer()
139 {
140     if (_errorstring) free(_errorstring);
141     if (_folder) free(_folder);
142     if (_password) free(_password);
143     if (_servername) free(_servername);
144     if (_shroud) free(_shroud);
145     if (_username) free(_username);
146 }
147
148 void
149 DtMailServer::set_password(char *password)
150 {
151     if (NULL == password) return;
152
153     if (NULL != _password) free(_password);
154     _password = NULL;
155     if (NULL != password) _password = strdup(password);
156 }
157
158 //
159 // Read message content and append to mailbox
160 //
161 //      len     - Length of message.
162 //
163 #if defined(reallyoldsun) || defined(USL)
164 #define SA_HANDLER_TYPE void (*)(void)
165 #else
166 #define SA_HANDLER_TYPE void (*)(int)
167 #endif
168
169 DTMailError_t
170 DtMailServer::ptrans_retrieve_readandappend(
171                                 DtMailEnv       &error,
172                                 long            len)
173 {
174     static char *pname = "DtMailServer::ptrans_retrieve_readandappend";
175     static char *from = "From ";
176     struct sigaction action, o_action;
177     int from_done = FALSE;
178     int done = FALSE;
179     size_t nread = 0;
180     char *s, *t;
181
182     memset((char*) &action, 0, sizeof(struct sigaction));
183     memset((char*) &o_action, 0, sizeof(struct sigaction));
184     action.sa_handler = (SA_HANDLER_TYPE) SIG_IGN;
185     sigaction(SIGINT, (const struct sigaction *) &action, &o_action);
186
187     while (! done)
188     {
189         size_t  nbytes;
190
191         if (nread < len)
192         {
193             if (DTMAS_MSGBUFSIZE - 1 > len - nread)
194               nbytes = (size_t) len - nread;
195             else
196               nbytes = DTMAS_MSGBUFSIZE - 1;
197
198             if (0 == (nbytes=SockRead(_msgbuf, 1, nbytes, _sockfp)))
199             {
200                 _logger.logError(
201                         DTM_FALSE,
202                         "Failed to retrieve %d bytes.",
203                         len);
204                 return DTME_MailServerAccess_SocketIOError;
205             }
206             _msgbuf[nbytes] = '\0';
207         }
208         else
209         {
210             if (NULL == SockGets(_msgbuf, DTMAS_MSGBUFSIZE, _sockfp))
211             {
212                 _logger.logError(DTM_FALSE, "Failed to retrieve %d bytes", len);
213                 return DTME_MailServerAccess_SocketIOError;
214             }
215             nbytes = strlen(_msgbuf);
216         }
217
218         nread += nbytes;
219
220         // Delete all carriage returns
221         for (s = t = _msgbuf; *s; s++)
222           if (*s != '\r') *t++ = *s;
223         *t = '\0';
224
225         if (_protologgingplus)
226           _logger.logError(
227                         DTM_FALSE,
228                         "INFO: read %d of %d octets %d remaining\n%s< %s\n",
229                         nbytes, len, len-nread, proto_name(), _msgbuf);
230
231         // Determine if we are done with this message.
232         if (proto_is_delimited())
233         {
234           char *s = const_cast<char *> (strrchr((const char *) _msgbuf, (int) '.'));
235             
236             if (s &&
237                 (s == _msgbuf || *(s-1) == '\n') &&
238                 (*s == '.') &&
239                 (*(s+1) == '\n'))
240             {
241                 *s = '\0';
242                 done = TRUE;
243             }
244         }
245         else if (nread >= len)
246           done = TRUE;
247     
248         if (0 < (nbytes = strlen(_msgbuf)))
249         {
250             if (! from_done && strncmp(_msgbuf, from, strlen(from)))
251             {
252                 time_t clock;
253                 char buffer[BUFSIZ];
254
255                 clock = time(&clock);
256                 sprintf(buffer, "%s %s %s",
257                         from, _servername, ctime((const time_t *) &clock));
258                 _append_mailbox_cb(
259                                 error, buffer, strlen(buffer),
260                                 _append_mailbox_cb_data);
261             }
262
263             from_done = TRUE;
264             _append_mailbox_cb(error, _msgbuf, nbytes, _append_mailbox_cb_data);
265         }
266
267         if (error.isSet())
268         {
269             error.logError(
270                         DTM_TRUE,
271                         "%s: Failed to append mailbox %s: %s.\n",
272                         pname, _folder, error.errnoMessage());
273             return DTME_AppendMailboxFile_Error;
274         }
275     }
276   
277     // Message separation.
278     _append_mailbox_cb(error, "\n", 1, _append_mailbox_cb_data);
279
280     // Sink the file pointer.
281     sigaction(SIGINT, (const struct sigaction *) &o_action, NULL);
282     return DTME_NoError;
283 }
284
285 //
286 // Assemble command in printf(3) style and send to the server.
287 //
288
289 DTMailError_t
290 DtMailServer::do_send(char *fmt, ... )
291 {
292     static char *pname = "DtMailServer::do_send";
293     char        *buf = new char[DTMAS_POPBUFSIZE+1];
294     int         nbytes;
295     va_list     ap;
296     DtMailEnv   error;
297
298     if (proto_is_tagged())
299     {
300         dtmasTAGGEN();
301         (void) sprintf(buf, "%s ", dtmasTAGGET());
302     }
303     else
304     {
305         dtmasTAGCLR();
306         buf[0] = '\0';
307     }
308
309     va_start(ap, fmt);
310     vsprintf(buf + strlen(buf), fmt, ap);
311     va_end(ap);
312
313     strcat(buf, "\r\n");
314     nbytes = SockWrite(buf, 1, strlen(buf), _sockfp);
315     if (nbytes != strlen(buf))
316     {
317         _logger.logError(DTM_FALSE, "Socket Error:  writing '%s'", buf);
318         delete [] buf;
319         return DTME_MailServerAccess_SocketIOError;
320     }
321
322     if (_protologging)
323     {
324         char *cp;
325         if (_shroud && (cp = strstr(buf, _shroud)))
326           memset(cp, '*', strlen(_shroud));
327         buf[strlen(buf)-1] = '\0';
328
329         _logger.logError(DTM_FALSE, "%s> %s", proto_name(), buf);
330     }
331     delete [] buf;
332     return DTME_NoError;
333 }
334
335 //
336 // Assemble command in printf(3) style, send to server, accept a response.
337 //
338 #if defined(__hpux)
339 #define DTMAS_COMMAND_TERMINATOR        "\n"
340 #else
341 #define DTMAS_COMMAND_TERMINATOR        "\r\n"
342 #endif
343 DTMailError_t
344 DtMailServer::do_transaction(char *fmt, ... )
345 {
346     static char         *pname = "DtMailServer::do_transaction";
347     DTMailError_t       ok;
348     char                *buf = new char[DTMAS_POPBUFSIZE+1];
349     int                 nbytes;
350     va_list             ap;
351
352     if (proto_is_tagged())
353     {
354         dtmasTAGGEN();
355         (void) sprintf(buf, "%s ", dtmasTAGGET());
356     }
357     else
358     {
359         dtmasTAGCLR();
360         buf[0] = '\0';
361     }
362
363     va_start(ap, fmt);
364     vsprintf(buf + strlen(buf), fmt, ap);
365     va_end(ap);
366
367     strcat(buf, DTMAS_COMMAND_TERMINATOR);
368     nbytes = SockWrite(buf, 1, strlen(buf), _sockfp);
369     if (nbytes != strlen(buf))
370     {
371         _logger.logError(DTM_FALSE, "Socket Error:  writing '%s'", buf);
372         delete [] buf;
373         return DTME_MailServerAccess_SocketIOError;
374     }
375
376     if (_protologging)
377     {
378         char *cp;
379         if (_shroud && (cp = strstr(buf, _shroud)))
380           memset(cp, '*', strlen(_shroud));
381         buf[strlen(buf)-1] = '\0';
382
383         _logger.logError(DTM_FALSE, "%s> %s", proto_name(), buf);
384     }
385
386     /* we presume this does its own response echoing */
387     ok = ptrans_parse_response(buf);
388     if (ok != DTME_NoError)
389     {
390       if (NULL == _errorstring)
391         _errorstring = strdup(buf);
392     }
393     delete [] buf;
394     return ok;
395 }
396
397 //
398 // Get the specified mailrc value interpreted as an integer
399 //
400 int
401 DtMailServer::get_mailrc_value(
402                         DtMail::Session *ssn,
403                         char *pfx,
404                         char *id,
405                         int dflt)
406 {
407     char        *string = NULL;
408     int         value = 0;
409
410     string = get_mailrc_value(ssn, pfx, id, (char*) NULL);
411     if (NULL == string)
412       return dflt;
413
414     value = atoi(string);
415     return value;
416 }
417
418 //
419 // Get the specified mailrc value interpreted as an string
420 //
421 char *
422 DtMailServer::get_mailrc_value(
423                         DtMail::Session *ssn,
424                         char *pfx,
425                         char *id,
426                         char *dflt,
427                         DtMailBoolean decrypt)
428 {
429     DtMailEnv           error;
430     DtMail::MailRc      *mailrc = ssn->mailRc(error);
431     const char          *value = NULL;
432     static char         idbuf[DTMAS_IDSIZE+1];
433     char                *charval = NULL;
434
435     DTMAS_CONCAT_MAILRC_KEY(idbuf, pfx, id);
436     mailrc->getValue(error, idbuf, &value, decrypt);
437     if (error.isSet())
438     {
439         if (NULL != dflt)
440           charval = strdup(dflt);
441     }
442     else
443       charval = strdup(value);
444
445     if (NULL != value) free((void*) value);
446     return charval;
447 }
448
449 //
450 // Get the specified mailrc value interpreted as an string
451 //
452 Boolean
453 DtMailServer::get_mailrc_value(
454                         DtMail::Session *ssn,
455                         char *pfx,
456                         char *id,
457                         Boolean dflt)
458 {
459     DtMailEnv           error;
460     DtMail::MailRc      *mailrc = ssn->mailRc(error);
461     const char          *value = NULL;
462     static char         idbuf[DTMAS_IDSIZE+1];
463     Boolean             boolval = FALSE;
464
465     DTMAS_CONCAT_MAILRC_KEY(idbuf, pfx, id);
466     mailrc->getValue(error, idbuf, &value);
467     if (error.isSet())
468       boolval = dflt;
469     else
470       boolval = TRUE;
471
472     if (NULL != value) free((void*) value);
473     return boolval;
474 }
475
476 //
477 // Returns TRUE if the folder being accessed is the inbox.
478 //
479 Boolean
480 DtMailServer::is_inbox()
481 {
482     if (NULL==_folder || 0==strncmp(_folder, DTMAS_INBOX, strlen(DTMAS_INBOX)))
483       return TRUE;
484     
485     return FALSE;
486 }
487
488 //
489 // Send message to the front end for display in the status line.
490 //
491 void
492 DtMailServer::send_info_message(DtMailCallbackOp op)
493 {
494     const char *errmsg = (const char *) _info;
495
496 #if defined(SEPARATE_FRONT_AND_BACK_END)
497     DtMailEnv error;
498     DtMailEventPacket event;
499
500     event.key = _mailbox->getObjectKey();
501     event.target = DTM_TARGET_MAILBOX;
502     event.target_object = _mailbox;
503     event.operation = (void*) op;
504     if (NULL != errmsg)
505       event.argument = strdup(errmsg);
506     else
507       event.argument = NULL;
508     event.event_time = time(NULL);
509
510     _session->writeEventData(error, &event, sizeof(event));
511 #else
512     _mailbox->callCallback(op, strdup(errmsg));
513 #endif
514 }
515
516 //
517 // Retrieve messages from server using given protocol method table
518 //
519 void
520 DtMailServer::retrieve_messages(DtMailEnv &error)
521 {
522     DTMailError_t       ok = DTME_NoError;
523     int                 js;
524     struct sigaction    action, o_action;
525     int                 *msgsizes = (int*) NULL;
526     int                 *msgisold = (int*) NULL;
527
528     _transnum = 0;
529
530     /* set up the server-nonresponse timeout */
531     memset((char*) &action, 0, sizeof(struct sigaction));
532     memset((char*) &o_action, 0, sizeof(struct sigaction));
533     action.sa_handler = (SA_HANDLER_TYPE) vtalarm_handler;
534
535     sigaction(SIGNAL_TYPE, (const struct sigaction *) &action, &o_action);
536
537     if ((js = setjmp(restart)) == 1)
538     {
539         _logger.logError(
540                 DTM_TRUE,
541                 "Timeout after %d seconds waiting for %s.\n",
542                 _timeout, _servername);
543         ok = DTME_MailServerAccess_Error;
544     }
545     else if (js == 2)
546     {
547         /* error message printed at point of longjmp */
548         ok = DTME_MailServerAccess_Error;
549     }
550     else
551     {
552         char    buf[DTMAS_POPBUFSIZE+1];
553         int     len, num, count, numnew;
554         int     deletions = 0;
555         int     sockfd = -1;
556
557         if (proto_requires_password() && NULL == _password)
558         {
559             ok = DTME_MailServerAccess_MissingPassword;
560             goto restoreSignal;
561         }
562
563         vtalarm_setitimer(_timeout);
564         _info.vSetError(DTME_MailServerAccessInfo_SocketOpen,
565                         DTM_FALSE, NULL, _username, _servername);
566         send_info_message(DTMC_SERVERACCESSINFO);
567         if (NULL != _errorstring)
568         {
569             free(_errorstring);
570             _errorstring = NULL;
571         }
572         _sockfp = SockOpen(_servername, proto_port(), &_errorstring);
573         if (NULL == _sockfp)
574         {
575             if (NULL == _errorstring)
576               _errorstring = strdup(_logger.errnoMessage());
577             ok = DTME_MailServerAccess_SocketIOError;
578             goto restoreSignal;
579         }
580         else if (_protologging)
581         {
582             _logger.logError(DTM_FALSE, "%s> %s", proto_name(), "SockOpen");
583         }
584
585         /* accept greeting message from mail server */
586         vtalarm_setitimer(_timeout);
587         ok = ptrans_parse_response(buf);
588         if (ok != DTME_NoError) goto closeServer;
589
590         /* try to get authorized to fetch mail */
591         vtalarm_setitimer(_timeout);
592         _shroud = _password;
593         ok = ptrans_authorize(buf);
594         _shroud = (char*) NULL;
595         if (ok != DTME_NoError) goto closeServer;
596
597         /* compute number of messages and number of new messages waiting */
598         vtalarm_setitimer(_timeout);
599         ok = ptrans_fldstate_read(&count, &numnew);
600         if (ok != DTME_NoError) goto closeServer;
601
602         /* show user how many messages we downloaded */
603         if (_protologging)
604         {
605             if (count == 0)
606               _logger.logError(
607                                 DTM_FALSE,
608                                 "INFO: No mail from %s@%s",
609                                 _username, _servername);
610             else
611             {
612                 if (numnew != -1 && (count - numnew) > 0)
613                   _logger.logError(
614                                 DTM_FALSE,
615                                 "INFO: %d message%s (%d seen) from %s@%s.",
616                                 count, count > 1 ? "s" : "", count-numnew,
617                                 _username, _servername);
618                 else
619                     _logger.logError(
620                                 DTM_FALSE,
621                                 "INFO: %d message%s from %s@%s.",
622                                 count, count > 1 ? "s" : "",
623                                 _username, _servername);
624             }
625         }
626
627         if (count > 0)
628         {
629             int nmsgtofetch = 0;
630             int fetched = 0;
631
632             /* we may need to get sizes in order to check message limits */
633             if (_sizelimit)
634             {
635                 msgsizes = (int *)malloc(sizeof(int) * count);
636
637                 vtalarm_setitimer(_timeout);
638                 ok = ptrans_msgsizes(count, msgsizes);
639                 if (ok != DTME_NoError) goto closeServer;
640             }
641
642             if (! _retrieveold)
643             {
644                 msgisold = (int*) malloc(sizeof(int) * count);
645
646                 for (num = 1; num <= count; num++)
647                 {
648                     vtalarm_setitimer(_timeout);
649                     msgisold[num-1] = ptrans_msgisold(num);
650                 }
651             }
652
653             for (num = 1; num <= count; num++)
654             {
655                 int toolarge =  msgsizes && (msgsizes[num-1] > _sizelimit);
656                 int ignoreold = msgisold && msgisold[num-1];
657
658                 if (! (toolarge || ignoreold)) nmsgtofetch++;
659             }
660
661             if (! nmsgtofetch)
662             {
663                 _info.vSetError(DTME_MailServerAccessInfo_NoMessages,
664                                 DTM_FALSE, NULL, _username, _servername);
665                 send_info_message(DTMC_SERVERACCESSINFO);
666             }
667
668             /*
669              * In IMAP4 you can retrieve a message without marking it as
670              * having been seen while in POP3 and IMAP2BIS this is NOT
671              * possible.  The proto_is_peek_capable encapsulates this
672              * capability.
673              *
674              * The problem is when there is any kind of transient error
675              * (DNS lookup failure, or sendmail refusing delivery due to
676              * process-table limits) during retrieval, the message will
677              * be marked "seen" on the server without having been retrieved
678              * by dtmail.
679              *
680              * We need to keep track of any errors which take place in a
681              * given retrieval pass (_retrieveerrors).  If there were any
682              * errors during the previous pass, all messages which were new
683              * at that time will be delivered.
684              */
685
686             /* read, forward, and delete messages */
687             _retrieveerrors = 0;
688             for (num = 1, fetched = 0; nmsgtofetch && num <= count; num++)
689             {
690                 int     toolarge =  msgsizes && (msgsizes[num-1] > _sizelimit);
691                 int     ignoreold = msgisold && msgisold[num-1];
692
693                 /*
694                  * We may want to reject this message if it is
695                  * too large or old
696                  */
697                 if (toolarge || ignoreold)
698                 {
699                     if (_protologging)
700                     {
701                         _logger.logError(DTM_FALSE,"skipping message %d",num);
702                         if (toolarge)
703                           _logger.logError(
704                                         DTM_FALSE,
705                                         " (oversized, %d bytes)",
706                                         msgsizes[num-1]);
707                     }
708                     if (toolarge)
709                     {
710                         _info.vSetError(
711                                 DTME_MailServerAccessInfo_MessageTooLarge,
712                                 DTM_FALSE, NULL, msgsizes[num-1]);
713                         send_info_message(DTMC_SERVERACCESSINFOERROR);
714                     }
715                 }
716                 else
717                 {
718                     vtalarm_setitimer(_timeout);
719
720                     /*
721                      * Fetch a message from the server.
722                      */
723                     fetched++;
724                     _info.vSetError(DTME_MailServerAccessInfo_RetrievingMessage,
725                                     DTM_FALSE, NULL,
726                                     fetched, nmsgtofetch,
727                                     _username, _servername);
728                     send_info_message(DTMC_SERVERACCESSINFO);
729
730                     ok = ptrans_retrieve_start(num, &len);
731                     if (ok != DTME_NoError)
732                     {
733                         _retrieveerrors++;
734                         goto closeServer;
735                     }
736
737                     if (_protologging)
738                       _logger.logError(
739                                         DTM_FALSE,
740                                         "INFO: reading message %d (%d bytes)",
741                                         num, len);
742
743                     /* Read the message and append it to the mailbox. */
744                     vtalarm_setitimer(_timeout);
745                     ok = ptrans_retrieve_readandappend(error, len);
746                     if (ok != DTME_NoError)
747                     {
748                         _retrieveerrors++;
749                         goto closeServer;
750                     }
751
752                     /* Tell the server we got it OK and resynchronize. */
753                     vtalarm_setitimer(_timeout);
754                     ok = ptrans_retrieve_end(num);
755                     if (ok != DTME_NoError)
756                     {
757                         _retrieveerrors++;
758                         goto closeServer;
759                     }
760
761                     /* Mark the message seen and remove it from the server. */
762                     if (_removeafterdelivery)
763                     {
764                         deletions++;
765                         if (_protologging) 
766                           _logger.logError(DTM_FALSE, " deleted\n");
767                         vtalarm_setitimer(_timeout);
768                         ok = ptrans_delete(num);
769                         if (ok != DTME_NoError) goto closeServer;
770                     }
771                     else if (_protologging) 
772                       _logger.logError(DTM_FALSE, " not deleted\n");
773                 }
774             }
775
776             /* Remove all messages flagged for deletion. */
777             if (deletions > 0)
778             {
779                 vtalarm_setitimer(_timeout);
780                 ok = ptrans_fldstate_expunge();
781                 if (ok != DTME_NoError) goto closeServer;
782             }
783         }
784         else
785         {
786             _info.vSetError(DTME_MailServerAccessInfo_NoMessages,
787                             DTM_FALSE, NULL, _username, _servername);
788             send_info_message(DTMC_SERVERACCESSINFO);
789         }
790
791     closeServer:
792         vtalarm_setitimer(_timeout);
793         if (ok != DTME_MailServerAccess_SocketIOError)
794           if (ok == DTME_NoError)
795             ok = ptrans_quit();
796           else
797             (void) ptrans_quit();
798         vtalarm_setitimer(0);
799         SockClose(_sockfp);
800         _sockfp = NULL;
801         dtmasTAGCLR();
802     }
803
804 restoreSignal:
805     _sockfp = NULL;
806     if (ok != DTME_NoError)
807     {
808         if (NULL == _errorstring)
809           _errorstring = strdup("");
810         error.vSetError(
811                         ok, DTM_TRUE, NULL,
812                         _username, _servername, proto_name(), _errorstring);
813         _logger.logError(
814                         DTM_TRUE,
815                         "Error while fetching from '%s':  \n%s\n",
816                         _servername, (const char*) error);
817
818     }
819     else
820       error.clear();
821
822     if (_errorstring)
823     {
824         free(_errorstring);
825         _errorstring = NULL;
826     }
827     if (msgsizes != NULL) free(msgsizes);
828     if (msgisold != NULL) free(msgisold);
829     sigaction(SIGNAL_TYPE, (const struct sigaction *) &o_action, NULL);
830 }
831
832 //
833 // Reset the nonresponse-timeout
834 //
835 #if defined(__hpux)
836 #define TV_USEC_TYPE    long
837 #else
838 #define TV_USEC_TYPE    int
839 #endif
840 void
841 DtMailServer::vtalarm_setitimer(int timeout_seconds)
842 {
843     struct itimerval ntimeout;
844
845     ntimeout.it_interval.tv_sec = (time_t) 0;
846     ntimeout.it_interval.tv_usec = (TV_USEC_TYPE) 0;
847     ntimeout.it_value.tv_sec  = (time_t) timeout_seconds;
848     ntimeout.it_value.tv_usec = (TV_USEC_TYPE) 0;
849     setitimer(ITIMER_TYPE, &ntimeout, (struct itimerval*) NULL);
850 }
851
852 //
853 // Handle server-timeout ALARM signal
854 //
855 void
856 DtMailServer::vtalarm_handler(int)
857 {
858     longjmp(restart, 1);
859 }