pop3.cxx

Go to the documentation of this file.
00001 
00002 //
00003 // Copyright 2002, Lowell Boggs Jr.
00004 //
00005 // This file or directory, containing source code for a computer program,
00006 // is Copyrighted by Lowell Boggs, Jr.  987 Regency Drive, Lewisville
00007 // TX (USA), 75067.  You may use, copy, modify, and distribute this
00008 // source file without charge or obligation so long as you agree to
00009 // the following:
00010 //
00011 //  1.  You must indemnify Lowell Boggs against any and all financial
00012 //      obligations caused by its use, misuse, function, or malfunction.
00013 //      Further, you acknowledge that there is no warranty of any kind,
00014 //      whatsoever.
00015 //
00016 //  2.  You agree not to attempt to patent any portion of this original
00017 //      work -- though you may attempt to patent your own extensions to
00018 //      it if you so choose.
00019 //
00020 //  3.  You keep this copyright notice with the file and all copies
00021 //      of the file and do not change it anyway except language translation.
00022 //
00023 // You are responsible for enforcing your own compliance with these
00024 // conditions and may not use this source file if you cannot agree to the
00025 // above terms and conditions.
00026 //
00027 // Warning:  not all files in this directory structure are covered by the
00028 // same copyright.  Some of them are part of the GNU source distribution
00029 // and you must obey the GPL copyright for those files.
00030 
00031 
00032 #include <pop3.h>
00033 #include <libspopc.h>
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <cxxtls/strtool.h>
00037 #include <vector>
00038 
00039 using namespace cxxtls;
00040 
00041 typedef StrTool::stringlist_t  stringlist;
00042 
00043 
00044 struct POP3::Impl
00045 {
00046    popsession *session_;
00047    int         status_;
00048 
00049    std::vector<POP3::Message*> messages_;
00050    std::vector<POP3::User*>    users_;
00051 
00052    char const* fetch_messages();
00053 
00054 };
00055 
00056 POP3::
00057 POP3()
00058 : impl_( new Impl )
00059 {
00060   impl_->status_        = not_connected;
00061   impl_->session_       = 0;
00062 }
00063 
00064 POP3::
00065 ~POP3()
00066 {
00067   if(impl_->status_ == connected)
00068   {
00069     disconnect();
00070   }
00071 
00072   size_t i;
00073 
00074   for(i=0; i < impl_->messages_.size(); ++i)
00075     delete impl_->messages_[i];
00076 
00077   for(i=0; i < impl_->users_.size(); ++i)
00078     delete impl_->users_[i];
00079 
00080 
00081   delete impl_;
00082 }
00083 
00084 char const *
00085 POP3::
00086 connect( string server,
00087          string user,
00088          string password
00089        )
00090 {
00091   //
00092   //  Connect to the server and download all messages without deleting them
00093   //
00094 
00095   if(impl_->status_ == connected )
00096     return 0;
00097 
00098   char const *error = popbegin(server.c_str(),
00099                                user.c_str(),
00100                                password.c_str(),
00101                                &impl_->session_
00102                               );
00103 
00104   if(error)
00105     impl_->status_ = connect_failed;
00106   else
00107   {
00108     impl_->status_ = connected;
00109 
00110     error = impl_->fetch_messages();
00111 
00112   }
00113 
00114   return error;
00115 }
00116 
00117 void
00118 POP3::
00119 disconnect()
00120 {
00121   if(impl_->status_ == connected)
00122   {
00123     popend(impl_->session_);
00124   }
00125 
00126   impl_->status_ = not_connected;
00127 
00128 }
00129 
00130 size_t
00131 POP3::
00132 messages() const
00133 {
00134   return impl_->messages_.size();
00135 }
00136 
00137 int
00138 POP3::
00139 connect_status() const
00140 {
00141   return impl_->status_;
00142 }
00143 
00144 char const *
00145 POP3::message_header(size_t message_index, Header** h)
00146 {
00147 
00148   if(message_index > messages())
00149     return "No such message";
00150 
00151   *h = &impl_->messages_[message_index]->header_;
00152 
00153   return 0;
00154 }
00155 
00156 char const *
00157 POP3::message_body(size_t message_index, Body** b)
00158 {
00159 
00160   if(message_index > messages())
00161     return "No such message";
00162 
00163   *b = &impl_->messages_[message_index]->body_;
00164 
00165   return 0;
00166 }
00167 
00168 
00169 static void cleanse_lines(std::list<std::string> &strings, bool handle_continuations=true)
00170 {
00171   // remove trailing \r's and combine
00172   // lines beginning with tabs with their predecessors
00173 
00174   // Remove trailing \r's and concatenate lines beginning with tab to
00175   // their immediate predecessor -- unless told not to.
00176 
00177   {
00178     int line_count=0;
00179 
00180     stringlist::iterator first = strings.begin(),
00181                          last  = strings.end();
00182                 
00183     while(first != last)
00184     {
00185        ++line_count;
00186 
00187        std::string& cur = *first;
00188 
00189        // remove trailing \r
00190 
00191        if(cur.size() && cur[cur.size()-1] == '\r')
00192        {
00193          cur.erase( cur.size()-1 );
00194        }
00195 
00196 
00197        if(handle_continuations &&
00198           line_count != 1      &&
00199           (cur[0] == '\t' || cur[0] == ' ')
00200          )
00201        {
00202          // this is a line continuation, append it to previous line
00203          // and delete it.
00204 
00205          stringlist::iterator prev = first;  --prev;
00206 
00207          (*prev) += ' ';
00208          (*prev) += cur;
00209 
00210          prev = first;
00211 
00212          ++first;
00213 
00214          strings.erase(prev);
00215 
00216        }
00217        else
00218        {
00219          ++first;
00220        }
00221 
00222     }
00223 
00224   }
00225 }
00226 
00227 
00228 char const *
00229 POP3::Impl::
00230 fetch_messages()
00231 {
00232   // read all the messages from the server without deleting them.  Split the
00233   // headers, bodies, options, etc into sections for easy display.
00234 
00235   int i;
00236 
00237   int message_count = popnum(session_);
00238 
00239   for(i=0; i < message_count; ++i)
00240   {
00241     //
00242     //  Read the header for the named message, and if said message
00243     //  exists, read its body.  Removing trailing \r's from the records
00244     //  and concatenate lines beginning with tabs to their immediate
00245     //  predecessor.
00246     //
00247     char *msg = popgethead(session_, i+1);   // one based number
00248 
00249     if(msg)
00250     {
00251       POP3::Message *m = new POP3::Message;
00252 
00253       messages_.push_back(m);
00254 
00255       stringlist strings;
00256 
00257       StrTool::parse_lines(msg, &strings);
00258 
00259       m->header_.id_ = popmsguid(session_,i+1);
00260 
00261       free(msg);
00262 
00263       cleanse_lines(strings);
00264 
00265       // now split the lines of the header into the
00266       // fields in the header
00267 
00268       stringlist::iterator first = strings.begin(),
00269                            last  = strings.end();
00270                         
00271       while(first != last)
00272       {
00273         FileName cur = *first++;
00274         
00275         if(  cur.matches("[sS]ubject:*"))
00276         {
00277           cur.erase(0,8);
00278           m->header_.subject_ = cur;
00279         }
00280         else
00281         if(cur.matches("[dD]ate:*"))
00282         {
00283           cur.erase(0,6);
00284           m->header_.date_ = static_cast<std::string const &>(cur);
00285         }
00286         else
00287         if(cur.matches("[fF]rom:*"))
00288         {
00289           cur.erase(0,6);
00290 
00291           stringlist fromlist;
00292 
00293           StrTool::parse_words(cur, &fromlist);
00294 
00295           stringlist::iterator ufirst = fromlist.begin(),
00296                                ulast  = fromlist.end();
00297 
00298 
00299         
00300           while(ufirst != ulast)
00301           {
00302             string& u = *ufirst++;
00303         
00304             m->header_.from_.push_back(u);
00305           }
00306 
00307         }
00308         else
00309         if(cur.matches("[tT]o:*"))
00310         {
00311           cur.erase(0,4);
00312           stringlist fromlist;
00313 
00314           StrTool::parse_words(cur, &fromlist);
00315 
00316           stringlist::iterator ufirst = fromlist.begin(),
00317                                ulast  = fromlist.end();
00318 
00319 
00320         
00321           while(ufirst != ulast)
00322           {
00323             string& u = *ufirst++;
00324         
00325             m->header_.to_.push_back(u);
00326           }
00327         }
00328         else
00329         if(cur.matches("[Bb]cc:*"))
00330         {
00331           cur.erase(0,5);
00332           stringlist fromlist;
00333 
00334           StrTool::parse_words(cur, &fromlist);
00335 
00336           stringlist::iterator ufirst = fromlist.begin(),
00337                                ulast  = fromlist.end();
00338 
00339 
00340         
00341           while(ufirst != ulast)
00342           {
00343             string& u = *ufirst++;
00344         
00345             m->header_.bcc_.push_back(u);
00346           }
00347         }
00348         
00349       }
00350 
00351       // now split the body into lines
00352 
00353       msg = popgetmsg(session_, i+1);
00354 
00355       if(msg)
00356       {
00357         StrTool::parse_lines(msg, &m->body_.lines_);
00358         
00359         free(msg);
00360         
00361       }
00362 
00363       // now split the options out the body into the header
00364       // That is, find the first empty line after the beginning of the
00365       // body, potentially including the first line.  The empty line
00366       // terminates the options and begins the real data
00367 
00368       for(;;)
00369       {
00370         stringlist &body = m->body_.lines_;
00371         
00372         stringlist::iterator first = body.begin(),
00373                              last  = body.end();
00374                         
00375         if(first == last)
00376           break;
00377         
00378         string &first_line = body.front();
00379         
00380         if(first_line == "\r")
00381           break;
00382         
00383         m->header_.options_.push_back(first_line);
00384 
00385         body.erase( first );
00386       }
00387 
00388       // options have been deleted, the first line should be 0 length
00389 
00390       if(m->body_.lines_.begin() != m->body_.lines_.end())
00391       {
00392         if(m->body_.lines_.begin() != m->body_.lines_.end())
00393         {
00394           m->body_.lines_.erase( m->body_.lines_.begin() );
00395         }
00396       }
00397 
00398       cleanse_lines(m->header_.options_);
00399       cleanse_lines(m->body_.lines_, false);
00400 
00401 
00402     }
00403   }
00404 
00405   return 0;
00406 
00407 }
00408 
00409 
Generated on Wed Feb 29 22:50:05 2012 for CXXUtilities by  doxygen 1.6.3