1 /* Copyright (C) 2000-2004  Thomas Bopp, Thorsten Hampel, Ludger Merkens
     2  * Copyright (C) 2002       Christian Schmidt
     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.
     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.
    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
    18  * $Id: mailbox.pike,v 1.1 2008/03/31 13:39:57 exodusd Exp $
    20 inherit "/kernel/module";
    21 inherit "/net/coal/binary";
    23 #include <exception.h>
    24 #include <attributes.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{
    36 //Flags stored for each mail, also needed in net/imap.pike !!
    38 #define ANSWERED (1<<1)
    39 #define FLAGGED  (1<<2)
    40 #define DELETED  (1<<3)
    46  string sServer = _Server->query_config("machine");
    47  string sDomain = _Server->query_config("domain");
    48  string sFQDN = sServer+"."+sDomain;
    53     mapping mMessages = ([ ]);
    56     mapping (int:int) mMessageNums=([]);
    59      void create(object o) {
    66     //return flags of message(num)
    67     int get_flags(int num)
    69         array inv = oMailBox->get_inventory();
    70         int flags=inv[num]->query_attribute(MAIL_IMAPFLAGS);
    74     //set flags of message(num), overwrite existing flags
    75     int set_flags(int num, int flags)
    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);
    83     //add flags to message(num), keep existing flags
    84     int add_flags(int num, int flags)
    86         array inv = oMailBox->get_inventory();
    87         int tflags=get_flags(num);
    88         tflags = tflags | flags;
    90         set_flags(num,tflags);
    91         if(!has_flag(num,flags)) 
    92             set_flags(num,flags); //attribute was not set before
    95     //remove given flags from message(num)
    96     int del_flags(int num, int flags)
    98         array inv = oMailBox->get_inventory();
    99         int tflags=get_flags(num);
   100         tflags = tflags & (~flags); //"substract" flags from tflags
   102         return set_flags(num,tflags);
   105     //check if a flag is set or not
   106     int has_flag(int num,int flag)
   108         return( get_flags(num) & flag );
   111     //returns the internal date of a message
   112     int message_internal_date(int num)
   114         array inv = oMailBox->get_inventory();
   115         return inv[num]->query_attribute(OBJ_CREATION_TIME);
   118     //get the rfc2822-headers of a message
   119     mapping(string:string) message_headers(int num)
   121         array inv = oMailBox->get_inventory();
   123         if(zero_type(inv[num]->query_attribute(MAIL_MIMEHEADERS)))
   124             add_header(num); //no headers found, create them now
   126         return inv[num]->query_attribute(MAIL_MIMEHEADERS);
   129     //check if a message has a rfc822-header
   130     int has_header(int num)
   132         array inv = oMailBox->get_inventory();
   133         return !zero_type(inv[num]->query_attribute(MAIL_MIMEHEADERS));
   136     //add a rfc822-header to a message
   137     void add_header(int num, int|void force)
   139         if(has_header(num) && !force)
   141             LOG("Message #:"+num+" already has rfc822 data - add_header() aborted!");
   145         array inv = oMailBox->get_inventory();
   146         mapping(string:string) mHeader=([]);
   149         LOG("creating rfc822-header for msg #"+num);
   150         tmp=inv[num]->query_attribute(OBJ_NAME);
   151         mHeader+=(["subject":tmp]);
   153         tmp=ctime(inv[num]->query_attribute(OBJ_CREATION_TIME))-"\n";
   154         mHeader+=(["date":tmp]);
   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]);
   161         tmp=inv[num]->query_attribute(DOC_MIME_TYPE);
   162         mHeader+=(["content-type":tmp]);
   164         LOG(sprintf("%O",mHeader));
   165         inv[num]->set_attribute(MAIL_MIMEHEADERS,mHeader);
   166         LOG("added rfc822-header to msg #"+num);
   169     //returns the body of a message
   170     string message_body(int num)
   172         array inv = oMailBox->get_inventory();
   173         return inv[num]->get_content();
   176     //converts a sequence of uids to message sequence numbers
   177     array uid_to_num(array uids)
   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
   186             if(zero_type(temp[i])!=1) res+=({temp[i]+1});
   191     mapping(int:int) get_uid2msn_mapping()
   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]);
   200     //logs some statistics for a specific mailbox
   204         LOG("init_mailbox() ...");
   205         array inv = oMailBox->get_inventory();
   206         for (int i=0; i<sizeof(inv); i++)
   208             mMessageNums+=([inv[i]->get_object_id():i]);
   209             LOG(i+": #"+inv[i]->get_object_id()+", Flags: "+get_flags(i));
   212                 LOG("WARNING! Message #"+i+" has no header-data!");
   216         LOG("init_mailbox() complete");
   221     //returns a complete message, needed for pop3
   222     object fetch_message(int num)
   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];
   231     //delete all mails marked by 'delete_message()', only for pop3
   234         foreach(to_delete, object del)
   238     //delete all mails flagged 'deleted' (imap4)
   239     //all connected imap-clients are notified via event-system
   242         array inv = oMailBox->get_inventory();
   243         for(int i=sizeof(inv)-1;i>=0;i--)
   245             if(has_flag(i,DELETED))
   249                     _SECURITY->access_delete(0, msg, msg);
   259     //returns the number of messages in a mailbox
   260     int get_num_messages()
   262         return sizeof(oMailBox->get_inventory());
   265     //size of a message (header + body)
   266     int get_message_size(int num)
   268         array inv=oMailBox->get_inventory();
   269         mapping(string:string) headers=inv[num]->query_attribute(MAIL_MIMEHEADERS);
   271 //        if(zero_value(inv[num]->query_attribute(MAIL_MIMEHEADERS))!=1)
   273             foreach(indices(headers),string key)
   274                 dummy+=key+": "+headers[key]+"\r\n";
   278         return inv[num]->get_content_size() + sizeof(dummy);
   281     //size of a message-body (without header)
   282     int get_body_size(int num)
   284         array inv=oMailBox->get_inventory();
   285         return inv[num]->get_content_size();
   288     //message id for pop3
   289     string get_message_id(int num)
   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);
   299     //message uid for imap4
   300     int get_message_uid(int num)
   302         array inv = oMailBox->get_inventory();
   303         return inv[num]->get_object_id();
   306     //size of all messages in the mailbox
   309         array inv = oMailBox->get_inventory();
   311         for ( int i = sizeof(inv) - 1; i >= 0; i-- ) {
   312             sz += get_message_size(i);
   317     //mark a message as deletet (only for pop3)
   318     bool delete_message(int num)
   320         array inv = oMailBox->get_inventory();
   321         object msg = inv[num];
   323             _SECURITY->access_delete(0, msg, msg);
   326             LOG("Error: " + err[0] + "\n"+sprintf("%O", err));
   329             to_delete += ({ msg });
   336     int get_object_id() {
   337         return oMailBox->get_object_id();
   340     //returns a message as one string (for pop3)
   342     string retrieve_message(int num) {
   343         object msg = fetch_message(num);
   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 "+
   361 object get_mailbox(object user)
   363     object mb = user->query_attribute(USER_MAILBOX);
   369 string get_identifier() { return "mailbox"; }