kpilot Library API Documentation

popmail-conduit.cc

00001 /* popmail-conduit.cc           KPilot
00002 **
00003 ** Copyright (C) 1998-2001 Dan Pilone
00004 ** Copyright (C) 1999,2000 Michael Kropfberger
00005 **
00006 ** This file is part of the popmail conduit, a conduit for KPilot that
00007 ** synchronises the Pilot's email application with the outside world,
00008 ** which currently means:
00009 **  -- sendmail or SMTP for outgoing mail
00010 **  -- POP or mbox for incoming mail
00011 */
00012 
00013 /*
00014 ** This program is free software; you can redistribute it and/or modify
00015 ** it under the terms of the GNU General Public License as published by
00016 ** the Free Software Foundation; either version 2 of the License, or
00017 ** (at your option) any later version.
00018 **
00019 ** This program is distributed in the hope that it will be useful,
00020 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00022 ** GNU General Public License for more details.
00023 **
00024 ** You should have received a copy of the GNU General Public License
00025 ** along with this program in a file called COPYING; if not, write to
00026 ** the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00027 ** MA 02111-1307, USA.
00028 */
00029 
00030 /*
00031 ** Bug reports and questions can be sent to kde-pim@kde.org
00032 */
00033 
00034 static const char *popmail_conduit_id=
00035     "$Id: popmail-conduit.cc,v 1.61 2003/12/30 10:28:58 adridg Exp $";
00036 
00037 #include "options.h"
00038 
00039 #include <qsocket.h>
00040 #include <qregexp.h>
00041 
00042 
00043 #include <sys/types.h>
00044 #include <sys/socket.h>
00045 #include <sys/utsname.h>
00046 #include <ctype.h>
00047 
00048 #include <unistd.h>
00049 #include <errno.h>
00050 
00051 #include <time.h>  // Needed by pilot-link include
00052 #include <pi-version.h>
00053 #if PILOT_LINK_MAJOR < 10
00054 #include <pi-config.h>
00055 #endif
00056 #include <pi-mail.h>
00057 
00058 #include <qdir.h>
00059 #include <qtextstream.h>
00060 #include <qtextcodec.h>
00061 
00062 #include <kapplication.h>
00063 #include <kmessagebox.h>
00064 #include <ksock.h>
00065 #include <kconfig.h>
00066 #include <ksimpleconfig.h>
00067 #include <dcopclient.h>
00068 #include <ktempfile.h>
00069 
00070 #include "pilotAppCategory.h"
00071 #include "pilotSerialDatabase.h"
00072 
00073 #include "passworddialog.h"
00074 #include "popmail-factory.h"
00075 #include "popmail-conduit.h"
00076 
00077 
00078 extern "C" {
00079 extern time_t parsedate(char * p);
00080 }
00081 
00082 
00083 // Just a convienience function [that doesn't
00084 // belong in the class interface]
00085 //
00086 //
00087 void showMessage(const QString &message)
00088 {
00089     KMessageBox::error(0L, message, i18n("Error retrieving mail"));
00090 }
00091 
00092 
00093 // Errors returned from getXXResponse()
00094 // and interpreted by showResponse():
00095 //
00096 //
00097 #define TIMEOUT (-2)
00098 #define PERROR  (-3)
00099 
00100 #define BADPOP  (-333)
00101 
00102 // This is a convenience function, that displays
00103 // a message with either
00104 //
00105 //  * an error text describing the error if ret < 0,
00106 //    errors as described by getXXXResponse
00107 //  * an error text with the contents of the buffer,
00108 //    if ret>=0
00109 //
00110 // Since we're printing an error message, we're
00111 // going to use someone else's fname, since the error
00112 // doesn't come from us.
00113 //
00114 //
00115 void showResponseResult(int const ret,
00116     const char *message,
00117     const char *buffer,
00118     const char *func)
00119 {
00120     QString msg(i18n(message));
00121 
00122     if (ret==TIMEOUT)
00123     {
00124         msg.append(i18n(" (Timed out)"));
00125 #ifdef DEBUG
00126         DEBUGCONDUIT << func
00127             << ": " << message
00128             << endl;
00129 #endif
00130     }
00131     if (ret==PERROR)
00132     {
00133         kdWarning() << func
00134             << ": " << message
00135             << perror
00136             << endl ;
00137     }
00138 
00139     if (ret>=0)
00140     {
00141 #ifdef DEBUG
00142         DEBUGCONDUIT << func
00143             << ": " << message
00144             << endl;
00145 #endif
00146 
00147         // Only add the buffer contents if they're interesting
00148         //
00149         //
00150         if (buffer && buffer[0])
00151         {
00152             msg.append(CSL1("\n"));
00153             msg.append(QString::fromLocal8Bit(buffer));
00154 #ifdef DEBUG
00155             DEBUGCONDUIT << func
00156                 << ": " << buffer
00157                 << endl;
00158 #endif
00159         }
00160     }
00161 
00162 
00163     showMessage(msg);
00164 }
00165 
00166 // This function waits for a response from a socket
00167 // (with some kind of busy waiting :( ) and returns:
00168 //
00169 //  >=0 The number of bytes read
00170 //  -2  If the response times out (currently
00171 //      unimplemented)
00172 //
00173 //
00174 static int getResponse(KSocket *s,char *buffer,const int bufsiz)
00175 {
00176     FUNCTIONSETUP;
00177     int ret;
00178 
00179     // We read one byte less than the buffer
00180     // size, to account for the fact that we're
00181     // going to add a 0 byte to the end.
00182     //
00183     //
00184     do
00185     {
00186         ret=read(s->socket(), buffer, bufsiz-1);
00187     }
00188     while ((ret==-1) && (errno==EAGAIN));
00189 
00190     buffer[ret]=0;
00191 
00192     return ret;
00193 }
00194 
00195 // This function waits for a response from the
00196 // POP3 server and then returns. It returns
00197 //
00198 //  BADPOP  If the response doesn't begin(*) with a +
00199 //      (indicating OK in POP3)
00200 //      >=0 If the response begins with a +, the number
00201 //      returned indicates the offset of the + in
00202 //      the buffer.
00203 //  TIMEOUT If the POP3 server times out (currently
00204 //      not implemented)
00205 //
00206 //
00207 static int getPOPResponse(KSocket *s,const char *message,
00208     char *buffer,const int bufsiz)
00209 {
00210     FUNCTIONSETUP;
00211     int i,ret;
00212 
00213     ret=getResponse(s,buffer,bufsiz);
00214 
00215     if (ret==TIMEOUT)
00216     {
00217         showResponseResult(ret,message,buffer,"getPOPResponse");
00218         return TIMEOUT;
00219     }
00220 
00221     // Skip any leading whitespace the POP3
00222     // server may print before the banner.
00223     //
00224     i=0;
00225     while(i<ret && isspace(buffer[i]) && i<bufsiz)
00226     {
00227         i++;
00228     }
00229 
00230     // If the POP3 server gives us a buffer full of
00231     // whitespace this test will fail as well.
00232     // Is that really bad?
00233     //
00234     //
00235     if(buffer[i] != '+')
00236     {
00237         showResponseResult(ret,message,buffer+i,"getPOPResponse");
00238         return BADPOP;
00239     }
00240 
00241     return i;
00242 }
00243 
00244 
00245 static void disconnectPOP(KSocket *s)
00246 {
00247     FUNCTIONSETUP;
00248 
00249     // This buffer is kinda small, but because
00250     // the POP server's response isn't important
00251     // *anyway*...
00252     //
00253     char buffer[12];
00254     const char *quitmsg="QUIT\r\n";
00255     write(s->socket(),quitmsg,strlen(quitmsg));
00256     getPOPResponse(s,"QUIT command to POP server failed",buffer,12);
00257 }
00258 
00259 
00260 
00261 void reset_Mail(struct Mail *t)
00262 {
00263       t->to = 0;
00264       t->from = 0;
00265       t->cc = 0;
00266       t->bcc = 0;
00267       t->subject = 0;
00268       t->replyTo = 0;
00269       t->sentTo = 0;
00270       t->body = 0;
00271       t->dated = 0;
00272 }
00273 
00274 PopMailConduit::PopMailConduit(KPilotDeviceLink *d,
00275     const char *n,
00276     const QStringList &l) :
00277     ConduitAction(d,n,l)
00278 {
00279     FUNCTIONSETUP;
00280 #ifdef DEBUG
00281     DEBUGCONDUIT<<popmail_conduit_id<<endl;
00282 #endif
00283     fConduitName=i18n("POP/Mail");
00284 }
00285 
00286 PopMailConduit::~PopMailConduit()
00287 {
00288     FUNCTIONSETUP;
00289 }
00290 
00291 void
00292 PopMailConduit::doSync()
00293 {
00294     FUNCTIONSETUP;
00295 
00296     int mode=0;
00297     int sent_count=0,received_count=0;
00298 
00299     addSyncLogEntry(CSL1("Mail "));
00300 
00301     mode=fConfig->readNumEntry(PopMailConduitFactory::syncOutgoing());
00302 #ifdef DEBUG
00303     DEBUGCONDUIT << fname
00304         << ": Outgoing mail mail disposition "
00305         << mode << endl;
00306 #endif
00307 
00308     if(mode)
00309     {
00310         sent_count=sendPendingMail(mode);
00311     }
00312 
00313     mode=fConfig->readNumEntry(PopMailConduitFactory::syncIncoming());
00314 #ifdef DEBUG
00315     DEBUGCONDUIT << fname << ": Sending mail mode " << mode << endl;
00316 #endif
00317 
00318     if(mode)
00319     {
00320         received_count=retrieveIncoming(mode);
00321     }
00322 
00323     // Internationalisation and Qt issues be here.
00324     // This is an attempt at making a nice log
00325     // message on the pilot, but it's obviously very
00326     // en locale-centric.
00327     //
00328     //
00329     if ((sent_count>0) || (received_count>0))
00330     {
00331         QString msg = CSL1("[ ");
00332         if (sent_count>0)
00333         {
00334             msg.append(i18n("Sent one message",
00335                 "Sent %n messages",sent_count));
00336             if (received_count>0)
00337             {
00338                 msg.append(CSL1(" ; "));
00339             }
00340         }
00341         if (received_count>0)
00342         {
00343             msg.append(i18n("Received one message",
00344                 "Received %n messages",received_count));
00345         }
00346         msg.append(CSL1(" ] "));
00347         addSyncLogEntry(msg);
00348     }
00349     addSyncLogEntry(CSL1("OK\n"));
00350 }
00351 
00352 
00353 // additional changes by Michael Kropfberger
00354 int PopMailConduit::sendPendingMail(int mode)
00355 {
00356     FUNCTIONSETUP;
00357     int count=-1;
00358 
00359 
00360     if (mode == PopMailConduit::SEND_SMTP)
00361     {
00362         count=sendViaSMTP();
00363     }
00364     if (mode==PopMailConduit::SEND_SENDMAIL)
00365     {
00366         count=sendViaSendmail();
00367     }
00368     if (mode==PopMailConduit::SEND_KMAIL)
00369     {
00370         count=sendViaKMail();
00371     }
00372 
00373     if (count < 0)
00374     {
00375         kdWarning() << k_funcinfo
00376             << ": Mail was not sent at all!"
00377             << endl;
00378         emit logError(TODO_I18N("[ No mail could be sent. ]"));
00379     }
00380     else
00381     {
00382 #ifdef DEBUG
00383         DEBUGCONDUIT << fname
00384             << ": Sent "
00385             << count
00386             << " messages"
00387             << endl;
00388 #endif
00389     }
00390 
00391     return count;
00392 }
00393 
00394 int PopMailConduit::retrieveIncoming(int mode)
00395 {
00396     FUNCTIONSETUP;
00397     int count=0;
00398 
00399     if (mode==RECV_POP)
00400     {
00401         count=doPopQuery();
00402     }
00403     if (mode==RECV_UNIX)
00404     {
00405         count=doUnixStyle();
00406     }
00407 
00408     return count;
00409 }
00410 
00411 
00412 
00414 //                                                                           //
00415 //    ---- |   | ----- ----  -----                                           //
00416 //   (     |\ /|   |   |   )   |        ___    _    ____  --            |    //
00417 //    ---  | V |   |   |---    |   |/\  ___| |/ \  (     |  )  __  |/\ -+-   //
00418 //       ) | | |   |   |       |   |   (   | |   |  \__  |--  /  \ |    |    //
00419 //   ___/  |   |   |   |       |   |    \__| |   | ____) |    \__/ |     \   //
00420 //                                                                           //
00422 //
00423 // SMTP Transfer Method (only sending)
00424 //
00425 // Additional changes by Michael Kropfberger
00426 // Cleanup and fixing by Marko Grnroos <magi@iki.fi>, 2001
00427 //
00428 
00429 // Helper function to get the Fully Qualified Domain Name
00430 QString getFQDomainName (const KConfig& config)
00431 {
00432     FUNCTIONSETUP;
00433 
00434     QString fqDomainName;
00435 
00436     // Has the user given an explicit domain name?
00437     int useExplicitDomainName = 0;
00438     if (!config.readEntry("explicitDomainName").isEmpty())
00439         useExplicitDomainName = 1;
00440 
00441     // Or was it given in the MAILDOMAIN environment variable?
00442     if (!useExplicitDomainName && getenv ("MAILDOMAIN"))
00443         useExplicitDomainName = 2;
00444 
00445 #ifdef DEBUG
00446     DEBUGCONDUIT << fname << ": EDN=" << config.readEntry("explicitDomainName") << endl;
00447     DEBUGCONDUIT << fname << ": useEDN=" << useExplicitDomainName << endl;
00448 #endif
00449 
00450     if (useExplicitDomainName > 0) {
00451         // User has provided the FQDN either in config or in environment.
00452 
00453         if (useExplicitDomainName == 2) {
00454             fqDomainName = "$MAILDOMAIN";
00455         } else {
00456             // Use explicitly configured FQDN.
00457             // The domain name can also be the name of an environment variable.
00458             fqDomainName = config.readEntry("explicitDomainName", CSL1("$MAILDOMAIN"));
00459 #ifdef DEBUG
00460             DEBUGCONDUIT << fname << ": got from config" << endl;
00461 #endif
00462         }
00463 
00464         // Get FQDN from environment, from given variable.
00465         if (fqDomainName.left(1) == CSL1("$")) {
00466             QString envVar = fqDomainName.mid (1);
00467             char* envDomain = getenv (envVar.latin1());
00468             if (envDomain) {
00469                 fqDomainName = envDomain;
00470 #ifdef DEBUG
00471                 DEBUGCONDUIT << fname << ": got from env" << endl;
00472 #endif
00473             } else {
00474                 // Ummh... It didn't exist, fall back to using system domain name
00475                 useExplicitDomainName = false;
00476 
00477 #ifdef DEBUG
00478                 DEBUGCONDUIT << fname << ": Promised domain name environment variable "
00479                              << fqDomainName << " wasn't available." << endl;
00480 #endif
00481             }
00482         }
00483     }
00484 
00485     if (useExplicitDomainName == 0) {
00486         // We trust in the system FQDN domain name
00487 
00488         struct utsname u;
00489         uname (&u);
00490         fqDomainName = u.nodename;
00491 
00492 #ifdef DEBUG
00493         DEBUGCONDUIT << fname
00494             << ": Got uname.nodename "
00495             << u.nodename << endl;
00496 #endif
00497     }
00498 
00499     return fqDomainName;
00500 }
00501 
00502 // Extracts email address from: "Firstname Lastname <mailbox@domain.tld>"
00503 QString extractAddress (const QString& address) {
00504     int pos = address.find (QRegExp (CSL1("<.+>")));
00505     if (pos != -1) {
00506         return address.mid (pos+1, address.find (CSL1(">"), pos)-pos-1);
00507     } else
00508         return address;
00509 }
00510 
00511 QString buildRFC822Headers (const QString& sender,
00512     const struct Mail& theMail,
00513     const PopMailConduit&)
00514 {
00515     FUNCTIONSETUP;
00516 
00517     QString buffer;
00518     QTextOStream bufs (&buffer);
00519 
00520     bufs << "From: " << sender << "\r\n";
00521     bufs << "To: " << theMail.to << "\r\n";
00522     if (theMail.cc)
00523         bufs << "Cc: " << theMail.cc << "\r\n";
00524     if (theMail.bcc)
00525         bufs << "Bcc: " << theMail.bcc << "\r\n";
00526     if (theMail.replyTo)
00527         bufs << "Reply-To: " << theMail.replyTo << "\r\n";
00528     if (theMail.subject)
00529         bufs << "Subject: " << theMail.subject << "\r\n";
00530     bufs << "X-mailer: " << "Popmail-Conduit " << KPILOT_VERSION << "\r\n\r\n";
00531 
00532     return buffer;
00533 }
00534 
00535 int sendSMTPCommand (KSocket& kSocket,
00536     const QString& sendBuffer,   // Buffer to send
00537     QTextOStream& logStream,     // For SMTP conversation logging
00538     const QString& logBuffer,    // Entire SMTP conversation log
00539     const QRegExp& expect,       // What do we expect as response (regexp)
00540     const QString& errormsg)     // Error message for error dialog
00541 {
00542     FUNCTIONSETUP;
00543 
00544     // Send
00545     logStream << ">>> " << sendBuffer;
00546     write (kSocket.socket(), sendBuffer.latin1(), sendBuffer.length());
00547 
00548     // Receive confirmation
00549     QByteArray response (1024);
00550     int ret;
00551     ret = getResponse (&kSocket, response.data(), response.size());
00552     logStream << "<<< " << (const char*) response;
00553 
00554     // Check if the confirmation was correct
00555     if (QString(response).find (expect) == -1) {
00556         QString msg;
00557         msg = errormsg +
00558             i18n("\n\nPOPMail conduit sent to SMTP server:\n") +
00559             sendBuffer +
00560             i18n("\nSMTP server responded with:\n") +
00561             QString(response);
00562 
00563         showMessage (msg);
00564 
00565         kdWarning() << k_funcinfo << ": SMTP error: " << msg << endl;
00566 #ifdef DEBUG
00567         DEBUGCONDUIT << fname << ": SMTP error: " << logBuffer << endl;
00568 #endif
00569 
00570         return -1;
00571     }
00572 
00573     return 0;
00574 }
00575 
00576 // Send
00577 int PopMailConduit::sendViaSMTP ()
00578 {
00579     FUNCTIONSETUP;
00580     QString         smtpSrv;                    // Hostname of the SMTP server
00581     int             smtpPort = 25;
00582     int             handledCount = 0;           // Number of messages handled
00583     int             current = 0;                // Current message
00584     PilotRecord*    pilotRec;                   // Message in Pilot format
00585     struct Mail     theMail;                    // Message in internal format
00586     QCString        currentDest, msg;
00587     QString         sendBuffer;                 // Output buffer
00588     int             ret;                        // Return value from socket functions
00589     QByteArray      recvBuffer (1024);          // Input buffer, size is always 1024 bytes
00590     QString         domainName;                 // The domain name of local host
00591     QString         logBuffer;                  // SMTP conversation log
00592     QTextOStream    logStream (&logBuffer);     // Log stream, use with: log << stuff;
00593 
00594     // Read user-defined parameters
00595     smtpSrv = fConfig->readEntry ("SMTPServer", CSL1("localhost"));
00596     smtpPort = fConfig->readNumEntry ("SMTPPort", 25);
00597 
00598     //
00599     // Determine "domain name"
00600     // (FQDN, Fully Qualified Domain Name, ie., hostname+domainname)
00601     //
00602 
00603     // If we are behind a masquerading firewall, we can't trust in our
00604     // host- and domainname or even the IP number, so we have to fake them.
00605     // Some systems also don't set the domainname properly.
00606 
00607     domainName = getFQDomainName (*fConfig);
00608 
00609 #ifdef DEBUG
00610     DEBUGCONDUIT << fname << ": " << domainName << endl;
00611 #endif
00612 
00613 
00614     //
00615     //     Create socket connection to SMTP server
00616     //
00617 
00618 #ifdef DEBUG
00619         DEBUGCONDUIT << fname << ": Connecting to SMTP server "
00620                   << smtpSrv << " on port " << smtpPort << endl;
00621 #endif
00622 
00623     //
00624     //     Connect to SMTP server
00625     //
00626 
00627     // We open the socket with KSocket, because it's blocking, which
00628     // is much easier for us.
00629     KSocket kSocket (smtpSrv.latin1(), smtpPort); // Socket to SMTP server
00630     if (kSocket.socket() < 0) {
00631         showMessage (i18n("Cannot connect to SMTP server"));
00632         return -1;
00633     }
00634     kSocket.enableRead (true);
00635     kSocket.enableWrite (true);
00636 
00637     //
00638     //     SMTP Handshaking
00639     //
00640 
00641     // all do-while loops wait until data is avail
00642     ret = getResponse (&kSocket, recvBuffer.data(), recvBuffer.size());
00643 
00644     // Receive server handshake initiation
00645     if (ret<0 || QString(recvBuffer).find(CSL1("220")) == -1) {
00646         showMessage (i18n("SMTP server failed to announce itself")+
00647                      CSL1("\n\n")+logBuffer);
00648         return -1;
00649     }
00650 
00651     // Send EHLO, expect "250- ... Hello"
00652     sendBuffer.sprintf ("EHLO %s\r\n", domainName.latin1());
00653     if (sendSMTPCommand (kSocket, sendBuffer, logStream, logBuffer,
00654                          QRegExp(CSL1("^250")),
00655                          i18n("Couldn't EHLO to SMTP server")))
00656         return -1;
00657 
00658     //
00659     //     Should probably read the prefs..
00660     //     But, let's just get the mail..
00661     //
00662 
00663     // Handle each message in queue
00664     for (current=0, handledCount=0; ; current++) {
00665 
00666         // Get the Pilot message record
00667         pilotRec = fDatabase->readNextRecInCategory (1);
00668         if (pilotRec == 0L)
00669             break;
00670 
00671         // Do not handle the message if it is deleted or archived
00672         if ((pilotRec->getAttrib() & dlpRecAttrDeleted)
00673            || (pilotRec->getAttrib() & dlpRecAttrArchived)) {
00674             delete pilotRec;
00675             continue; // Jumps to end of the for loop
00676         }
00677 
00678         // Ok, we shall send the message
00679         handledCount++;
00680 
00681         // Get the message data
00682         unpack_Mail (&theMail, (unsigned char*)pilotRec->getData(),
00683                      pilotRec->getLen());
00684         currentDest = "Mailing: ";
00685         currentDest += theMail.to;
00686 
00687         // Send "MAIL FROM: <...>", with the user-defined sender address
00688         QString sender = fConfig->readEntry("EmailAddress");
00689         QString fromAddress = extractAddress (sender);
00690         fromAddress.replace (QRegExp(CSL1("\\s")), QString::null); // Remove whitespaces
00691 
00692         // Send MAIL and receive response, expecting 250
00693         sendBuffer.sprintf ("MAIL FROM: <%s>\r\n", fromAddress.latin1());
00694         if (sendSMTPCommand (kSocket, sendBuffer, logStream, logBuffer,
00695                              QRegExp(CSL1("^250")),
00696                              i18n("Couldn't start sending new mail.")))
00697         {
00698             return handledCount;
00699         }
00700 
00701         //
00702         //     List recipients
00703         //
00704 
00705         // Get recipient(s) and clean up any whitespaces
00706         QCString recipients = theMail.to;
00707         if (QCString(theMail.cc).length()>1)
00708             recipients += QCString(",") + QCString (theMail.cc);
00709         if (QCString(theMail.bcc).length()>1)
00710             recipients += QCString(",") + QCString (theMail.bcc);
00711         recipients.replace (QRegExp(CSL1("\\s")), ""); // Remove whitespaces
00712 
00713         // Send to all recipients
00714         int rpos=0;
00715         int nextComma=0;
00716         for (rpos=0; rpos<int(recipients.length());) {
00717             QCString recipient;
00718 
00719             nextComma = recipients.find (',', rpos);
00720             if (nextComma > rpos) {
00721                 recipient = recipients.mid (rpos, nextComma-rpos);
00722                 rpos = nextComma+1;
00723             } else {
00724                 recipient = recipients.mid (rpos);
00725                 rpos = recipients.length(); // Will exit
00726             }
00727 
00728             // Send "RCPT TO: <...>", expect 25*
00729             sendBuffer.sprintf ("RCPT TO: <%s>\r\n", recipient.data());
00730             if (sendSMTPCommand (kSocket, sendBuffer, logStream, logBuffer,
00731                                  QRegExp(CSL1("^25")),
00732                                  i18n("The recipient doesn't exist!")))
00733                 return handledCount;
00734         }
00735 
00736         // Send "DATA",
00737         sendBuffer.sprintf("DATA\r\n");
00738         if (sendSMTPCommand (kSocket, sendBuffer, logStream, logBuffer,
00739                              QRegExp(CSL1("^354")),
00740                              i18n("Unable to start writing mail body\n")))
00741             return handledCount;
00742 
00743         // Send RFC822 mail headers
00744         sendBuffer = buildRFC822Headers (sender, theMail, *this);
00745         write (kSocket.socket(), sendBuffer.latin1(), sendBuffer.length());
00746 
00747         // Send message body
00748         if (theMail.body) {
00749             sendBuffer = QString::fromLatin1 (theMail.body)+CSL1("\r\n");
00750             write (kSocket.socket(), sendBuffer.latin1(), sendBuffer.length());
00751         }
00752 
00753         //insert the real signature file from disk
00754         if (!fConfig->readPathEntry ("Signature").isEmpty()) {
00755             QFile f (fConfig->readPathEntry ("Signature"));
00756             if ( f.open (IO_ReadOnly) ) {    // file opened successfully
00757                 sendBuffer.sprintf ("\r\n-- \r\n");
00758                 write (kSocket.socket(), sendBuffer.latin1(), sendBuffer.length());
00759 
00760                 // Read signature file with a text stream
00761                 QTextStream t ( &f );
00762                 while ( !t.eof() ) {        // until end of file...
00763                     sendBuffer.sprintf ("%s\r\n", t.readLine().latin1());
00764                     write (kSocket.socket(), sendBuffer.latin1(), sendBuffer.length());
00765                 }
00766                 f.close ();
00767             }
00768         }
00769 
00770         // Send end-of-mail
00771         sendBuffer.sprintf(".\r\n");
00772         if (sendSMTPCommand (kSocket, sendBuffer, logStream, logBuffer,
00773                              QRegExp(CSL1("^250")),
00774                              i18n("Unable to send message")))
00775             return -1;
00776 
00777         // Mark it as filed...
00778         pilotRec->setCat (3);
00779         pilotRec->setAttrib (pilotRec->getAttrib() & ~dlpRecAttrDirty);
00780         fDatabase->writeRecord (pilotRec);
00781         delete pilotRec;
00782 
00783         // This is ok since we got the mail with unpack mail..
00784         free_Mail (&theMail);
00785     }
00786 
00787     sendBuffer.sprintf("QUIT\r\n");
00788     sendSMTPCommand (kSocket, sendBuffer, logStream, logBuffer,
00789                      QRegExp(CSL1("^221")),
00790                      i18n("QUIT command to SMTP server failed.\n"));
00791 
00792     return handledCount;
00793 }
00794 
00795 
00796 
00798 //                   ----                 |             o |                  //
00799 //                  (      ___    _       |        ___    |                  //
00800 //                   ---  /   ) |/ \   ---| |/|/|  ___| | |                  //
00801 //                      ) |---  |   | (   | | | | (   | | |                  //
00802 //                  ___/   \__  |   |  ---| | | |  \__| | |                  //
00804 
00805 int PopMailConduit::sendViaSendmail()
00806 {
00807     FUNCTIONSETUP;
00808     int count=0;
00809 
00810   int i = 0;
00811   struct Mail theMail;
00812   QString sendmailCmd;
00813   QString currentDest;
00814   PilotRecord* pilotRec;
00815 
00816   sendmailCmd = fConfig->readPathEntry("SendmailCmd");
00817 
00818   // Should probably read the prefs..
00819   // But, let's just get the mail..
00820   for(i = 0;i<100; i++)
00821     {
00822       FILE* sendf; // for talking to sendmail
00823 
00824 #ifdef DEBUG
00825     {
00826         DEBUGCONDUIT << fname << ": Reading " << i << "th message" << endl;
00827     }
00828 #endif
00829       pilotRec = fDatabase->readNextRecInCategory(1);
00830     if(pilotRec == 0L)
00831     {
00832 #ifdef DEBUG
00833         DEBUGCONDUIT << fname << ": Got a NULL record from "
00834             "readNextRecord" << endl;
00835 #endif
00836         break;
00837     }
00838       if((pilotRec->getAttrib() & dlpRecAttrDeleted)
00839                || (pilotRec->getAttrib() & dlpRecAttrArchived))
00840     {
00841 #ifdef DEBUG
00842         {
00843             DEBUGCONDUIT << fname << ": Skipping deleted record." << endl;
00844         }
00845 #endif
00846         delete pilotRec;
00847     }
00848       else
00849     {
00850       unpack_Mail(&theMail, (unsigned char*)pilotRec->getData()
00851                       , pilotRec->getLen());
00852       sendf = popen(sendmailCmd.latin1(), "w");
00853       if(!sendf)
00854         {
00855           KMessageBox::error(0L, TODO_I18N("Cannot talk to sendmail!"),
00856                    TODO_I18N("Error Sending Mail"));
00857         kdWarning() << k_funcinfo
00858             << ": Could not start sendmail." << endl;
00859         kdWarning() << k_funcinfo << ": " << count
00860             << " messages sent OK"
00861             << endl ;
00862           return -1;
00863         }
00864       // TODO: Is currentDest used at all?
00865       currentDest = CSL1("Mailing: ");
00866       currentDest += PilotAppCategory::codec()->toUnicode(theMail.to);
00867       writeMessageToFile(sendf, theMail);
00868       pclose(sendf);
00869       // Mark it as filed...
00870       pilotRec->setCat(3);
00871       pilotRec->setAttrib(pilotRec->getAttrib() & ~dlpRecAttrDirty);
00872      fDatabase->writeRecord(pilotRec);
00873       delete pilotRec;
00874       // This is ok since we got the mail with unpack mail..
00875       free_Mail(&theMail);
00876         count++;
00877     }
00878     }
00879 //   free_MailAppInfo(&mailAppInfo);
00880 
00881 #ifdef DEBUG
00882     {
00883         DEBUGCONDUIT << fname << ": Sent " << count << " messages"
00884             << endl;
00885     }
00886 #endif
00887 
00888     return count;
00889 }
00890 
00891 
00892 
00893 
00894 QString PopMailConduit::getKMailOutbox() const
00895 {
00896     FUNCTIONSETUP;
00897     // Read-only config file. This is code
00898     // suggested by Don Sanders. It must be
00899     // kept up-to-date with what KMail does.
00900     //
00901     // TODO: Completely broken since KMail disposed of this
00902     // setting in KDE 3.0. No idea how to fix short of i18n("outbox").
00903     KSimpleConfig c(CSL1("kmailrc"),true);
00904     c.setGroup("General");
00905 
00906     QString outbox = c.readEntry("outboxFolder");
00907     if (outbox.isEmpty())
00908     {
00909         KConfigGroupSaver gs(fConfig,PopMailConduitFactory::group());
00910         outbox = fConfig->readEntry("outboxFolder");
00911     }
00912 
00913     if (outbox.isEmpty()) outbox=CSL1("outbox");
00914 
00915     return outbox;
00916 }
00917 
00918 /*
00919  * This function uses KMail's DCOP interface to put all the
00920  * outgoing mail into the outbox.
00921  */
00922 int PopMailConduit::sendViaKMail()
00923 {
00924     FUNCTIONSETUP;
00925     int count=0;
00926     bool sendImmediate = true;
00927     QString kmailOutboxName = getKMailOutbox();
00928 
00929     sendImmediate = fConfig->readBoolEntry("SendImmediate",true);
00930 
00931     DCOPClient *dcopptr = KApplication::kApplication()->
00932         dcopClient();
00933     if (!dcopptr)
00934     {
00935         kdWarning() << k_funcinfo
00936             << ": Can't get DCOP client."
00937             << endl;
00938         KMessageBox::error(0L,
00939             i18n("Couldn't connect to DCOP server for "
00940                 "the KMail connection."),
00941             i18n("Error Sending Mail"));
00942         return -1;
00943     }
00944 
00945     dcopptr->attach();
00946     while (PilotRecord *pilotRec = fDatabase->readNextRecInCategory(1))
00947     {
00948 #ifdef DEBUG
00949         DEBUGCONDUIT << fname
00950             << ": Reading "
00951             << count + 1
00952             << "th message"
00953             << endl;
00954 #endif
00955 
00956         if (pilotRec->isDeleted() || pilotRec->isArchived())
00957         {
00958 #ifdef DEBUG
00959             DEBUGCONDUIT << fname
00960                 << ": Skipping record."
00961                 << endl;
00962 #endif
00963             continue;
00964         }
00965 
00966         struct Mail theMail;
00967         KTempFile t;
00968         t.setAutoDelete(true);
00969 
00970         if (t.status())
00971         {
00972             kdWarning() << k_funcinfo
00973                 << ": Can't open temp file."
00974                 << endl;
00975             KMessageBox::error(0L,
00976                 i18n("Cannot open temporary file to store "
00977                     "mail from Pilot in."),
00978                 i18n("Error Sending Mail"));
00979             continue;
00980         }
00981 
00982         FILE *sendf = t.fstream();
00983 
00984         if (!sendf)
00985         {
00986             kdWarning() << k_funcinfo
00987                 << ": Can't open temporary file for writing!"
00988                 << endl;
00989             KMessageBox::error(0L,
00990                 i18n("Cannot open temporary file to store "
00991                     "mail from Pilot in."),
00992                 i18n("Error Sending Mail"));
00993             continue;
00994         }
00995 
00996         unpack_Mail(&theMail,
00997             (unsigned char*)pilotRec->getData(),
00998             pilotRec->getLen());
00999         writeMessageToFile(sendf, theMail);
01000 
01001 
01002         QByteArray data,returnValue;
01003         QCString returnType;
01004         QDataStream arg(data,IO_WriteOnly);
01005 
01006         arg << kmailOutboxName
01007             << t.name();
01008 
01009         if (!dcopptr->call("kmail",
01010             "KMailIface",
01011             "dcopAddMessage(QString,QString)",
01012             data,
01013             returnType,
01014             returnValue,
01015             true))
01016         {
01017             kdWarning() << k_funcinfo
01018                 << ": DCOP call failed."
01019                 << endl;
01020 
01021             KMessageBox::error(0L,
01022                 i18n("DCOP connection with KMail failed."),
01023                 i18n("Error Sending Mail"));
01024             continue;
01025         }
01026 
01027 #ifdef DEBUG
01028         DEBUGCONDUIT << fname
01029             << ": DCOP call returned "
01030             << returnType
01031             << " of "
01032             << (const char *)returnValue
01033             << endl;
01034 #endif
01035 
01036         // Mark it as filed...
01037         pilotRec->setCat(3);
01038         pilotRec->setAttrib(pilotRec->getAttrib() & ~dlpRecAttrDirty);
01039         fDatabase->writeRecord(pilotRec);
01040         delete pilotRec;
01041         // This is ok since we got the mail with unpack mail..
01042         free_Mail(&theMail);
01043 
01044         count++;
01045     }
01046 
01047     if ((count > 0)  && sendImmediate)
01048     {
01049         QByteArray data;
01050         if (dcopptr->send("kmail","KMailIface","sendQueued",data))
01051         {
01052             kdWarning() << k_funcinfo
01053                 << ": Couldn't flush queue."
01054                 << endl;
01055         }
01056     }
01057 
01058     return count;
01059 }
01060 
01061 // From pilot-link-0.8.7 by Kenneth Albanowski
01062 // additional changes by Michael Kropfberger
01063 
01064 void
01065 PopMailConduit::writeMessageToFile(FILE* sendf, struct Mail& theMail)
01066 {
01067     FUNCTIONSETUP;
01068 
01069   QTextStream mailPipe(sendf, IO_WriteOnly);
01070 
01071   QString fromAddress = fConfig->readEntry("EmailAddress");
01072   mailPipe << "From: " << fromAddress << "\r\n";
01073   mailPipe << "To: " << theMail.to << "\r\n";
01074   if(theMail.cc)
01075     mailPipe << "Cc: " << theMail.cc << "\r\n";
01076   if(theMail.bcc)
01077     mailPipe << "Bcc: " << theMail.bcc << "\r\n";
01078   if(theMail.replyTo)
01079     mailPipe << "Reply-To: " << theMail.replyTo << "\r\n";
01080   if(theMail.subject)
01081     mailPipe << "Subject: " << theMail.subject << "\r\n";
01082   mailPipe << "X-mailer: " << "Popmail-Conduit " << KPILOT_VERSION << "\r\n";
01083   mailPipe << "\r\n";
01084 
01085 
01086 #ifdef DEBUG
01087     {
01088         DEBUGCONDUIT << fname << ": To: " << theMail.to << endl;
01089     }
01090 #endif
01091 
01092 
01093     if(theMail.body)
01094     {
01095 #ifdef DEBUG
01096         {
01097             DEBUGCONDUIT << fname << ": Sent body." << endl;
01098         }
01099 #endif
01100         mailPipe << theMail.body << "\r\n";
01101     }
01102 
01103   //insert the real signature file from disk
01104   if(!fConfig->readPathEntry("Signature").isEmpty()) {
01105 #ifdef DEBUG
01106     {
01107         DEBUGCONDUIT << fname << ": Reading signature" << endl;
01108     }
01109 #endif
01110 
01111       QFile f(fConfig->readPathEntry("Signature"));
01112       if ( f.open(IO_ReadOnly) ) {    // file opened successfully
01113          mailPipe << "-- \r\n";
01114          QTextStream t( &f );        // use a text stream
01115          while ( !t.eof() ) {        // until end of file...
01116            mailPipe << t.readLine() << "\r\n";
01117          }
01118          f.close();
01119       }
01120    }
01121     mailPipe << "\r\n";
01122 
01123 #ifdef DEBUG
01124     {
01125         DEBUGCONDUIT << fname << ": Done" << endl;
01126     }
01127 #endif
01128 }
01129 
01130 /* static */ char*
01131 PopMailConduit::skipspace(char * c)
01132     {
01133     while (c && ((*c == ' ') || (*c == '\t')))
01134     c++;
01135     return c;
01136     }
01137 
01138 int
01139 PopMailConduit::getpopchar(int socket)
01140     {
01141     unsigned char buf;
01142     int ret;
01143     do
01144     {
01145       do
01146         ret=read(socket, &buf, 1);
01147       while ((ret==-1) && (errno==EAGAIN));
01148     if (ret < 0)
01149         return ret;
01150     } while ((ret==0) || (buf == '\r'));
01151 
01152     return buf;
01153     }
01154 
01155 int
01156 PopMailConduit::getpopstring(int socket, char * buf)
01157     {
01158     int c;
01159     while ((c = getpopchar(socket)) >= 0)
01160     {
01161     *buf++ = c;
01162     if (c == '\n')
01163         break;
01164     }
01165     *buf = '\0';
01166     return c;
01167     }
01168 
01169 int
01170 PopMailConduit::getpopresult(int socket, char * buf)
01171     {
01172     int c = getpopstring(socket, buf);
01173 
01174     if (c<0)
01175     return c;
01176 
01177     if (buf[0] == '+')
01178     return 0;
01179     else
01180     return 1;
01181     }
01182 
01183 /* static */ void
01184 PopMailConduit::header(struct Mail * m, char * t)
01185 {
01186     FUNCTIONSETUP;
01187 
01188     static char holding[4096];
01189 
01190     if (t && strlen(t) && t[strlen(t)-1] == '\n')
01191     t[strlen(t)-1] = 0;
01192     if (t && ((t[0] == ' ') || (t[0] == '\t')))
01193     {
01194     if ((strlen(t) + strlen(holding)) > 4096)
01195         return; /* Just discard approximate overflow */
01196     strcat(holding, t+1);
01197     return;
01198     }
01199 
01200     /* Decide on what we do with m->sendTo */
01201 
01202     if (strncmp(holding, "From:", 5)==0)
01203     {
01204     m->from = strdup(skipspace(holding+5));
01205     }
01206     else if (strncmp(holding, "To:",3)==0)
01207     {
01208     m->to = strdup(skipspace(holding+3));
01209     }
01210     else if (strncmp(holding, "Subject:",8)==0)
01211     {
01212     m->subject = strdup(skipspace(holding+8));
01213     }
01214     else if (strncmp(holding, "Cc:",3)==0)
01215     {
01216     m->cc = strdup(skipspace(holding+3));
01217     }
01218     else if (strncmp(holding, "Bcc:",4)==0)
01219     {
01220     m->bcc = strdup(skipspace(holding+4));
01221     }
01222     else if (strncmp(holding, "Reply-To:",9)==0)
01223     {
01224     m->replyTo = strdup(skipspace(holding+9));
01225     }
01226     else if (strncmp(holding, "Date:",4)==0)
01227     {
01228     time_t d = parsedate(skipspace(holding+5));
01229     if (d != -1)
01230         {
01231         struct tm * d2;
01232         m->dated = 1;
01233         d2 = localtime(&d);
01234         m->date = *d2;
01235         }
01236     }
01237     holding[0] = 0;
01238     if (t)
01239     strcpy(holding, t);
01240     }
01241 
01242 void PopMailConduit::retrievePOPMessages(KSocket *popSocket,int const msgcount,
01243     int const flags,
01244     char *buffer,int const bufsiz)
01245 {
01246     FUNCTIONSETUP;
01247     int i,ret;
01248 
01249     for(i=1;i<(msgcount+1);i++)
01250     {
01251         int len;
01252         char * msg;
01253         int h;
01254         struct Mail t;
01255         PilotRecord* pilotRec;
01256 
01257         reset_Mail(&t);
01258 
01259         //       pilotLink->updateProgressBar(i);
01260 
01261         sprintf(buffer, "LIST %d\r\n", i);
01262         write(popSocket->socket(), buffer, strlen(buffer));
01263         ret=getPOPResponse(popSocket,"LIST command failed",
01264             buffer,bufsiz);
01265         if (ret<0) return;
01266 
01267         sscanf(buffer+ret, "%*s %*d %d", &len);
01268 
01269 #ifdef DEBUG
01270         {
01271             DEBUGCONDUIT << fname
01272                 << ": Message " << i
01273                 << " is " << len << " bytes long"
01274                 << endl;
01275         }
01276 #endif
01277 
01278         if (len > 16000)
01279         {
01280             kdWarning() << k_funcinfo
01281                 << ": Skipped long message " << i
01282                 << endl;
01283             continue;
01284         }
01285 
01286         sprintf(buffer, "RETR %d\r\n", i);
01287         write(popSocket->socket(), buffer, strlen(buffer));
01288         ret = getpopstring(popSocket->socket(), buffer);
01289         if ((ret < 0) || (buffer[0] != '+'))
01290         {
01291             /* Weird */
01292             continue;
01293         }
01294         else
01295         {
01296             buffer[ret] = 0;
01297         }
01298 
01299         msg = (char*)buffer;
01300         h = 1;
01301         for(;;)
01302         {
01303             if (getpopstring(popSocket->socket(), msg) < 0)
01304             {
01305                 showMessage(i18n("Error reading message"));
01306                 return;
01307             }
01308 
01309             if (h == 1)
01310             {
01311                 /* Header mode */
01312                 if ((msg[0] == '.') &&
01313                     (msg[1] == '\n') && (msg[2] == 0))
01314                 {
01315                     break; /* End of message */
01316                 }
01317                 if (msg[0] == '\n')
01318                 {
01319                     h = 0;
01320                     header(&t, 0);
01321                 }
01322                 else
01323                 {
01324                     header(&t, msg);
01325                 }
01326                 continue;
01327             }
01328             if ((msg[0] == '.') &&
01329                 (msg[1] == '\n') && (msg[2] == 0))
01330             {
01331                 msg[0] = 0;
01332                 break; /* End of message */
01333             }
01334             if (msg[0] == '.')
01335             {
01336                 /* Must be escape */
01337                 memmove(msg, msg+1, strlen(msg));
01338             }
01339             msg += strlen(msg);
01340         }
01341 
01342         // Well, we've now got the message.
01343         // I bet _you_ feel happy with yourself.
01344 
01345         if (h)
01346         {
01347             /* Oops, incomplete message, still reading headers */
01348             //    showMessage("Incomplete message");
01349             // This is ok since we used strdup's for them all.
01350             free_Mail(&t);
01351             continue;
01352         }
01353 
01354         // Need to add this support...
01355         //  if (strlen(msg) > p.truncate)
01356         //      {
01357         //      /* We could truncate it, but we won't for now */
01358         //      fprintf(stderr, "Message %d too large (%ld bytes)\n", i, (long)strlen(msg));
01359         //      free_Mail(&t);
01360         //      continue;
01361         //      }
01362 
01363         t.body = strdup(buffer);
01364 
01365         len = pack_Mail(&t, (unsigned char*)buffer, 0xffff);
01366         pilotRec = new PilotRecord(buffer, len, 0, 0, 0);
01367         if (fDatabase->writeRecord(pilotRec) > 0)
01368         {
01369             if (flags & POP_DELE)
01370             {
01371                 sprintf(buffer, "DELE %d\r\n", i);
01372                 write(popSocket->socket(),
01373                     buffer, strlen(buffer));
01374                 getPOPResponse(popSocket,
01375                     "Error deleting message",
01376                     buffer,bufsiz);
01377 
01378             }
01379         }
01380         else
01381         {
01382             showMessage(
01383                 i18n("Error writing message to the Pilot."));
01384         }
01385 
01386         delete pilotRec;
01387         // This is ok since we used strdup's for them all..
01388         free_Mail(&t);
01389     }
01390 
01391 }
01392 
01393 
01394 
01395 int PopMailConduit::doPopQuery()
01396 {
01397     FUNCTIONSETUP;
01398 
01399     KSocket* popSocket;
01400     char buffer[0xffff];
01401     int offset;
01402     int flags=0;
01403     int msgcount;
01404 
01405 
01406     // Setup the flags to reflect the settings in
01407     // the config file.
01408     //
01409     //
01410     if (fConfig->readNumEntry("LeaveMail") == 0)
01411     {
01412         flags |= POP_DELE ;
01413     }
01414 
01415     popSocket = new KSocket(fConfig->readEntry("PopServer").latin1(),
01416         fConfig->readNumEntry("PopPort"));
01417     Q_CHECK_PTR(popSocket);
01418 
01419 #ifdef DEBUG
01420     {
01421         DEBUGCONDUIT << fname
01422             << ": Attempted to connect to POP3 server "
01423             << fConfig->readEntry("PopServer")
01424             << endl;
01425     }
01426 #endif
01427 
01428     if(popSocket->socket() < 0)
01429     {
01430         showResponseResult(PERROR,
01431             "Cannot connect to POP server -- no socket",
01432             0L,"doPopQuery");
01433         delete popSocket;
01434         return -1;
01435     }
01436 
01437 
01438 
01439     popSocket->enableRead(true);
01440     popSocket->enableWrite(true);
01441 
01442 #ifdef DEBUG
01443     {
01444         DEBUGCONDUIT << fname
01445             << ": Connected to POP3 server socket "
01446             << popSocket->socket()
01447             << endl ;
01448     }
01449 #endif
01450 
01451     // The following code is based _HEAVILY_ :)
01452     // on pilot-mail.c by Kenneth Albanowski
01453     // additional changes by Michael Kropfberger
01454     // all do-while loops wait until data is avail
01455 
01456     if (getPOPResponse(popSocket,"POP server failed to announce itself",
01457         buffer,1024)<0)
01458     {
01459         delete popSocket;
01460         return -1;
01461     }
01462 
01463 
01464     sprintf(buffer, "USER %s\r\n", fConfig->readEntry("PopUser").latin1());
01465     write(popSocket->socket(), buffer, strlen(buffer));
01466     if (getPOPResponse(popSocket,"USER command to POP server failed",
01467         buffer,1024)<0)
01468     {
01469         delete popSocket;
01470         return -1;
01471     }
01472 
01473     if(fConfig->readNumEntry("StorePass", 0))
01474     {
01475 #ifdef DEBUG
01476         {
01477             DEBUGCONDUIT << fname
01478                 << ": Reading password from config."
01479                 << endl;
01480         }
01481 #endif
01482 
01483         sprintf(buffer, "PASS %s\r\n",
01484             fConfig->readEntry("PopPass").latin1());
01485     }
01486     else
01487     {
01488         // Create a modal password dialog.
01489         //
01490         //
01491         PasswordDialog* passDialog = new PasswordDialog(
01492             i18n("Please enter your POP password:"),
01493             0L, "PopPassword", true);
01494         passDialog->show();
01495         if (passDialog->result()==QDialog::Accepted)
01496         {
01497             sprintf(buffer, "PASS %s\r\n", passDialog->password());
01498             delete passDialog;
01499         }
01500         else
01501         {
01502 #ifdef DEBUG
01503             DEBUGCONDUIT << fname
01504                 << ": Password dialog was canceled."
01505                 << endl;
01506 #endif
01507             delete passDialog;
01508             disconnectPOP(popSocket);
01509             delete popSocket;
01510             return -1;
01511         }
01512     }
01513 
01514 
01515 
01516     write(popSocket->socket(), buffer, strlen(buffer));
01517     if (getPOPResponse(popSocket,"PASS command to POP server failed",
01518         buffer,1024)<0)
01519     {
01520         disconnectPOP(popSocket);
01521         delete popSocket;
01522         return -1;
01523     }
01524 
01525 
01526     sprintf(buffer, "STAT\r\n");
01527     write(popSocket->socket(), buffer, strlen(buffer));
01528     if ((offset=getPOPResponse(popSocket,
01529         "STAT command to POP server failed",
01530         buffer,1024))<0)
01531     {
01532         disconnectPOP(popSocket);
01533         delete popSocket;
01534         return -1;
01535     }
01536 
01537     //sometimes looks like: "+OK ? messages (??? octets)
01538     //                  or: "+OK <user> has ? message (??? octets)
01539     //
01540     // [ The standard says otherwise ]
01541     //
01542     // Surely POP3 speaks latin1?
01543     QString msg(QString::fromLatin1(buffer+offset));
01544     if (msg.find( fConfig->readEntry("PopUser")) != -1) // with username
01545     {
01546         sscanf(buffer+offset, "%*s %*s %*s %d %*s", &msgcount);
01547     }
01548     else // normal version
01549     {
01550         sscanf(buffer+offset, "%*s %d %*s", &msgcount);
01551     }
01552 
01553 #ifdef DEBUG
01554     {
01555         DEBUGCONDUIT << fname
01556             << ": POP STAT is "
01557             << buffer+offset
01558             << endl;
01559         DEBUGCONDUIT << fname
01560             << ": Will retrieve "
01561             << msgcount << " messages."
01562             << endl;
01563     }
01564 #endif
01565 
01566     if(msgcount < 1)
01567     {
01568         // No messages, so bail early..
01569         disconnectPOP(popSocket);
01570         delete popSocket;
01571         return 0;
01572     }
01573 
01574 
01575 
01576     retrievePOPMessages(popSocket,msgcount,flags,buffer,1024);
01577 
01578     disconnectPOP(popSocket);
01579     delete popSocket;
01580 
01581     return msgcount;
01582 }
01583 
01584 
01585 
01586 /* static */ int PopMailConduit::skipBlanks(FILE *f,char *buffer,int buffersize)
01587 {
01588     FUNCTIONSETUP;
01589 
01590     char *s;
01591     int count=0;
01592 
01593     while (!feof(f))
01594     {
01595         if (fgets(buffer,buffersize,f)==0L) break;
01596 #ifdef DEBUG
01597         {
01598             DEBUGCONDUIT <<  fname << ": Got line " << buffer ;
01599         }
01600 #endif
01601 
01602         s=buffer;
01603         while (isspace(*s)) s++;
01604         if (*s) return count;
01605         //
01606         // Count lines skipped
01607         //
01608         count++;
01609     }
01610 
01611     //
01612     // EOF found, so erase buffer beginning.
01613     //
01614     *buffer=0;
01615     return count;
01616 }
01617 #define LINESIZE    (800)
01618 /* static */ int PopMailConduit::readHeaders(FILE *f,
01619     char *buf,int bufsiz,
01620     struct Mail *t,
01621     int expectFrom)
01622 {
01623     FUNCTIONSETUP;
01624 
01625     char line[LINESIZE];
01626     int count=0;
01627 
01628     // First line of a message should be a "^From "
01629     // line, but we'll accept some blank lines first
01630     // as well.
01631     //
01632     //
01633     if (expectFrom)
01634     {
01635 #ifdef DEBUG
01636         {
01637             DEBUGCONDUIT << fname << ": Looking for From line." << endl;
01638         }
01639 #endif
01640 
01641         skipBlanks(f,line,LINESIZE);
01642         if (strncmp(line,"From ",5))
01643         {
01644             kdWarning() << k_funcinfo
01645                 << ": No leading From line." << endl;
01646             return 0;
01647         }
01648 
01649 #ifdef DEBUG
01650         {
01651             DEBUGCONDUIT << fname << ": Found it." << endl;
01652         }
01653 #endif
01654     }
01655 
01656     while ((skipBlanks(f,line,LINESIZE)==0) && !feof(f))
01657     {
01658         if ((line[0]=='.') && (line[1]=='\n') && (line[2] == 0))
01659         {
01660 #ifdef DEBUG
01661             {
01662                 DEBUGCONDUIT << fname << ": Found end-of-headers "
01663                     "and end-of-message."
01664                     << endl;
01665             }
01666 #endif
01667             // End of message *and* end-of headers.
01668             return -count;
01669         }
01670 
01671         // This if-clause is actually subsumed by
01672         // skipBlanks, which returns > 0 if lines are
01673         // skipped because they are blank.
01674         //
01675         //
01676         if (line[0]=='\n')
01677         {
01678 #ifdef DEBUG
01679             {
01680                 DEBUGCONDUIT << fname << ": Found end-of-headers"
01681                     << endl;
01682             }
01683 #endif
01684             // End of headers
01685             header(t,0);
01686             return count;
01687         }
01688 
01689         header(t,line);
01690         count++;
01691     }
01692 
01693 #ifdef DEBUG
01694     {
01695         DEBUGCONDUIT << fname << ": Read " << count << " lines." << endl;
01696     }
01697 #endif
01698     strncpy(buf,line,bufsiz);
01699     return count;
01700 }
01701 
01702 
01703 /* static */ int PopMailConduit::readBody(FILE *f,char *buf,int bufsize)
01704 {
01705     FUNCTIONSETUP;
01706     int count=0;
01707     int linelen=0;
01708 
01709 #ifdef DEBUG
01710     {
01711         DEBUGCONDUIT << fname << ": Buffer @" << (int) buf << endl;
01712     }
01713 #endif
01714 
01715     while(!feof(f) && (bufsize > 80))
01716     {
01717         if (fgets(buf,bufsize,f)==0)
01718         {
01719             // End of file, implies end
01720             // of message.
01721             //
01722             //
01723             return count;
01724         }
01725 
01726 #ifdef DEBUG
01727         {
01728             DEBUGCONDUIT << fname << ": Got line ["
01729                 << (int) buf[0] << ',' << (int) buf[1]
01730                 << ']'
01731                 << buf;
01732         }
01733 #endif
01734 
01735         if ((buf[0]=='.') && ((buf[1]=='\n') || (buf[1]=='\r')))
01736         {
01737             // Explicit end of message
01738             //
01739             //
01740             return count;
01741         }
01742 
01743         count++;
01744         if (buf[0]=='.')
01745         {
01746             // Handle . escapes
01747             //
01748             //
01749             memmove(buf+1,buf,strlen(buf));
01750         }
01751 
01752 
01753         linelen=strlen(buf);
01754         buf+=linelen;
01755         bufsize-=linelen;
01756     }
01757 
01758     return count;
01759 }
01760 
01761 #undef LINESIZE
01762 
01763 /* static */ PilotRecord *PopMailConduit::readMessage(FILE *mailbox,
01764     char *buffer,int bufferSize)
01765 {
01766     FUNCTIONSETUP;
01767 
01768     struct Mail t;      // Just like in doPopQuery
01769     int messageLength=0;
01770     int len;
01771     PilotRecord* pilotRec=0L;
01772 
01773     reset_Mail(&t);
01774 
01775     // Don't forget: readHeaders returns the number of lines.
01776     //
01777     messageLength=readHeaders(mailbox,buffer,bufferSize,&t,1);
01778     if (messageLength == 0)
01779     {
01780         kdWarning() << k_funcinfo
01781             << ": Bad headers in message." << endl;
01782         return 0;
01783     }
01784 
01785 
01786     if (messageLength>0)
01787     {
01788         messageLength=strlen(buffer);
01789 #ifdef DEBUG
01790         {
01791             DEBUGCONDUIT << fname << ": Message so far:" << endl
01792                 << buffer << endl;
01793             DEBUGCONDUIT << fname << ": Length "
01794                 << messageLength << endl;
01795             DEBUGCONDUIT << fname << ": Buffer @" << (int) buffer
01796                 << endl;
01797         }
01798 #endif
01799 
01800         if (readBody(mailbox,
01801             buffer+messageLength,
01802             bufferSize-messageLength) < 0)
01803         {
01804             kdWarning() << k_funcinfo
01805                 << ": Bad body for message." << endl;
01806             return 0;
01807         }
01808     }
01809     else
01810     {
01811         // The message has already ended.
01812         // Nothing to do.
01813     }
01814 
01815     t.body = strdup(buffer);
01816 
01817     len = pack_Mail(&t, (unsigned char*)buffer, bufferSize);
01818     pilotRec = new PilotRecord(buffer, len, 0, 0, 0);
01819     free_Mail(&t);
01820 
01821     return pilotRec;
01822 }
01823 
01824 
01825 #define BUFFERSIZE  (12000)
01826 int PopMailConduit::doUnixStyle()
01827 {
01828     FUNCTIONSETUP;
01829     QString filename;
01830     FILE *mailbox;
01831     // A buffer to hold the body and headers
01832     // of each message. 12000 isn't very big, but
01833     // since the mail application truncates at
01834     // 8000 the buffer is way larger than
01835     // the largest possible message actually
01836     // passed to the pilot.
01837     //
01838     //
01839     char *buffer=new char[BUFFERSIZE];
01840     int messageCount=0;
01841 
01842     PilotRecord *pilotRec=0L;
01843 
01844     {
01845         filename=fConfig->readEntry("UNIX Mailbox");
01846         if (filename.isEmpty()) return 0;
01847 
01848 #ifdef DEBUG
01849         {
01850             DEBUGCONDUIT << fname << ": Trying to read mailbox "
01851                 << filename << endl;
01852         }
01853 #endif
01854 
01855         QFileInfo info(filename);
01856         if (!info.exists())
01857         {
01858             kdWarning() << k_funcinfo
01859                 << ": Mailbox doesn't exist."
01860                 << endl;
01861             return -1;
01862         }
01863 
01864 #ifdef DEBUG
01865         {
01866             DEBUGCONDUIT << fname << ": Mailbox found." << endl;
01867         }
01868 #endif
01869 
01870     }
01871 
01872     mailbox=fopen(filename.latin1(),"r");
01873     if (mailbox==0L)
01874     {
01875         kdWarning() << k_funcinfo << ": Can't open mailbox:"
01876             << perror
01877             << endl;
01878         return -1;
01879     }
01880 
01881     while (!feof(mailbox))
01882     {
01883         pilotRec=readMessage(mailbox,buffer,BUFFERSIZE);
01884         if  (pilotRec && fDatabase->writeRecord(pilotRec)>0)
01885         {
01886             messageCount++;
01887 #ifdef DEBUG
01888             {
01889                 DEBUGCONDUIT << fname << ": Read message "
01890                     << messageCount << " from mailbox."
01891                     << endl;
01892             }
01893 #endif
01894         }
01895         else
01896         {
01897             kdWarning() << k_funcinfo << ": Message "
01898                 << messageCount << " couldn't be written."
01899                 << endl;
01900             showMessage(i18n("Error writing mail message to Pilot"));
01901         }
01902         delete pilotRec;
01903     }
01904 
01905 #ifdef DEBUG
01906     {
01907         DEBUGCONDUIT << fname << ": Wrote "
01908             << messageCount
01909             << " messages to pilot."
01910             << endl;
01911     }
01912 #endif
01913 
01914     return messageCount;
01915 }
01916 #undef BUFFERSIZE
01917 
01918 /* virtual */ void PopMailConduit::doTest()
01919 {
01920     FUNCTIONSETUP;
01921 
01922 
01923     QString outbox = getKMailOutbox();
01924 
01925 #ifdef DEBUG
01926     DEBUGCONDUIT << fname
01927         << ": KMail's outbox is "
01928         << outbox
01929         << endl;
01930 #endif
01931 }
01932 
01933 /* virtual */ bool PopMailConduit::exec()
01934 {
01935     FUNCTIONSETUP;
01936     DEBUGCONDUIT<<popmail_conduit_id<<endl;
01937 
01938     if (!fConfig) return false;
01939 
01940     KConfigGroupSaver cfgs(fConfig,PopMailConduitFactory::group());
01941 
01942     fDatabase=new PilotSerialDatabase(pilotSocket(),
01943         CSL1("MailDB"),this,"MailDB");
01944 
01945     if (!fDatabase || !fDatabase->isDBOpen())
01946     {
01947         emit logError(i18n("Unable to open mail database on handheld"));
01948         KPILOT_DELETE(fDatabase);
01949         return false;
01950     }
01951 
01952     if (isTest())
01953     {
01954         doTest();
01955     }
01956     else if (isBackup())
01957     {
01958         emit logError(TODO_I18N("Cannot perform backup on mail database"));
01959     }
01960     else
01961     {
01962         doSync();
01963         fDatabase->resetSyncFlags();
01964     }
01965 
01966     KPILOT_DELETE(fDatabase);
01967     emit syncDone(this);
01968     return true;
01969 }
KDE Logo
This file is part of the documentation for kpilot Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:36:49 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003