1# GNU Mailutils -- a suite of utilities for electronic mail 2# Copyright (C) 2009-2021 Free Software Foundation, Inc. 3# 4# This library is free software; you can redistribute it and/or 5# modify it under the terms of the GNU Lesser General Public 6# License as published by the Free Software Foundation; either 7# version 3 of the License, or (at your option) any later version. 8# 9# This library is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# Lesser General Public License for more details. 13# 14# You should have received a copy of the GNU Lesser General 15# Public License along with this library. If not, see 16# <http://www.gnu.org/licenses/>. 17 18from mailutils.c_api import mailbox 19from mailutils import message 20from mailutils import folder 21from mailutils import url 22from mailutils.error import MailboxError 23 24class MailboxBase: 25 def open (self, mode=0): 26 """Open the connection. 27 28 'mode' may be a string, consisting of the characters described 29 below, giving the access mode for the mailbox. 30 31 mode Meaning 32 -------------------------------------------------------- 33 r Open for reading. 34 w Open for writing. 35 a Open for appending to the end of the mailbox. 36 c Create the mailbox if it does not exist. 37 38 """ 39 if isinstance (mode, str): 40 from mailutils import stream 41 flags = 0 42 for m in mode: 43 if m == 'r': 44 flags = flags | stream.MU_STREAM_READ 45 elif m == 'w': 46 flags = flags | stream.MU_STREAM_WRITE 47 elif m == 'a': 48 flags = flags | stream.MU_STREAM_APPEND 49 elif m == 'c': 50 flags = flags | stream.MU_STREAM_CREAT 51 if flags & stream.MU_STREAM_READ and flags & stream.MU_STREAM_WRITE: 52 flags = (flags & ~(stream.MU_STREAM_READ | \ 53 stream.MU_STREAM_WRITE)) | \ 54 stream.MU_STREAM_RDWR 55 mode = flags 56 status = mailbox.open (self.mbox, mode) 57 if status: 58 raise MailboxError (status) 59 60 def close (self): 61 """Close the connection.""" 62 status = mailbox.close (self.mbox) 63 if status: 64 raise MailboxError (status) 65 66 def flush (self, expunge=False): 67 """Flush the mailbox.""" 68 status = mailbox.flush (self.mbox, expunge) 69 if status: 70 raise MailboxError (status) 71 72 def messages_count (self): 73 """Return the number of messages in mailbox.""" 74 status, total = mailbox.messages_count (self.mbox) 75 if status: 76 raise MailboxError (status) 77 return total 78 79 def messages_recent (self): 80 """Return the number of recent messages in mailbox.""" 81 status, recent = mailbox.messages_recent (self.mbox) 82 if status: 83 raise MailboxError (status) 84 return recent 85 86 def message_unseen (self): 87 """Return the number of first unseen message in mailbox.""" 88 status, recent = mailbox.message_unseen (self.mbox) 89 if status: 90 raise MailboxError (status) 91 return unseen 92 93 def get_message (self, msgno): 94 """Retrieve message number 'msgno'.""" 95 status, c_msg = mailbox.get_message (self.mbox, msgno) 96 if status: 97 raise MailboxError (status) 98 return message.Message (c_msg) 99 100 def append_message (self, msg): 101 """Append 'msg' to the mailbox.""" 102 status = mailbox.append_message (self.mbox, msg.msg) 103 if status: 104 raise MailboxError (status) 105 106 def expunge (self): 107 """Remove all messages marked for deletion.""" 108 status = mailbox.expunge (self.mbox) 109 if status: 110 raise MailboxError (status) 111 112 def sync (self): 113 """Synchronize the mailbox.""" 114 status = mailbox.sync (self.mbox) 115 if status: 116 raise MailboxError (status) 117 118 def get_uidls (self): 119 """Get UIDL list.""" 120 status, uidls = mailbox.get_uidls (self.mbox) 121 if status: 122 raise MailboxError (status) 123 return uidls 124 125 def lock (self): 126 """Lock the mailbox.""" 127 status = mailbox.lock (self.mbox) 128 if status: 129 raise MailboxError (status) 130 131 def unlock (self): 132 """Unlock the mailbox.""" 133 status = mailbox.unlock (self.mbox) 134 if status: 135 raise MailboxError (status) 136 137 def get_size (self): 138 """Return the mailbox size.""" 139 status, size = mailbox.get_size (self.mbox) 140 if status: 141 raise MailboxError (status) 142 return size 143 144 def get_folder (self): 145 """Get the Folder object.""" 146 status, fld = mailbox.get_folder (self.mbox) 147 if status: 148 raise MailboxError (status) 149 return folder.Folder (fld) 150 151 def get_url (self): 152 """Get the Url object.""" 153 status, u = mailbox.get_url (self.mbox) 154 if status: 155 raise MailboxError (status) 156 return url.Url (u) 157 158 def __next__ (self): 159 if self.__count >= self.__len: 160 self.__count = 0 161 raise StopIteration 162 else: 163 self.__count += 1 164 return self.get_message (self.__count) 165 166 def __getitem__ (self, msgno): 167 return self.get_message (msgno) 168 169 def __iter__ (self): 170 self.__count = 0 171 self.__len = self.messages_count () 172 return self 173 174 def __getattr__ (self, name): 175 if name == 'size': 176 return self.get_size () 177 elif name == 'folder': 178 return self.get_folder () 179 elif name == 'url': 180 return self.get_url () 181 else: 182 raise AttributeError(name) 183 184 def __len__ (self): 185 return self.messages_count () 186 187 def __str__ (self): 188 return '<Mailbox %s (%d)>' % (self.get_url (), self.messages_count ()) 189 190class Mailbox (MailboxBase): 191 __owner = False 192 def __init__ (self, name): 193 if isinstance (name, mailbox.MailboxType): 194 self.mbox = name 195 else: 196 self.mbox = mailbox.MailboxType () 197 self.__owner = True 198 status = mailbox.create (self.mbox, name) 199 if status: 200 raise MailboxError (status) 201 202 def __del__ (self): 203 if self.__owner: 204 mailbox.destroy (self.mbox) 205 del self.mbox 206 207class MailboxDefault (MailboxBase): 208 def __init__ (self, name=None): 209 """MailboxDefault creates a Mailbox object for the supplied 210 mailbox 'name'. Before creating, the name is expanded using 211 the rules below: 212 213 % --> system mailbox for the real uid 214 %user --> system mailbox for the given user 215 ~/file --> /home/user/file 216 ~user/file --> /home/user/file 217 +file --> /home/user/Mail/file 218 =file --> /home/user/Mail/file 219 """ 220 self.mbox = mailbox.MailboxType () 221 status = mailbox.create_default (self.mbox, name) 222 if status: 223 raise MailboxError (status) 224 225 def __del__ (self): 226 mailbox.destroy (self.mbox) 227 del self.mbox 228