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