1
/* Copyright (C) 2004 Christian Schmidt
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation; either version 2 of the License, or
6
* (at your option) any later version.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program; if not, write to the Free Software
15
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* This module is responsible for sending messages to users/groups/... and
20
* e-mails to remote adresses. It also keeps track of system-wide
21
* alias-adresses and of user-forwards.
24
inherit "/kernel/module";
30
#include <attributes.h>
33
//#define DEBUG_FORWARD
36
#define LOG_FORWARD(s, args...) werror("forward: "+s+"\n", args)
41
#if constant(Protocols.SMTP.client)
42
#define SMTPCLIENT Protocols.SMTP.client
44
#define SMTPCLIENT Protocols.SMTP.Client
47
//stores aliases & forwards
48
static mapping(string:array) mAliases, mForwards;
49
static mapping(object:object) mListeners;
54
string get_mask_char() { return "/";}
61
add_data_storage(STORE_FORWARD,retrieve_aliases,restore_aliases);
64
static array|void get_parent_groups(object group)
66
object parent = group->get_parent();
71
parents += ({ parent });
72
array grandparents=get_parent_groups(parent);
73
if(arrayp(grandparents) )
74
parents += grandparents;
78
static array get_user_groups(object user)
81
array usergroups = groups = user->get_groups();
82
foreach(usergroups;; object group)
84
array parents = get_parent_groups(group);
88
return(Array.uniq(groups));
93
add_global_event(EVENT_ADD_MEMBER, user_join_group, PHASE_NOTIFY);
95
LOG_FORWARD("forwards are: %O\n", mForwards);
96
foreach(mForwards; string user;)
98
groups += get_user_groups(MODULE_USERS->lookup(user));
100
groups = Array.uniq(groups);
101
LOG_FORWARD("listen to groups: %O\n", groups->get_identifier());
102
foreach(groups;; object group)
104
listen_annotations(group);
106
// always provide an abuse adress:
107
add_alias( "abuse", "admin" );
110
static void user_join_group(int event, object group, object caller, object user)
112
if(!objectp(mListeners[group]) && mForwards[user->get_user_name()])
113
listen_annotations(group);
116
void listen_annotations(object group)
118
if(!objectp(mListeners[group]))
121
add_event(group->query_attribute(GROUP_WORKROOM),
122
EVENT_ANNOTATE|EVENTS_MONITORED, PHASE_NOTIFY,
123
lambda(int event, mixed ... args)
125
send_annotation_remote(event, group, @args);
130
werror("already listening for %s in %s:\n%O", group->get_identifier(),
131
group->query_attribute(GROUP_WORKROOM)->get_identifier(),
132
mListeners[group]->get_listening());
136
static void send_annotation_remote(int event, object group, object annotated,
137
object caller, object ... thread)
139
// find root of thread...
140
object parent = thread[-1];
141
while ( objectp(parent->get_annotating()) )
143
parent = parent->get_annotating();
146
LOG_FORWARD("send_annotation_remote(event: %d, group: %O, annotated: %O, caller: %O, thread: %s) - parent: %O\n",
147
event, group->get_identifier(), annotated->get_identifier(),
148
caller->get_identifier(), thread->get_identifier()*", ",
149
parent->get_identifier());
151
if(parent==annotated)
152
send_group(group, thread[-1]);
155
void install_module()
157
_mailserver = _Server->query_config(CFG_MAILSERVER);
158
_mailport = (int)_Server->query_config(CFG_MAILPORT);
159
LOG_FORWARD("mailserver is: "+_mailserver+":"+_mailport);
162
string get_identifier() { return "forward"; }
164
mapping get_aliases()
169
array get_alias ( string key ) {
170
if ( arrayp(mAliases[key]) )
171
return copy_value( mAliases[key] );
176
mapping retrieve_aliases()
178
if ( CALLER != _Database )
179
THROW("Caller is not database !", E_ACCESS);
181
return (["aliases" : mAliases, "forwards" : mForwards]);
184
void restore_aliases(mapping data)
186
if ( CALLER != _Database )
187
THROW("Caller is not database !", E_ACCESS);
189
mAliases=data["aliases"];
190
mForwards=data["forwards"];
192
LOG_FORWARD("loaded "+sizeof(mAliases)+" aliases and "
193
+sizeof(mForwards)+" forwards");
197
* check if an address is valid
199
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
200
* @param string address - the address to check
201
* @return int 1 if valid, 0 if invalid, -1 if access denied
203
int is_valid(string address)
205
LOG_FORWARD("checking adress \"%O\"",address);
206
LOG_FORWARD("alias...");
207
if(arrayp(mAliases[address]))
208
return 1; //adress is alias
209
LOG_FORWARD("no - trying user...");
210
if(objectp(MODULE_USERS->lookup(address)))
211
return 1; //address is single user
212
LOG_FORWARD("no - trying group...");
213
if ( address == "steam" )
214
return 0; // no mailing to steam-group allowed
215
if(objectp(MODULE_GROUPS->lookup(address)))
216
return 1; //adress is a group
217
LOG_FORWARD("no - trying to replace - with space...");
218
if(objectp(MODULE_GROUPS->lookup(replace(address, "-", " "))))
219
return 1; //adress is a group
220
LOG_FORWARD("no - trying object-id...");
221
if(sscanf(address,"%d",int oid))
223
LOG_FORWARD("looking for object #%O",oid);
224
object tmp=_Database->find_object(oid);
227
LOG_FORWARD("checking access on object #%O",oid);
228
mixed err = catch { _SECURITY->access_annotate(0, tmp, CALLER, 0); };
229
if(err!=0) return -1; //access denied -> invalid target-address
230
else return 1; //target is existing object & annotatable
232
else LOG_FORWARD("not found");
234
LOG_FORWARD("sorry - no valid target found!");
236
return 0; //no checks succeeded, target address is invalid
240
* return the remote addresses within an array of mixed addresses
242
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
243
* @param array(string) names - the addresses to get remotes from
244
* @return array(string) the remote adresses
246
private array(string) get_remote_addresses(array(string) names)
248
array(string) result=({});
249
for(int i=0;i<sizeof(names);i++)
250
if(search(names[i],"@")!=-1)
251
result+=({names[i]});
255
string resolve_name(object grp)
257
if ( objectp(grp) ) {
258
if ( grp->get_object_class() & CLASS_USER )
259
return grp->get_user_name();
260
return grp->get_identifier();
266
* split targets into remote, groups, users, and objects
268
* @author Martin B�hr
269
* @param array(string) names - the addresses to work with
270
* @return mapping - containing the different recipient types
272
private mapping resolve_recipients(array(string) names)
274
array unresolved=({});
275
array(string) resolved=replace_aliases(names);
276
resolved=replace_forwards(resolved);
278
mapping result =([ "groups":({}), "remote":({}), "users":({}),
283
foreach(resolved;; string target)
285
if ( !stringp(target) )
287
if(search(target,"@")!=-1)
288
result->remote += ({ target });
289
else if ( objectp(target_obj=MODULE_GROUPS->lookup(target)) )
290
result->groups += ({ target_obj });
291
// groupnames may have spaces, but those don't work well with email.
292
else if ( objectp(target_obj=MODULE_GROUPS->lookup(replace(target, "-", " "))) )
293
result->groups += ({ target_obj });
294
else if ( objectp(target_obj=MODULE_USERS->lookup(target)) )
295
result->users += ({ target_obj });
296
else if ( sscanf(target,"%d",oid)
297
&& objectp(target_obj=_Database->find_object(oid)) )
298
result->objects += ({ target_obj });
300
unresolved += ({ target });
303
if(sizeof(unresolved))
304
FATAL("Warning! unresolved addresses: %O", unresolved);
309
* within an array of adresses, search for aliases and replace them with
312
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
313
* @param array(string) names - the addresses to work with
314
* @return array(string) the input-array with aliases replaced by targets
316
private array(string) replace_aliases(array(string) names)
318
array(string) result=({});
319
foreach(names;; string name)
321
if(arrayp(mAliases[name])) //add code for checking aliases on aliases here...
322
result+=mAliases[name];
326
return Array.uniq(result);
331
* within an array of adresses, search for forwards and replace them with
334
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
335
* @param array(string) names - the addresses to work with
336
* @return array(string) the input-array with forwards replaced by targets
338
private array(string) replace_forwards(array(string) names, void|mapping fwd_done)
340
array(string) result=({});
342
if ( !mappingp(fwd_done) )
345
for(int i=0;i<sizeof(names);i++)
347
if ( fwd_done[names[i]] )
349
if(arrayp(mForwards[names[i]]))
351
array(string) tmp=mForwards[names[i]];
352
for(int j=0;j<sizeof(tmp);j++)
354
if ( !stringp(tmp[j]) )
357
fwd_done[tmp[j]] = 1;
358
if(search(tmp[j],"@")!=-1) //remote address
362
if(search(tmp[j],"/")!=-1) //local forward-target starts with "/" -> don't forward further
363
result+=({tmp[j]-"/"});
364
else //lookup forward of this forward-target
366
array(string) tmp2=replace_aliases( ({tmp[j]}) );
367
result+=replace_forwards(tmp2, fwd_done);
372
else result+=({names[i]});
378
* send a message to multiple recipients
380
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
381
* @param array(string) target - the addresses to send the message to
382
* @param Message msg - the message to send (WARNING msg is destructed by sending!)
383
* @return int 1 if successful
385
int send_message(array(string) target, Messaging.Message msg)
388
string rawText=msg->complete_text();
389
string sSender=msg->sender();
390
array(string) resolved=replace_aliases(target);
391
resolved=replace_forwards(resolved);
392
array(string) asRemote=get_remote_addresses(resolved);
394
array(string) asLocal=resolved-asRemote;
395
if(sizeof(asLocal)>0) hasLocal=1;
397
send_local(asLocal,msg);
401
LOG_FORWARD("Sending to " + sizeof(asRemote) + " Remote Recipients !");
403
asRemote = Array.uniq(asRemote);
404
send_remote(asRemote, rawText, sSender);
406
for(int i=0;i<sizeof(asRemote);i++)
407
send_remote(asRemote[i],rawText,sSender);
409
return 1; //success, add code for failures!
413
* send a message (rfc2822 raw text) to multiple recipients
415
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
416
* @param array(string) target - the addresses to send the message to
417
* @param string rawText - the text of the message (rfc2822-format!)
418
* @param string|void envFrom - the sender-value of the SMTP-envelope (only needed for forwarding, may be left empty)
419
* @return int 1 if successful
421
int send_message_raw(array(string) target, string rawText, string envFrom)
424
LOG_FORWARD("Forward: send_message_raw(%O)", target);
425
mapping sendAs = resolve_recipients(target);
427
if(sizeof(sendAs->users))
428
err = catch(res=send_users(sendAs->users,Messaging.MIME2Message(rawText)));
430
FATAL("Error while sending message to users: %O, %O", err[0], err[1]);
432
LOG_FORWARD("Warning! send_message_raw failed on one ore more recipient users!");
435
if(sizeof(sendAs->objects))
436
err = catch(res=send_objects(sendAs->objects,Messaging.MIME2Message(rawText)));
438
FATAL("Error while sending message to objects: %O,%O", err[0], err[1]);
441
LOG_FORWARD("Warning! send_message_raw failed on one ore more recipient objects!");
443
send_remote(sendAs->remote, rawText, envFrom);
444
foreach(sendAs->groups;; object target)
445
send_group(target,rawText,envFrom);
451
* send a message to objects
453
* @author Martin B�hr
454
* @param array(object) targets - the objects to send the message to
455
* @param string msg - the message to send
456
* @return int 1 if successful
458
private int send_objects(array(object) targets, Messaging.Message msg)
460
LOG_FORWARD("send_objects(%O, %O)\n", targets, msg->header()->subject);
461
if(sizeof(targets)==0 || !arrayp(targets)) return 0;
465
seteuid(USER("root"));
466
foreach(targets; int count; object target)
468
Messaging.Message copy;
469
if(count<sizeof(targets)-1)
470
// duplicate message if more than one recipient
471
copy=msg->duplicate();
473
// last recipient gets original
476
mixed err=catch{Messaging.add_message_to_object(copy,target);};
482
FATAL("unable to add message to: %s(%d):%O", target->get_identifier(), target->get_object_id(), err);
488
LOG_FORWARD("Warning!! send_objects encountered errors - some recipients failed!");
496
* send a message to users
498
* @author Martin B�hr
499
* @param array(object) users - the users to send the message to
500
* @param string msg - the message to send
501
* @return int 1 if successful
503
private int send_users(array(object) targets, Messaging.Message msg)
505
if(sizeof(targets)==0 || !arrayp(targets)) return 0;
507
foreach(targets; int count; object user)
509
if ( !objectp(user) )
511
Messaging.Message copy=msg->duplicate();
512
if(count<sizeof(targets)-1)
513
// duplicate message if more than one recipient
514
copy=msg->duplicate();
516
// last recipient gets original
519
//the recipient gets all rights on his/her copy
520
copy->grant_access(user);
522
Messaging.BaseMailBox box = Messaging.get_mailbox(user);
523
copy->this()->set_acquire(box->this());
524
box->add_message(copy);
532
* create headers to be added to annotations sent as mails
534
* @author Martin B�hr
535
* @param object group - the group to send the message to
536
* @return mapping of headers
538
mapping create_list_headers(object group)
540
mapping headers = ([]);
541
headers["X-Steam-Group"] = group->get_identifier();
542
headers["List-Id"] = replace(group->get_identifier(), " ", "-")+"@"+
543
(_Server->query_config("smtp_host")||(_Server->query_config("machine")+"."+_Server->query_config("domain")));
545
object group_workroom = group->query_attribute("GROUP_WORKROOM");
546
object modpath=get_module("filepath:tree");
547
headers["X-Steam-Path"] = _Server->query_config("web_server")+
548
modpath->object_to_filename(group_workroom);
550
headers["X-Steam-Annotates"] = _Server->query_config("web_server")+":"
551
+(string)group_workroom->get_object_id();
556
* send a message to a group
558
* @author Martin B�hr
559
* @param object group - the group to send the message to
560
* @param string|object msg - the message to send
561
* @return int 1 if successful
563
private int send_group(object group, string|object msg, string|void envFrom)
565
LOG_FORWARD("send_group(%O)\n", group);
566
mapping headers = create_list_headers(group);
571
rawmessage = (((array)headers)[*]*": ")*"\r\n" + "\r\n" + msg;
572
messageobj = Messaging.MIME2Message(rawmessage);
574
//string messages come from outside, need to be added to group
575
send_objects( ({ group->query_attribute(GROUP_WORKROOM) }), messageobj);
577
else if(objectp(msg))
579
messageobj = Messaging.Message(msg);
581
envFrom = "<"+messageobj->sender()+">";
582
LOG_FORWARD("sender is: %O\n", messageobj->sender());
583
messageobj->add_to_header(headers);
584
messageobj->add_to_header(([ "to":headers["List-Id"] ]));
585
rawmessage = (string)messageobj->mime_message();
589
FATAL("Warning! unknown message format: %O", msg);
593
//TODO: only send to users that want a copy of group mails
594
array(string) members = group->get_members_recursive(CLASS_USER)->get_user_name();
595
send_message_raw(members, rawmessage, envFrom);
601
* send a message to a subgroup
603
* @author Martin B�hr
604
* @param object group - the group to send the message to
605
* @param object parent - the group that the message was initially sent to
606
* @param string msg - the message to send
607
* @return int 1 if successful
609
private int send_subgroup(object group, object parent, string msg, string envFrom)
611
mapping headers = ([]);
612
headers["X-sTeam-Subgroup"] = group->get_identifier();
613
msg = (((array)headers)[*]*": ")*"\r\n" + "\r\n" + msg;
615
//TODO: only send to users that want a copy of group mails
616
array(string) members = group->get_members(CLASS_USER)->get_user_name();
617
send_message_raw(members, msg, envFrom);
619
array subgroups = group->get_sub_groups();
620
foreach(subgroups;; object subgroup)
621
send_subgroup(subgroup, parent, msg, envFrom);
626
* send a simple message (subject & text) to multiple recipients
628
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
629
* @param array(string) target - the addresses to send the message to
630
* @param string subject - the subject of the message to send
631
* @param string message - the text of the message to send
632
* @return int 1 if successful
634
int send_message_simple(array(string) target, string subject, string message)
637
Messaging.Message msg = Messaging.SimpleMessage(target, subject, message);
638
string rawText=msg->complete_text();
639
string sSender=msg->sender();
640
array(string) resolved=replace_aliases(target);
641
resolved=replace_forwards(resolved);
642
array(string) asRemote=get_remote_addresses(resolved);
643
array(string) asLocal=resolved-asRemote;
644
if(sizeof(asLocal)>0) hasLocal=1;
646
send_local(asLocal,msg);
649
asRemote = Array.uniq(asRemote);
650
send_remote(asRemote, rawText, sSender);
652
for(int i=0;i<sizeof(asRemote);i++)
653
send_remote(asRemote[i],rawText,sSender);
655
return 1; //success, add code for failures!
659
* replace group-entries with members of group
660
* object ids included in input are not changed by this
662
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
663
* @param array(string) target - the addresses to replace groups in
664
* @return array(string) input-array with groups replaced by members of groups
666
private array(string) expand_local_addresses(array(string) target)
668
array(string) result=({});
669
for(int i=0;i<sizeof(target);i++)
671
if(objectp(MODULE_USERS->lookup(target[i])))
673
result+=({target[i]});
676
// FIXME: this is dead code! all groups should have been removed by now.
677
object tmp=MODULE_GROUPS->lookup(target[i]);
680
result+=tmp->get_members();
683
if(sscanf(target[i],"%d",int oid))
685
result+=({target[i]});
688
LOG_FORWARD("expand_local_addresses: failed to find \""+target[i]+"\"");
690
return result; //now contains only user-names and object-ids
693
private int send_local_single(string recipient, Messaging.Message msg)
696
if(!sscanf(recipient,"%d",oid)==1)
698
object user=MODULE_USERS->lookup(recipient);
699
Messaging.BaseMailBox box = Messaging.get_mailbox(user);
700
msg->grant_access(user); //the recipient gets all rights on his/her copy
701
msg->this()->set_acquire(box->this());
702
box->add_message(msg);
704
else //store message on object
706
object target=_Database->find_object(oid);
707
if(!objectp(target)) return 0; //invalid object-id, do nothing
708
// msg->grant_access(target->query_attribute(OBJ_OWNER));
709
msg->this()->set_acquire(target);
710
Messaging.BaseMailBox box = Messaging.get_mailbox(target);
711
if(objectp(box)) //target can be accessed as mailbox
712
box->add_message(msg);
714
Messaging.add_message_to_object(msg,target);
719
* send a message to local recipients
721
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
722
* @param array(string) target - the local addresses to send the message to
723
* @param Message msg - the message to send (WARNING msg is destructed by sending!)
724
* @return int 1 if successful
726
private int send_local(array(string) target, Messaging.Message msg)
728
if(sizeof(target)==0 || !arrayp(target)) return 0;
730
int result=1; //success
732
// FIXME: expand_local_addresses should not be needed anymore:
733
array(string) asLocal=expand_local_addresses(target); //resolve aliases & forwards
734
LOG_FORWARD("expanded local adresses are:%O",asLocal);
736
for(int i=sizeof(asLocal)-1;i>0;i--) //duplicate message if more than one recipient
738
Messaging.Message copy=msg->duplicate();
739
if(send_local_single(asLocal[i],copy)==0)
741
LOG_FORWARD("failed to send message #"+copy->get_object_id()+" to: "+asLocal[i]);
747
if(send_local_single(asLocal[0],msg)==0) //last recipient gets "original" message
749
LOG_FORWARD("failed to send message #"+msg->get_object_id()+" to: "+asLocal[0]);
755
if(result==0) LOG_FORWARD("Warning!! send_local encountered errors - some recipients failed!");
761
* send a message to a remote address (-> send e-mail)
763
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
764
* @param string address - the address to send the mail to
765
* @param string rawText - the text of the message (rfc2822-format!)
766
* @param string|void envFrom - the sender-value of the SMTP-envelope
767
* @return int 1 if successful, 0 if not
769
private int send_remote(string|array address, string rawText, string envFrom)
772
if( arrayp(address) && sizeof(address)==0 ) return 1;
773
if( stringp(address) && strlen(address) == 0 ) return 1;
775
if( sscanf(envFrom,"%*s<%s>",fixed) == 0 )
777
LOG_FORWARD("send_remote: illegal envFrom! : "+envFrom);
781
if ( arrayp(address) && (l=sizeof(address)) > 10 ) {
782
for ( int i = 0; i < sizeof(address); i+=10 ) {
785
users = address[i..];
787
users = address[i..i+9];
788
get_module("smtp")->send_mail_raw(users, rawText, fixed);
789
LOG_FORWARD("Message chunked delivered to "+sprintf("%O", users));
793
get_module("smtp")->send_mail_raw(address, rawText, fixed);
794
LOG_FORWARD("Message delivered to " + sprintf("%O", address));
801
* Adds an alias to the system-aliases.
802
* If an alias with the given name already exists, the alias
803
* will point to a list of targets. The target will be added to the
804
* alias if it hasn't been added before. If you want to replace an alias
805
* completely, you'll have to delete it first.
807
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
808
* @param string alias - the name of the alias to add
809
* @param string taget - the target the alias should point to
810
* @return 1 if successful
813
int add_alias(string alias, string target)
815
if ( (arrayp(mAliases[alias]) && search(mAliases[alias], target)>=0) )
816
return 1; // target was already set for that alias
818
if ( !arrayp(mAliases[alias]) )
819
mAliases[alias] = ({ });
821
mAliases[alias]+=({target});
827
* remove an alias from the system aliases
829
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
830
* @param string alias - the alias to delete
831
* @return 1 if successful, 0 if alias does not exist
834
int delete_alias(string alias)
836
if(arrayp(mAliases[alias]))
838
m_delete(mAliases,alias);
846
* add a forward for a specific user
847
* if user already has a forward, it is extended by the given target
848
* target may be a remote e-mail address or a local system address
849
* (user, group, object-id, alias)
851
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
852
* @param object user - the user to add a forward for
853
* @param string forward - the target address to add (e-mail or other valid system-address)
854
* @param int|void no_more - set to 1, if this forward is "final", so mails get stored at this adress,
855
* no matter if a forward exists for this target, too
856
* @return int 1 if successful, 0 if not
858
int add_forward(object user, string forward, int|void no_more)
860
LOG_FORWARD("adding forward for %s:%s", user->get_user_name(), forward);
861
if ( ! stringp(forward) ) {
862
LOG_FORWARD("invalid forward: %O", forward);
866
if(intp(no_more) && no_more==1) forward="/"+forward;
867
if(user->get_object_class() && CLASS_USER)
869
string name=user->get_identifier();
870
if ( forward == name )
871
steam_error("add_forward: Unable to resolve forward to itself !");
873
if(!mForwards[name]) //new user may be in groups we are not listening to
875
foreach(get_user_groups(user);; object group)
877
if(!mListeners[group])
878
listen_annotations(group);
882
if ( mForwards[name] && search( mForwards[name], forward ) >= 0 ) {
883
LOG_FORWARD("add_forward(%s : %s) : forward already exists",
885
return 0; // forward already exists
887
mForwards[name]+=({forward});
893
LOG_FORWARD("ERROR, add_forward() called for non-user object #"
894
+user->get_object_id());
900
* remove a user-forward
902
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
903
* @param object user - the user to remove forwarding for
904
* @param forward - the forward to remove (if not specified, all forwards
905
* for that user will be removed)
906
* @return int 1 if successful, 0 otherwise
908
int delete_forward(object user, void|string forward)
910
if ( ! objectp(user) || !(user->get_object_class() && CLASS_USER) ) {
911
LOG_FORWARD("delete_forward: invalid user %O", user);
915
string name = user->get_identifier();
916
if ( ! arrayp(mForwards[name] ) ) {
917
LOG_FORWARD("delete_forward: user %s has no forwards", name);
918
return 0; // no forwards for this user
921
if ( zero_type(forward) ) { // delete all forwards for user
922
LOG_FORWARD("deleting forwards for %s", name);
923
m_delete(mForwards,name);
925
else { // delete single forward
926
LOG_FORWARD("deleting forward %O for %s", forward, name);
927
if ( search( mForwards[name], forward ) < 0 ) {
928
LOG_FORWARD("forward %O not found for %s", forward, name);
931
mForwards[name] -= ({ forward });
938
* get the current forward for a user
940
* @author <a href="mailto:sepp@upb.de">Christian Schmidt</a>
941
* @param object user - the user to get forward for
942
* @return array(string) of forwards or 0 if user is not a sTeam-user-object
944
array(string) get_forward(object user)
946
if(user->get_object_class() & CLASS_USER)
947
return mForwards[user->get_identifier()];
955
res=sprintf("forwards:%O aliases:%O",mForwards,mAliases);
956
LOG_FORWARD("current data of forward-module:\n"+res);
957
LOG_FORWARD("mailserver is: "+_mailserver+":"+_mailport);