pop3d_dbox.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 package require mime ;
00017 package require log ;
00018
00019 namespace ::pop3d::dbox {
00020
00021
00022
00023
00024
00025
00026 variable counter 0
00027
00028
00029 variable commands [list \
00030 "add" \
00031 "base" \
00032 "dele" \
00033 "destroy" \
00034 "exists" \
00035 "get" \
00036 "list" \
00037 "lock" \
00038 "locked" \
00039 "move" \
00040 "remove" \
00041 "size" \
00042 "stat" \
00043 "unlock" \
00044 ]
00045
00046 variable version ; version = 1.0.2
00047 }
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 ret ::pop3d::dbox::new (optional name ="") {
00063 variable counter
00064
00065 if { [llength [info level 0]] == 1 } {
00066 incr counter
00067 set name "p3dbox${counter}"
00068 }
00069
00070 if { ![string equal [info commands ::$name] ""] } {
00071 return -code error \
00072 "command \"$name\" already exists,\
00073 unable to create mailbox database"
00074 }
00075
00076 # Set up the namespace
00077 namespace eval ::pop3d::dbox::dbox::$name {
00078 variable dir ""
00079 variable state ; array set state {}
00080 variable locked ; array set locked {}
00081 variable transfer ; array set transfer {}
00082 }
00083
00084 # Create the command to manipulate the mailbox database
00085 interp alias {} ::$name {} ::pop3d::dbox::DboxProc $name
00086
00087 return $name
00088 }
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 ret ::pop3d::dbox::DboxProc (type name , optional cmd ="" , type args) {
00105
00106 # Do minimal args checks here
00107 if { [llength [info level 0]] == 2 } {
00108 return -code error \
00109 "wrong # args: should be \"$name option ?arg arg ...?\""
00110 }
00111
00112 # Split the args into command and args components
00113 if { [llength [info commands ::pop3d::dbox::_$cmd]] == 0 } {
00114 variable commands
00115 set optlist [join $commands ", "]
00116 set optlist [linsert $optlist "end-1" "or"]
00117 return -code error "bad option \"$cmd\": must be $optlist"
00118 }
00119 eval [list ::pop3d::dbox::_$cmd $name] $args
00120 }
00121
00122
00123 ret ::pop3d::dbox::_base (type name , type base) {
00124 # @c Constructor. Does some more checks on the given base directory.
00125
00126 # sanity checks
00127 if {$base == {}} {
00128 return -code error "directory not specified"
00129 }
00130 if {! [file exists $base]} {
00131 return -code error "base: \"$base\" does not exist"
00132 }
00133 if {! [file isdirectory $base]} {
00134 return -code error "base: \"$base\" not a directory"
00135 }
00136 if {! [file readable $base]} {
00137 return -code error "base: \"$base\" not readable"
00138 }
00139 if {! [file writable $base]} {
00140 return -code error "base: \"$base\" not writable"
00141 }
00142
00143 upvar ::pop3d::dbox::dbox::${name}::dir dir
00144 set dir $base
00145 return
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 ret ::pop3d::dbox::_destroy (type name) {
00161 namespace delete ::pop3d::dbox::dbox::$name
00162 interp alias {} ::$name {}
00163 return
00164 }
00165
00166 ret ::pop3d::dbox::_add (type name , type mbox) {
00167 # @c Create a mailbox with handle <a mbox>. The handle is used as the
00168 # @c name of the directory to contain the mails too.
00169 #
00170 # @a mbox: Reference to the mailbox to be operated on.
00171
00172 set dir [CheckDir $name]
00173 set mboxpath [file join $dir $mbox]
00174
00175 if {[file exists $mboxpath]} {
00176 return -code error "cannot add \"$mbox\", mailbox already in existence"
00177 }
00178
00179 file mkdir $mboxpath
00180 return
00181 }
00182
00183
00184 ret ::pop3d::dbox::_remove (type name , type mbox) {
00185 # @c Remove mailbox with handle <a mbox>. This will destroy all mails
00186 # @c contained in it too.
00187 #
00188 # @a mbox: Reference to the mailbox to be operated on.
00189
00190 set dir [CheckDir $name]
00191 set mboxpath [file join $dir $mbox]
00192
00193 if {![file exists $mboxpath]} {
00194 return -code error "cannot remove \"$mbox\", mailbox does not exist"
00195 }
00196
00197 if {[_locked $name $mbox]} {
00198 return -code error "cannot remove \"$mbox\", mailbox is locked"
00199 }
00200
00201 file delete -force $mboxpath
00202 return
00203 }
00204
00205
00206 ret ::pop3d::dbox::_move (type name , type old , type new) {
00207 # @c Change the handle of mailbox <a old> to <a new>.
00208 #
00209 # @a old: Reference to the mailbox to be operated on.
00210 # @a new: New reference to the mailbox
00211
00212 set dir [CheckDir $name]
00213 set oldpath [file join $dir $old]
00214 set newpath [file join $dir $new]
00215
00216 if {![file exists $oldpath]} {
00217 return -code error "cannot move \"$old\", mailbox does not exist"
00218 }
00219 if {[file exists $newpath]} {
00220 return -code error \
00221 "cannot move \"$old\", destination \"$new\" already exists"
00222 }
00223
00224 file rename -force $oldpath $newpath
00225 return
00226 }
00227
00228
00229 ret ::pop3d::dbox::_list (type name) {
00230 # @c Lists known mailboxes in object.
00231 # @r List of mailbox names.
00232
00233 set dir [CheckDir $name]
00234 set here [pwd]
00235 cd $dir
00236 set files [glob -nocomplain *]
00237 cd $here
00238
00239 set res [list]
00240 foreach f $files {
00241 set mboxpath [file join $dir $f]
00242 if {! [file isdirectory $mboxpath]} {continue}
00243 if {! [file readable $mboxpath]} {continue}
00244 if {! [file writable $mboxpath]} {continue}
00245 lappend res $f
00246 }
00247 return $res
00248 }
00249
00250
00251 ret ::pop3d::dbox::_exists (type name , type mbox) {
00252 # @c Determines existence of mailbox <a mbox>.
00253 # @a mbox: Reference to the mailbox to check for.
00254 # @r 1 if the mailbox exists, 0 else.
00255
00256 set dir [CheckDir $name]
00257 set mbox [file join $dir $mbox]
00258 return [file exists $mbox]
00259 }
00260
00261
00262 ret ::pop3d::dbox::_locked (type name , type mbox) {
00263 # @c Checks wether the specified mailbox is locked or not.
00264 # @a mbox: Reference to the mailbox to check.
00265 # @r 1 if the mailbox is locked, 0 else.
00266
00267 set dir [CheckDir $name]
00268 set mbox [file join $dir $mbox]
00269
00270 upvar ::pop3d::dbox::dbox::${name}::locked locked
00271
00272 return [::info exists locked($mbox)]
00273 }
00274
00275
00276
00277
00278 ret ::pop3d::dbox::_lock (type name , type mbox) {
00279 # @c Locks the given mailbox, additionally stores a list of the
00280 # @c available files in the manager state. All files (= messages)
00281 # @c added to the mailbox after this operation will be ignored
00282 # @c during the session.
00283 #
00284 # @a mbox: Reference to the mailbox to be locked.
00285 # @r 1 if mailbox was locked sucessfully, 0 else.
00286
00287 # locked already ?
00288 if {[_locked $name $mbox]} {
00289 return 0
00290 }
00291
00292 set dir [Check $name $mbox]
00293
00294 # Compute a list of message files residing in the mailbox directory
00295
00296 upvar ::pop3d::dbox::dbox::${name}::state state
00297 upvar ::pop3d::dbox::dbox::${name}::locked locked
00298
00299 set state($dir) [lsort [glob -nocomplain [file join $dir *]]]
00300 set locked($dir) 1
00301 return 1
00302 }
00303
00304
00305 ret ::pop3d::dbox::_unlock (type name , type mbox) {
00306 # @c A locked mailbox is unlocked, thereby made available
00307 # @c to other sessions.
00308 #
00309 # @a mbox: Reference to the mailbox to be locked.
00310
00311 # not locked ?
00312 if {![_locked $name $mbox]} {return}
00313 set dir [Check $name $mbox]
00314
00315 upvar ::pop3d::dbox::dbox::${name}::state state
00316 upvar ::pop3d::dbox::dbox::${name}::locked locked
00317
00318 unset state($dir)
00319 unset locked($dir)
00320 return
00321 }
00322
00323
00324 ret ::pop3d::dbox::_stat (type name , type mbox) {
00325 # @c Determines the number of messages picked up by <m lock>.
00326 # @c Will fail if the mailbox was not locked.
00327 #
00328 # @a mbox: Reference to the mailbox queried.
00329 # @r The number of messages in the mailbox
00330
00331 set dir [Check $name $mbox]
00332
00333 if {![_locked $name $mbox]} {
00334 return -code error "mailbox \"$mbox\" is not locked"
00335 }
00336
00337 upvar ::pop3d::dbox::dbox::${name}::state state
00338
00339 return [llength $state($dir)]
00340 }
00341
00342
00343 ret ::pop3d::dbox::_size (type name , type mbox , optional msgId ={)} {
00344 # @c Determines the size of the specified message, in bytes.
00345 #
00346 # @a mbox: Reference to the mailbox to be operated on.
00347 # @a msgId: Numerical index of the message to look at.
00348 # @r size of the message in bytes.
00349
00350 log::log debug "$name size $mbox ($msgId)"
00351
00352 set dir [Check $name $mbox]
00353
00354 log::log debug "$name mbox dir = $dir"
00355
00356 upvar ::pop3d::dbox::dbox::${name}::state state
00357
00358 if {$msgId == {}} {
00359 log::log debug "$name size /full"
00360
00361
00362 if {![info exists state($dir)]} {
00363
00364
00365
00366 return 0
00367 }
00368
00369 n = 0
00370 k = [llength $state($dir)]
00371 for { id = 0} {$id < $k} {incr id} {
00372 incr n [file size [lindex $state($dir) $id]]
00373 }
00374 return $n
00375 }
00376
00377 if {
00378 ($msgId < 1) ||
00379 (![info exists state($dir)]) ||
00380 ([llength $state($dir)] < $msgId)
00381 } {
00382 return -code error "id \"$msgId\" out of range"
00383 }
00384 incr msgId -1
00385
00386
00387 log::log debug "$name msg file = [lindex $state($dir) $msgId]"
00388
00389 return [file size [lindex $state($dir) $msgId]]
00390 }
00391
00392
00393 ret ::pop3d::dbox::_dele (type name , type mbox , type msgList) {
00394 # @c Deletes the specified messages from the mailbox. This should
00395 # @c be followed by a <m unlock> as the state is not updated
00396 # @c accordingly.
00397 #
00398 # @a mbox: Reference to the mailbox to be operated on.
00399 # @a msgList: List of message ids.
00400
00401 set dir [Check $name $mbox]
00402 if {[llength $msgList] == 0} {
00403 return -code error "nothing to delete"
00404 }
00405
00406 # @d The code assumes that the id's in the list were already
00407 # @d checked against the maximal number of messages.
00408
00409 upvar ::pop3d::dbox::dbox::${name}::state state
00410
00411 foreach msgId $msgList {
00412 if {
00413 ($msgId < 1) ||
00414 (![info exists state($dir)]) ||
00415 ([llength $state($dir)] < $msgId)
00416 } {
00417 return -code error "id \"$msgId\" out of range"
00418 }
00419 }
00420 foreach msgId $msgList {
00421 file delete [lindex $state($dir) [incr msgId -1]]
00422 }
00423
00424 # the mailbox state is unusable now.
00425 return
00426 }
00427
00428 ret ::pop3d::dbox::_get (type name , type mbox , type msgId) {
00429 set dir [Check $name $mbox]
00430
00431 upvar ::pop3d::dbox::dbox::${name}::state state
00432
00433 if {
00434 ($msgId < 1) ||
00435 (![info exists state($dir)]) ||
00436 ([llength $state($dir)] < $msgId)
00437 } {
00438 return -code error "id \"$msgId\" out of range"
00439 }
00440 incr msgId -1
00441
00442 set mailfile [lindex $state($dir) $msgId]
00443
00444 set token [::mime::initialize -file $mailfile]
00445 return $token
00446 }
00447
00448
00449
00450
00451
00452 ret ::pop3d::dbox::Check (type name , type mbox) {
00453 # @c Internal procedure. Used to map a mailbox handle
00454 # @c to the directory containing the messages.
00455 # @a mbox: Reference to the mailbox to be operated on.
00456 # @r Path of directory holding the message files of the
00457 # @r specified mailbox.
00458
00459 set dir [CheckDir $name]
00460 set mboxpath [file join $dir $mbox]
00461
00462 if {! [file exists $mboxpath]} {
00463 return -code error "\"$mbox\" does not exist"
00464 }
00465 if {! [file isdirectory $mboxpath]} {
00466 return -code error "\"$mbox\" is not a directory"
00467 }
00468 if {! [file readable $mboxpath]} {
00469 return -code error "\"$mbox\" is not readable"
00470 }
00471 if {! [file writable $mboxpath]} {
00472 return -code error "\"$mbox\" is not writable"
00473 }
00474 return $mboxpath
00475 }
00476
00477 ret ::pop3d::dbox::CheckDir (type name) {
00478 upvar ::pop3d::dbox::dbox::${name}::dir dir
00479
00480 if {$dir == {}} {
00481 return -code error "base directory not specified"
00482 }
00483 return $dir
00484 }
00485
00486
00487
00488
00489 package provide pop3d::dbox $::pop3d::dbox::version
00490