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 Wed Jul 28 23:57:49 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003