mailbox._pike
Go to the documentation of this file.
1 /* Copyright (C) 2000-2004 Thomas Bopp, Thorsten Hampel, Ludger Merkens
2  * Copyright (C) 2002 Christian Schmidt
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * $Id: mailbox.pike,v 1.1 2008/03/31 13:39:57 exodusd Exp $
19  */
20 inherit "/kernel/module";
21 inherit "/net/coal/binary";
22 #include <macros.h>
23 #include <exception.h>
24 #include <attributes.h>
25 #include <database.h>
26 //! This module simulates a Mailbox for use with pop3 and imap4
27 //! That is normal sTeam documents are kept inside the Mailbox,
28 //! but Access of them is encapsulated by some functions.
29 class mailbox : public module,binary{
30 public:
31 
32 
33 
34 
35 
36 //Flags stored for each mail, also needed in net/imap.pike !!
37 #define SEEN (1<<0)
38 #define ANSWERED (1<<1)
39 #define FLAGGED (1<<2)
40 #define DELETED (1<<3)
41 #define DRAFT (1<<4)
42 
43 
44  object oMessages;
45 
46  string sServer = _Server->query_config("machine");
47  string sDomain = _Server->query_config("domain");
48  string sFQDN = sServer+"."+sDomain;
49 
50 class MailBox {
51 public:
52  object oMailBox;
53  mapping mMessages = ([ ]);
54  array to_delete;
55 
56  mapping (int:int) mMessageNums=([]);
57 
58 protected:
59  void create(object o) {
60  oMailBox = o;
61  to_delete = ({ });
62  }
63 
64 public:
65 
66  //return flags of message(num)
67  int get_flags(int num)
68  {
69  array inv = oMailBox->get_inventory();
70  int flags=inv[num]->query_attribute(MAIL_IMAPFLAGS);
71  return flags;
72  }
73 
74  //set flags of message(num), overwrite existing flags
75  int set_flags(int num, int flags)
76  {
77  array inv = oMailBox->get_inventory();
78  mixed err = catch { inv[num]->set_attribute(MAIL_IMAPFLAGS,flags); };
79  if (err==0) return inv[num]->query_attribute(MAIL_IMAPFLAGS);
80  else return -1;
81  }
82 
83  //add flags to message(num), keep existing flags
84  int add_flags(int num, int flags)
85  {
86  array inv = oMailBox->get_inventory();
87  int tflags=get_flags(num);
88  tflags = tflags | flags;
89 
90  set_flags(num,tflags);
91  if(!has_flag(num,flags))
92  set_flags(num,flags); //attribute was not set before
93  }
94 
95  //remove given flags from message(num)
96  int del_flags(int num, int flags)
97  {
98  array inv = oMailBox->get_inventory();
99  int tflags=get_flags(num);
100  tflags = tflags & (~flags); //"substract" flags from tflags
101 
102  return set_flags(num,tflags);
103  }
104 
105  //check if a flag is set or not
106  int has_flag(int num,int flag)
107  {
108  return( get_flags(num) & flag );
109  }
110 
111  //returns the internal date of a message
112  int message_internal_date(int num)
113  {
114  array inv = oMailBox->get_inventory();
115  return inv[num]->query_attribute(OBJ_CREATION_TIME);
116  }
117 
118  //get the rfc2822-headers of a message
119  mapping(string:string) message_headers(int num)
120  {
121  array inv = oMailBox->get_inventory();
122 
123  if(zero_type(inv[num]->query_attribute(MAIL_MIMEHEADERS)))
124  add_header(num); //no headers found, create them now
125 
126  return inv[num]->query_attribute(MAIL_MIMEHEADERS);
127  }
128 
129  //check if a message has a rfc822-header
130  int has_header(int num)
131  {
132  array inv = oMailBox->get_inventory();
133  return !zero_type(inv[num]->query_attribute(MAIL_MIMEHEADERS));
134  }
135 
136  //add a rfc822-header to a message
137  void add_header(int num, int|void force)
138  {
139  if(has_header(num) && !force)
140  {
141  LOG("Message #:"+num+" already has rfc822 data - add_header() aborted!");
142  return;
143  }
144 
145  array inv = oMailBox->get_inventory();
146  mapping(string:string) mHeader=([]);
147  string tmp;
148 
149  LOG("creating rfc822-header for msg #"+num);
150  tmp=inv[num]->query_attribute(OBJ_NAME);
151  mHeader+=(["subject":tmp]);
152 
153  tmp=ctime(inv[num]->query_attribute(OBJ_CREATION_TIME))-"\n";
154  mHeader+=(["date":tmp]);
155 
156  tmp=inv[num]->query_attribute(DOC_USER_MODIFIED)->get_identifier();
157  string fullname = inv[num]->query_attribute(DOC_USER_MODIFIED)->query_attribute(USER_FULLNAME);
158  tmp="\""+fullname+"\" <"+tmp+"@"+sFQDN+">";
159  mHeader+=(["from":tmp]);
160 
161  tmp=inv[num]->query_attribute(DOC_MIME_TYPE);
162  mHeader+=(["content-type":tmp]);
163 
164  LOG(sprintf("%O",mHeader));
165  inv[num]->set_attribute(MAIL_MIMEHEADERS,mHeader);
166  LOG("added rfc822-header to msg #"+num);
167  }
168 
169  //returns the body of a message
170  string message_body(int num)
171  {
172  array inv = oMailBox->get_inventory();
173  return inv[num]->get_content();
174  }
175 
176  //converts a sequence of uids to message sequence numbers
177  array uid_to_num(array uids)
178  {
179  array res=({});
180  mapping(int:int) temp=([]);
181  array inv = oMailBox->get_inventory();
182  for(int i=0;i<sizeof(inv);i++)
183  temp+=([inv[i]->get_object_id():i]); //maps uids to sequence numbers
184 
185  foreach(uids, int i)
186  if(zero_type(temp[i])!=1) res+=({temp[i]+1});
187 
188  return res;
189  }
190 
191  mapping(int:int) get_uid2msn_mapping()
192  {
193  array inv = oMailBox->get_inventory();
194  mapping(int:int) temp=([]);
195  for(int i=0;i<sizeof(inv);i++)
196  temp+=([inv[i]->get_object_id():i+1]);
197  return temp;
198  }
199 
200  //logs some statistics for a specific mailbox
201 private:
202  void init_mailbox()
203  {
204  LOG("init_mailbox() ...");
205  array inv = oMailBox->get_inventory();
206  for (int i=0; i<sizeof(inv); i++)
207  {
208  mMessageNums+=([inv[i]->get_object_id():i]);
209  LOG(i+": #"+inv[i]->get_object_id()+", Flags: "+get_flags(i));
210  if(!has_header(i))
211  {
212  LOG("WARNING! Message #"+i+" has no header-data!");
213  add_header(i);
214  }
215  }
216  LOG("init_mailbox() complete");
217  }
218 
219 public:
220 
221  //returns a complete message, needed for pop3
222  object fetch_message(int num)
223  {
224  if ( objectp(mMessages[num]) )
225  return mMessages[num];
226  array inv = oMailBox->get_inventory();
227  mMessages[num] = oMessages->fetch_message(inv[num]);
228  return mMessages[num];
229  }
230 
231  //delete all mails marked by 'delete_message()', only for pop3
232  void cleanup()
233  {
234  foreach(to_delete, object del)
235  del->delete();
236  }
237 
238  //delete all mails flagged 'deleted' (imap4)
239  //all connected imap-clients are notified via event-system
240  void delete_mails()
241  {
242  array inv = oMailBox->get_inventory();
243  for(int i=sizeof(inv)-1;i>=0;i--)
244  {
245  if(has_flag(i,DELETED))
246  {
247  object msg=inv[i];
248  mixed err = catch {
249  _SECURITY->access_delete(0, msg, msg);
250  };
251  if(err==0)
252  {
253  msg->delete();
254  }
255  }
256  }
257  }
258 
259  //returns the number of messages in a mailbox
260  int get_num_messages()
261  {
262  return sizeof(oMailBox->get_inventory());
263  }
264 
265  //size of a message (header + body)
266  int get_message_size(int num)
267  {
268  array inv=oMailBox->get_inventory();
269  mapping(string:string) headers=inv[num]->query_attribute(MAIL_MIMEHEADERS);
270  string dummy="";
271 // if(zero_value(inv[num]->query_attribute(MAIL_MIMEHEADERS))!=1)
272 // {
273  foreach(indices(headers),string key)
274  dummy+=key+": "+headers[key]+"\r\n";
275  dummy+="\r\n";
276 // }
277 
278  return inv[num]->get_content_size() + sizeof(dummy);
279  }
280 
281  //size of a message-body (without header)
282  int get_body_size(int num)
283  {
284  array inv=oMailBox->get_inventory();
285  return inv[num]->get_content_size();
286  }
287 
288  //message id for pop3
289  string get_message_id(int num)
290  {
291  int char_min = 0x21; // 33
292  int char_max = 0x7E; // 126
293  array inv = oMailBox->get_inventory();
294  int id = inv[num]->get_object_id();
295  string binary_str = send_binary(id);
296  return MIME.encode_base64(binary_str);
297  }
298 
299  //message uid for imap4
300  int get_message_uid(int num)
301  {
302  array inv = oMailBox->get_inventory();
303  return inv[num]->get_object_id();
304  }
305 
306  //size of all messages in the mailbox
307  int get_size()
308  {
309  array inv = oMailBox->get_inventory();
310  int sz = 0;
311  for ( int i = sizeof(inv) - 1; i >= 0; i-- ) {
312  sz += get_message_size(i);
313  }
314  return sz;
315  }
316 
317  //mark a message as deletet (only for pop3)
318  bool delete_message(int num)
319  {
320  array inv = oMailBox->get_inventory();
321  object msg = inv[num];
322  mixed err = catch {
323  _SECURITY->access_delete(0, msg, msg);
324  };
325  if ( err != 0 ) {
326  LOG("Error: " + err[0] + "\n"+sprintf("%O", err));
327  }
328  else
329  to_delete += ({ msg });
330  return ( err == 0 );
331  }
332 
333  return oMailBox;
334  }
335 
336  int get_object_id() {
337  return oMailBox->get_object_id();
338  }
339 
340  //returns a message as one string (for pop3)
341 private:
342  string retrieve_message(int num) {
343  object msg = fetch_message(num);
344  return (string)msg;
345  }
346 
347 public:
348 };
349 
350 private:
351 void init_module()
352 {
353  oMessages = _Server->get_module("message");
354  set_attribute(OBJ_DESC, "This module functions as a pop3 and imap4 "+
355  "server for getting the users mailbox content to the mailreader "+
356  "of the user.");
357 }
358 
359 public:
360 
361 object get_mailbox(object user)
362 {
363  object mb = user->query_attribute(USER_MAILBOX);
364  if ( objectp(mb) )
365  return MailBox(mb);
366  return 0;
367 }
368 
369 string get_identifier() { return "mailbox"; }
370 
371 
372 };