pop3.tcl

Go to the documentation of this file.
00001 /*  pop3.tcl --*/
00002 /* */
00003 /*  POP3 mail client package, written in pure Tcl.*/
00004 /*  Some concepts borrowed from "frenchie", a POP3*/
00005 /*  mail client utility written by Scott Beasley.*/
00006 /* */
00007 /*  Copyright (c) 2000 by Ajuba Solutions.*/
00008 /*  portions Copyright (c) 2000 by Scott Beasley*/
00009 /* */
00010 /*  See the file "license.terms" for information on usage and redistribution*/
00011 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00012 /*  */
00013 /*  RCS: @(#) $Id: pop3.tcl,v 1.33 2005/09/30 05:36:39 andreas_kupries Exp $*/
00014 
00015 package require Tcl 8.2
00016 package require cmdline
00017 package require log
00018 package provide pop3 1.6.3
00019 
00020 namespace ::pop3 {
00021 
00022     /*  The state variable remembers information about the open pop3*/
00023     /*  connection. It is indexed by channel id. The information is*/
00024     /*  a keyed list, with keys "msex" and "retr_mode". The value*/
00025     /*  associated with "msex" is boolean, a true value signals that the*/
00026     /*  server at the other end is MS Exchange. The value associated*/
00027     /*  with "retr_mode" is one of {retr, list, slow}.*/
00028 
00029     /*  The value of "msex" influences how the translation for the*/
00030     /*  channel is set and is determined by the contents of the received*/
00031     /*  greeting. The value of "retr_mode" is initially "retr" and*/
00032     /*  completely determined by the first call to [retrieve]. For "list"*/
00033     /*  the system will use LIST before RETR to retrieve the message size.*/
00034 
00035     /*  The state can be influenced by options given to "open".*/
00036 
00037     variable  state
00038     array  state =  {}
00039 
00040 }
00041 
00042 /*  ::pop3::config --*/
00043 /* */
00044 /*  Retrieve configuration of pop3 connection*/
00045 /* */
00046 /*  Arguments:*/
00047 /*  chan      The channel, returned by ::pop3::open*/
00048 /* */
00049 /*  Results:*/
00050 /*  A serialized array.*/
00051 
00052 ret  ::pop3::config (type chan) {
00053     variable state
00054     return  $state($chan)
00055 }
00056 
00057 /*  ::pop3::close --*/
00058 /* */
00059 /*  Close the connection to the POP3 server.*/
00060 /* */
00061 /*  Arguments:*/
00062 /*  chan      The channel, returned by ::pop3::open*/
00063 /* */
00064 /*  Results:*/
00065 /*  None.*/
00066 
00067 ret  ::pop3::close (type chan) {
00068     variable state
00069     catch {::pop3::send $chan "QUIT"}
00070     unset state($chan)
00071     ::close $chan
00072 }
00073 
00074 /*  ::pop3::delete --*/
00075 /* */
00076 /*  Delete messages on the POP3 server.*/
00077 /* */
00078 /*  Arguments:*/
00079 /*  chan      The channel, returned by ::pop3::open*/
00080 /*        start     The first message to delete in the range.*/
00081 /*                  May be "next" (the next message after the last*/
00082 /*                  one seen, see ::pop3::last), "start" (aka 1),*/
00083 /*                  "end" (the last message in the spool, for */
00084 /*                  deleting only the last message).*/
00085 /*        end       (optional, defaults to -1) The last message*/
00086 /*                  to delete in the range. May be "last"*/
00087 /*                  (the last message viewed), "end" (the last*/
00088 /*                  message in the spool), or "-1" (the default,*/
00089 /*                  any negative number means delete only*/
00090 /*                  one message).*/
00091 /* */
00092 /*  Results:*/
00093 /*  None.*/
00094 /*        May throw errors from the server.*/
00095 
00096 ret  ::pop3::delete (type chan , type start , optional end =-1) {
00097 
00098     variable state
00099     array set  cstate $state($chan)
00100     set count $cstate(limit)
00101     set last 0
00102     catch {set last [::pop3::last $chan]}
00103 
00104     if {![string is integer $start]} {
00105     if {[string match $start "next"]} {
00106         set start $last
00107         incr start
00108     } elseif {$start == "start"} {
00109         set start 1
00110     } elseif {$start == "end"} {
00111         set start $count
00112     } else {
00113         error "POP3 Deletion error: Bad start index $start"
00114     }
00115     } 
00116     if {$start == 0} {
00117     set start 1
00118     }
00119     
00120     if {![string is integer $end]} {
00121     if {$end == "end"} {
00122         set end $count
00123     } elseif {$end == "last"} {
00124         set end $last
00125     } else {
00126         error "POP3 Deletion error: Bad end index $end"
00127     }
00128     } elseif {$end < 0} {
00129     set end $start
00130     }
00131 
00132     if {$end > $count} {
00133     set end $count
00134     }
00135     
00136     for {set index $start} {$index <= $end} {incr index} {
00137     if {[catch {::pop3::send $chan "DELE $index"} errorStr]} {
00138         error "POP3 DELETE ERROR: $errorStr"
00139     }
00140     }
00141     return {}
00142 }
00143 
00144 /*  ::pop3::last --*/
00145 /* */
00146 /*  Gets the index of the last email read from the server.*/
00147 /*        Note, some POP3 servers do not support this feature,*/
00148 /*        in which case the value returned may always be zero,*/
00149 /*        or an error may be thrown.*/
00150 /* */
00151 /*  Arguments:*/
00152 /*  chan      The channel, returned by ::pop3::open*/
00153 /* */
00154 /*  Results:*/
00155 /*  The index of the last email message read, which may*/
00156 /*        be zero if none have been read or if the server does*/
00157 /*        not support this feature.*/
00158 /*        Server errors may be thrown, including some cases*/
00159 /*        when the LAST command is not supported.*/
00160 
00161 ret  ::pop3::last (type chan) {
00162 
00163     if {[catch {
00164         set resultStr [::pop3::send $chan "LAST"]
00165         } errorStr]} {
00166     error "POP3 LAST ERROR: $errorStr"
00167     }
00168     
00169     return [string trim $resultStr]
00170 }
00171 
00172 /*  ::pop3::list --*/
00173 /* */
00174 /*  Returns "scan listing" of the mailbox. If parameter msg*/
00175 /*        is defined, then the listing only for the given message */
00176 /*        is returned.*/
00177 /* */
00178 /*  Arguments:*/
00179 /*  chan        The channel open to the POP3 server.*/
00180 /*        msg         The message number (optional).*/
00181 /* */
00182 /*  Results:*/
00183 /*  If msg parameter is not given, Tcl list of scan listings in */
00184 /*        the maildrop is returned. In case msg parameter is given,*/
00185 /*        a list of length one containing the specified message listing*/
00186 /*        is returned.*/
00187 
00188 ret  ::pop3::list (type chan , optional msg ="") {
00189     global PopErrorNm PopErrorStr debug
00190  
00191     if {$msg == ""} {
00192     if {[catch {::pop3::send $chan "LIST"} errorStr]} {
00193         error "POP3 LIST ERROR: $errorStr"
00194     }
00195     set msgBuffer [RetrSlow $chan]
00196     } else {
00197     # argument msg given, single-line response expected
00198 
00199     if {[catch {expr {0 + $msg}}]} {
00200         error "POP3 LIST ERROR: malformed message number '$msg'"
00201     } else {
00202         set msgBuffer [string trim [::pop3::send $chan "LIST $msg"]]
00203     }
00204     }
00205     return $msgBuffer
00206 }
00207 
00208 /*  pop3::open --*/
00209 /* */
00210 /*  Opens a connection to a POP3 mail server.*/
00211 /* */
00212 /*  Arguments:*/
00213 /*        args     A list of options and values, possibly empty,*/
00214 /*       followed by the regular arguments, i.e. host, user,*/
00215 /*       passwd and port. The latter is optional.*/
00216 /* */
00217 /*  host     The name or IP address of the POP3 server host.*/
00218 /*        user     The username to use when logging into the server.*/
00219 /*        passwd   The password to use when logging into the server.*/
00220 /*        port     (optional) The socket port to connect to, defaults*/
00221 /*                 to port 110, the POP standard port address.*/
00222 /* */
00223 /*  Results:*/
00224 /*  The connection channel (a socket).*/
00225 /*        May throw errors from the server.*/
00226 
00227 ret  ::pop3::open (type args) {
00228     variable state
00229     array set cstate {msex 0 retr_mode retr limit {}}
00230 
00231     log::log debug "pop3::open | [join $args]"
00232 
00233     while {[set err [cmdline::getopt args {msex.arg retr-mode.arg} opt arg]]} {
00234     if {$err < 0} {
00235         return -code error "::pop3::open : $arg"
00236     }
00237     switch -exact -- $opt {
00238         msex {
00239         if {![string is boolean $arg]} {
00240             return -code error \
00241                 ":pop3::open : Argument to -msex has to be boolean"
00242         }
00243         set cstate(msex) $arg
00244         }
00245         retr-mode {
00246         switch -exact -- $arg {
00247             retr - list - slow {
00248             set cstate(retr_mode) $arg
00249             }
00250             default {
00251             return -code error \
00252                 ":pop3::open : Argument to -retr-mode has to be one of retr, list or slow"
00253             }
00254         }
00255         }
00256         default {# Can't happen}
00257     }
00258     }
00259 
00260     if {[llength $args] > 4} {
00261     return -code error "To many arguments to ::pop3::open"
00262     }
00263     if {[llength $args] < 3} {
00264     return -code error "Not enough arguments to ::pop3::open"
00265     }
00266     foreach {host user password port} $args break
00267     if {$port == {}} {
00268     set port 110
00269     }
00270 
00271     log::log debug "pop3::open | protocol, connect to $host $port"
00272 
00273     # Argument processing is finally complete, now open the channel
00274 
00275     set chan [socket $host $port]
00276     fconfigure $chan -buffering none
00277 
00278     log::log debug "pop3::open | connect on $chan"
00279 
00280     if {$cstate(msex)} {
00281     # We are talking to MS Exchange. Work around its quirks.
00282     fconfigure $chan -translation binary
00283     } else {
00284     fconfigure $chan -translation {binary crlf}
00285     }
00286 
00287     log::log debug "pop3::open | wait for greeting"
00288 
00289     if {[catch {::pop3::send $chan {}} errorStr]} {
00290     ::close $chan
00291     error "POP3 CONNECT ERROR: $errorStr"
00292     }
00293 
00294     if {0} {
00295     # -FUTURE- Identify MS Exchange servers
00296     set cstate(msex) 1
00297 
00298     # We are talking to MS Exchange. Work around its quirks.
00299     fconfigure $chan -translation binary
00300     }
00301 
00302     log::log debug "pop3::open | authenticate $user (*password not shown*)"
00303 
00304     if {[catch {
00305     ::pop3::send $chan "USER $user"
00306     ::pop3::send $chan "PASS $password"
00307     } errorStr]} {
00308     ::close $chan
00309     error "POP3 LOGIN ERROR: $errorStr"
00310     }
00311 
00312     # [ 833486 ] Can't delete messages one at a time ...
00313     # Remember the number of messages in the maildrop at the beginning
00314     # of the session. This gives us the highest possible number for
00315     # message ids later. Note that this number must not be affected
00316     # when deleting mails later. While the number of messages drops
00317     # down the limit for the message id's stays the same. The messages
00318     # are not renumbered before the session actually closed.
00319 
00320     set cstate(limit) [lindex [::pop3::status $chan] 0]
00321 
00322     # Remember the state.
00323 
00324     set state($chan) [array get cstate]
00325 
00326     log::log debug "pop3::open | ok ($chan)"
00327     return $chan
00328 }
00329 
00330 /*  ::pop3::retrieve --*/
00331 /* */
00332 /*  Retrieve email message(s) from the server.*/
00333 /* */
00334 /*  Arguments:*/
00335 /*  chan      The channel, returned by ::pop3::open*/
00336 /*        start     The first message to retrieve in the range.*/
00337 /*                  May be "next" (the next message after the last*/
00338 /*                  one seen, see ::pop3::last), "start" (aka 1),*/
00339 /*                  "end" (the last message in the spool, for */
00340 /*                  retrieving only the last message).*/
00341 /*        end       (optional, defaults to -1) The last message*/
00342 /*                  to retrieve in the range. May be "last"*/
00343 /*                  (the last message viewed), "end" (the last*/
00344 /*                  message in the spool), or "-1" (the default,*/
00345 /*                  any negative number means retrieve only*/
00346 /*                  one message).*/
00347 /* */
00348 /*  Results:*/
00349 /*  A list containing all of the messages retrieved.*/
00350 /*        May throw errors from the server.*/
00351 
00352 ret  ::pop3::retrieve (type chan , type start , optional end =-1) {
00353     variable state
00354     array set cstate $state($chan)
00355     
00356     set count $cstate(limit)
00357     set last 0
00358     catch {set last [::pop3::last $chan]}
00359 
00360     if {![string is integer $start]} {
00361     if {[string match $start "next"]} {
00362         set start $last
00363         incr start
00364     } elseif {$start == "start"} {
00365         set start 1
00366     } elseif {$start == "end"} {
00367         set start $count
00368     } else {
00369         error "POP3 Retrieval error: Bad start index $start"
00370     }
00371     } 
00372     if {$start == 0} {
00373     set start 1
00374     }
00375     
00376     if {![string is integer $end]} {
00377     if {$end == "end"} {
00378         set end $count
00379     } elseif {$end == "last"} {
00380         set end $last
00381     } else {
00382         error "POP3 Retrieval error: Bad end index $end"
00383     }
00384     } elseif {$end < 0} {
00385     set end $start
00386     }
00387 
00388     if {$end > $count} {
00389     set end $count
00390     }
00391     
00392     set result {}
00393 
00394     ::log::log debug "pop3 $chan retrieve $start -- $end"
00395 
00396     for {set index $start} {$index <= $end} {incr index} {
00397     switch -exact -- $cstate(retr_mode) {
00398         retr {
00399         set sizeStr [::pop3::send $chan "RETR $index"]
00400 
00401         ::log::log debug "pop3 $chan retrieve ($sizeStr)"
00402 
00403         if {[scan $sizeStr {%d %s} size dummy] < 1} {
00404             # The server did not deliver the size information.
00405             # Switch our mode to "list" and use the slow
00406             # method this time. The next call will use LIST before
00407             # RETR to get the size information. If even that fails
00408             # the system will fall back to slow mode all the time.
00409 
00410             ::log::log debug "pop3 $chan retrieve - no size information, go slow"
00411 
00412             set cstate(retr_mode) list
00413             set state($chan) [array get cstate]
00414 
00415             # Retrieve in slow motion.
00416             set msgBuffer [RetrSlow $chan]
00417         } else {
00418             ::log::log debug "pop3 $chan retrieve - size information present, use fast mode"
00419 
00420             set msgBuffer [RetrFast $chan $size]
00421         }
00422         }
00423         list {
00424         set sizeStr [::pop3::send $chan "LIST $index"]
00425 
00426         if {[scan $sizeStr {%d %d %s} dummy size dummy] < 2} {
00427             # Not even LIST generates the necessary size information.
00428             # Switch to full slow mode and don't bother anymore.
00429 
00430             set cstate(retr_mode) slow
00431             set state($chan) [array get cstate]
00432 
00433             ::pop3::send $chan "RETR $index"
00434 
00435             # Retrieve in slow motion.
00436             set msgBuffer [RetrSlow $chan]
00437         } else {
00438             # Ignore response of RETR, already know the size
00439             # through LIST
00440 
00441             ::pop3::send $chan "RETR $index"
00442             set msgBuffer [RetrFast $chan $size]
00443         }
00444         }
00445         slow {
00446         # Retrieve in slow motion.
00447 
00448         ::pop3::send $chan "RETR $index"
00449         set msgBuffer [RetrSlow $chan]
00450         }
00451     }
00452     lappend result $msgBuffer
00453     }
00454     return $result
00455 }
00456 
00457 /*  ::pop3::RetrFast --*/
00458 /* */
00459 /*  Fast retrieval of a message from the pop3 server.*/
00460 /*  Internal helper to prevent code bloat in "pop3::retrieve"*/
00461 /* */
00462 /*  Arguments:*/
00463 /*  chan    The channel to read the message from.*/
00464 /* */
00465 /*  Results:*/
00466 /*  The text of the retrieved message.*/
00467 
00468 ret  ::pop3::RetrFast (type chan , type size) {
00469     set msgBuffer [read $chan $size]
00470 
00471     foreach line [split $msgBuffer \n] {
00472     ::log::log debug "pop3 $chan fast <$line>"
00473     }
00474 
00475     # There is a small discrepance in counting octets we have to be
00476     # aware of. 'size' is #octets before transmission, i.e. can be
00477     # with one eol character, CR or LF. The channel system in binary
00478     # mode counts every character, and the protocol specified CRLF as
00479     # eol, so for every line in the message we read that many
00480     # characters _less_. Another factor which can cause a miscount is
00481     # the ".-stuffing performed by the sender. I.e. what we got now is
00482     # not necessarily the complete message. We have to perform slow
00483     # reads to get the remainder of the message. This has another
00484     # complication. We cannot simply check for a line containing the
00485     # terminating signature, simply because the point where the
00486     # message was broken in two might just be in between the dots of a
00487     # "\r\n..\r\n" sequence. We have to make sure that we do not
00488     # misinterpret the second part of this sequence as terminator.
00489     # Another possibility: "\r\n.\r\n" is broken just after the dot.
00490     # Then we have to ensure to not to miss the terminator entirely.
00491 
00492     # Sometimes the gets returns nothing, need to get the real
00493     # terminating "."                                    / "
00494 
00495     if {[string equal [string range $msgBuffer end-3 end] "\n.\r\n"]} {
00496     # Complete terminator found. Remove it from the message buffer.
00497 
00498     ::log::log debug "pop3 $chan /5__"
00499     set msgBuffer [string range $msgBuffer 0 end-3]
00500 
00501     } elseif {[string equal [string range $msgBuffer end-2 end] "\n.\r"]} {
00502     # Complete terminator found. Remove it from the message buffer.
00503     # Also perform an empty read to remove the missing '\n' from
00504     # the channel. If we don't do this all following commands will
00505     # run into off-by-one (character) problems.
00506 
00507     ::log::log debug "pop3 $chan /4__"
00508     set msgBuffer [string range $msgBuffer 0 end-2]
00509     while {[read $chan 1] != "\n"} {}
00510 
00511     } elseif {[string equal [string range $msgBuffer end-1 end] "\n."]} {
00512     # \n. at the end of the fast buffer.
00513     # Can be    \n.\r\n  = Terminator
00514     # or        \n..\r\n = dot-stuffed single .
00515 
00516     log::log debug "pop3 $chan /check for cut .. or terminator sequence"
00517 
00518     # Idle until non-empty line encountered.
00519     while {[set line [gets $chan]] == ""} {}
00520     if {"$line" == "\r"} {
00521         # Terminator already found. Note that we have to
00522         # remove the partial terminator sequence from the
00523         # message buffer.
00524         ::log::log debug "pop3 $chan /3__ <$line>"
00525         set msgBuffer [string range $msgBuffer 0 end-1]
00526     } else {
00527         # Append line and look for the real terminator
00528         append msgBuffer $line
00529         ::log::log debug "pop3 $chan ____ <$line>"
00530         while {[set line [gets $chan]] != ".\r"} {
00531         ::log::log debug "pop3 $chan ____ <$line>"
00532         append msgBuffer $line
00533         }
00534         ::log::log debug "pop3 $chan /2__ <$line>"
00535     }
00536     } elseif {[string equal [string index $msgBuffer end] \n]} {
00537     # Line terminator (\n) found. The remainder of the mail has to
00538     # consist of true lines we can read directly.
00539 
00540     while {![string equal [set line [gets $chan]] ".\r"]} {
00541         ::log::log debug "pop3 $chan ____ <$line>"
00542         append msgBuffer $line
00543     }
00544     ::log::log debug "pop3 $chan /1__ <$line>"
00545     } else {
00546     # Incomplete line at the end of the buffer. We complete it in
00547     # a single read, and then handle the remainder like the case
00548     # before, where we had a complete line at the end of the
00549     # buffer.
00550 
00551     set line [gets $chan]
00552     ::log::log debug "pop3 $chan /1a_ <$line>"
00553     append msgBuffer $line
00554 
00555     ::log::log debug "pop3 $chan /1b_"
00556 
00557     while {![string equal [set line [gets $chan]] ".\r"]} {
00558         ::log::log debug "pop3 $chan ____ <$line>"
00559         append msgBuffer $line
00560     }
00561     ::log::log debug "pop3 $chan /1c_ <$line>"
00562     }
00563 
00564     ::log::log debug "pop3 $chan done"
00565 
00566     # Map both cr+lf and cr to lf to simulate auto EOL translation, then
00567     # unstuff .-stuffed lines.
00568 
00569     return [string map [::list \n.. \n.] [string map [::list \r \n] [string map [::list \r\n \n] $msgBuffer]]]
00570 }
00571 
00572 /*  ::pop3::RetrSlow --*/
00573 /* */
00574 /*  Slow retrieval of a message from the pop3 server.*/
00575 /*  Internal helper to prevent code bloat in "pop3::retrieve"*/
00576 /* */
00577 /*  Arguments:*/
00578 /*  chan    The channel to read the message from.*/
00579 /* */
00580 /*  Results:*/
00581 /*  The text of the retrieved message.*/
00582 
00583 ret  ::pop3::RetrSlow (type chan) {
00584 
00585     set msgBuffer ""
00586     
00587     while {1} {
00588     set line [string trimright [gets $chan] \r]
00589     ::log::log debug "pop3 $chan slow $line"
00590 
00591     # End of the message is a line with just "."
00592     if {$line == "."} {
00593         break
00594     } elseif {[string index $line 0] == "."} {
00595         set line [string range $line 1 end]
00596     }
00597         
00598     append msgBuffer $line "\n"
00599     }
00600 
00601     return $msgBuffer
00602 }
00603 
00604 /*  ::pop3::send --*/
00605 /* */
00606 /*  Send a command string to the POP3 server.  This is an*/
00607 /*        internal function, but may be used in rare cases.*/
00608 /* */
00609 /*  Arguments:*/
00610 /*  chan        The channel open to the POP3 server.*/
00611 /*        cmdstring   POP3 command string*/
00612 /* */
00613 /*  Results:*/
00614 /*  Result string from the POP3 server, except for the +OK tag.*/
00615 /*        Errors from the POP3 server are thrown.*/
00616 
00617 ret  ::pop3::send (type chan , type cmdstring) {
00618    global PopErrorNm PopErrorStr debug
00619 
00620    if {$cmdstring != {}} {
00621        ::log::log debug "pop3 $chan >>> $cmdstring"       
00622        puts $chan $cmdstring
00623    }
00624    
00625    set popRet [string trim [gets $chan]]
00626    ::log::log debug "pop3 $chan <<< $popRet"
00627 
00628    if {[string first "+OK" $popRet] == -1} {
00629        error [string range $popRet 4 end]
00630    }
00631 
00632    return [string range $popRet 3 end]
00633 }
00634 
00635 /*  ::pop3::status --*/
00636 /* */
00637 /*  Get the status of the mail spool on the POP3 server.*/
00638 /* */
00639 /*  Arguments:*/
00640 /*  chan      The channel, returned by ::pop3::open*/
00641 /* */
00642 /*  Results:*/
00643 /*  A list containing two elements, {msgCount octetSize},*/
00644 /*        where msgCount is the number of messages in the spool*/
00645 /*        and octetSize is the size (in octets, or 8 bytes) of*/
00646 /*        the entire spool.*/
00647 
00648 ret  ::pop3::status (type chan) {
00649 
00650     if {[catch {set statusStr [::pop3::send $chan "STAT"]} errorStr]} {
00651     error "POP3 STAT ERROR: $errorStr"
00652     }
00653 
00654     # Dig the sent size and count info out.
00655     set rawStatus [split [string trim $statusStr]]
00656     
00657     return [::list [lindex $rawStatus 0] [lindex $rawStatus 1]]
00658 }
00659 
00660 /*  ::pop3::top --*/
00661 /* */
00662 /*        Optional POP3 command (see RFC1939). Retrieves message header*/
00663 /*        and given number of lines from the message body.*/
00664 /* */
00665 /*  Arguments:*/
00666 /*  chan        The channel open to the POP3 server.*/
00667 /*        msg         The message number to be retrieved.*/
00668 /*        n           Number of lines returned from the message body.*/
00669 /* */
00670 /*  Results:*/
00671 /*  Text (with newlines) from the server.*/
00672 /*        Errors from the POP3 server are thrown.*/
00673 
00674 ret  ::pop3::top (type chan , type msg , type n) {
00675     global PopErrorNm PopErrorStr debug
00676     
00677     if {[catch {::pop3::send $chan "TOP $msg $n"} errorStr]} {
00678     error "POP3 TOP ERROR: $errorStr"
00679     }
00680 
00681     return [RetrSlow $chan]
00682 }
00683 
00684 /*  ::pop3::uidl --*/
00685 /* */
00686 /*  Returns "uid listing" of the mailbox. If parameter msg*/
00687 /*  is defined, then the listing only for the given message*/
00688 /*  is returned.*/
00689 /* */
00690 /*  Arguments:*/
00691 /*  chan        The channel open to the POP3 server.*/
00692 /*  msg         The message number (optional).*/
00693 /* */
00694 /*  Results:*/
00695 /*  If msg parameter is not given, Tcl list of uid listings in*/
00696 /*  the maildrop is returned. In case msg parameter is given,*/
00697 /*  a list of length one containing the uid of the specified*/
00698 /*  message listing is returned.*/
00699 
00700 ret  ::pop3::uidl (type chan , optional msg ="") {
00701     if {$msg == ""} {
00702     if {[catch {::pop3::send $chan "UIDL"} errorStr]} {
00703         error "POP3 UIDL ERROR: $errorStr"
00704     }
00705     set msgBuffer [RetrSlow $chan]
00706     } else {
00707     # argument msg given, single-line response expected
00708     
00709     if {[catch {expr {0 + $msg}}]} {
00710         error "POP3 UIDL ERROR: malformed message number '$msg'"
00711     } else {
00712         set msgBuffer [string trim [::pop3::send $chan "UIDL $msg"]]
00713     }
00714     }
00715 
00716     return $msgBuffer
00717 }
00718 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1