File Coverage

blib/lib/GMail/IMAPD.pm
Criterion Covered Total %
statement 18 388 4.6
branch 0 148 0.0
condition 0 19 0.0
subroutine 6 46 13.0
pod 2 39 5.1
total 26 640 4.0


line stmt bran cond sub pod time code
1             package GMail::IMAPD;
2              
3 1     1   12981 use IO::Socket;
  1         23555  
  1         4  
4 1     1   1233 use IO::File;
  1         2244  
  1         143  
5 1     1   1156 use Mail::Webmail::Gmail;
  1         173280  
  1         73  
6 1     1   9 use strict;
  1         1  
  1         499  
7              
8             our $VERSION = "0.94";
9              
10             our @ISA = qw(Exporter);
11             our @EXPORT_OK = ();
12             our @EXPORT = ();
13              
14              
15             our @COMMANDS=qw(APPEND AUTHENTICATE CAPABILITY CHECK CLOSE COPY CREATE
16             DELETE EXPUNGE FETCH IDLE LIST LOGIN LOGOUT LSUB NAMESPACE
17             NOOP RENAME SELECT STATUS STORE SUBSCRIBE UNSUBSCRIBE);
18              
19             our @FOLDERS=('INBOX', 'All', 'Starred', 'Sent', 'Spam','Trash');
20              
21             sub new {
22 0     0 1   my($class, %args) = @_;
23 0 0 0       my $self = {
      0        
      0        
24             LocalAddr => $args{LocalAddr} || '0.0.0.0',
25             LocalPort => $args{LocalPort} || 143,
26             Debug => $args{Debug} || 0,
27             Detach => defined $args{Detach} ? $args{Detach} : 1,
28             LogFile => $args{LogFile},
29             CacheDBH => $args{CacheDBH},
30             Socket => $args{Socket},
31             Peer => undef,
32             Gmail => {},
33             User => '',
34             Folders => [],
35             SelFolder => '',
36             Msgs => undef,
37             UIDList => undef,
38             CopyFolder => '',
39             CmdID => '',
40             CmdArgs => '',
41             Cache => undef,
42             };
43 0           bless($self, $class);
44 0           return $self;
45             }
46              
47 0     0 0   sub run { my($self)=@_;
48 0 0         if($self->{Detach}){
49 0           close(STDIN); close(STDERR); close(STDOUT);
  0            
  0            
50 0 0         fork && exit;
51             }
52            
53 0           $self->logit("Starting daemon");
54              
55 0           $SIG{CHLD}='IGNORE';
56            
57 0   0       my $l=IO::Socket::INET->new(Listen=>5,
58             LocalPort=>$self->{LocalPort},
59             LocalAddr=>$self->{LocalAddr},
60             Reuse=>1) || die("Socket: $!");
61              
62 0           my $s;
63 0           for(;;close($s)){ $s=$l->accept();
  0            
64 0 0         if(!fork){
65 0 0         exit unless defined $s;
66 0           $self->{Socket} = $s;
67 0           $self->{Peer} = $s->peerhost;
68 0           $self->logit("Connect");
69 0           $self->procimap();
70 0           close($s); exit;
  0            
71             }
72             }
73             }
74              
75 0     0 1   sub procimap { my($self)=@_;
76 1     1   5 no strict 'refs';
  1         2  
  1         5707  
77 0           $self->writesock('* OK localhost IMAP4rev1 v11.237 server ready');
78 0           for(;;){
79 0           my($cmdid,$cmd,$args)=split(' ',$self->readsock(),3);
80 0 0         if(uc($cmd) eq 'UID'){
81 0           ($cmd,$args)=split(' ',$args,2);
82 0           $args.=' UID';
83             }
84 0           $cmd=uc($cmd);
85 0   0       $cmdid = $cmdid || '*';
86 0 0         if($cmd eq 'LOGOUT'){
87 0           $self->logit("LOGOUT '$self->{User}'");
88 0           $self->writesock("* BYE Logging out");
89 0           $self->writesock("$cmdid OK Logout completed.");
90 0 0         untie %{$self->{Cache}} if $self->{CacheDBH};
  0            
91 0           return;
92             }
93              
94 0 0         if(grep(/^$cmd$/,@COMMANDS)){
95 0           $self->{CmdID} = $cmdid;
96 0           $self->{CmdArgs} = $args;
97 0           &{"cmd_$cmd"}($self);
  0            
98             }
99             else{
100 0           $self->writesock("$cmdid BAD $cmd unknown");
101             }
102             }
103             }
104              
105 0     0 0   sub cmd_APPEND { my($self)=@_;
106 0           my($mbox,@args)=$self->parseargs($self->{CmdArgs});
107 0           $self->writesock("+ Ready for data");
108 0           my $dlength=$args[-1]; $dlength=~s/\D+//g;
  0            
109 0           my $buf;
110 0           while(length($buf) <= $dlength){ $buf.=$self->readsock('raw') }
  0            
111            
112 0           $self->sendemail('imap2gmail',$self->{User}. '@gmail.com',$buf);
113            
114 0 0         if($mbox eq 'INBOX'){
115 0           $self->writesock("$self->{CmdID} OK Append completed.");
116             }
117             else{
118 0           $self->writesock("$self->{CmdID} BAD Warning: Messages Appended to Inbox");
119             }
120             }
121              
122 0     0 0   sub cmd_AUTHENTICATE { my($self)=@_;
123 0           $self->writesock("+\r\n");
124 0           my($junk,$user,$pass)=split(/\0/,$self->mdecode($self->readsock()));
125 0           $self->{CmdArgs}="$user $pass";
126 0           $self->cmd_LOGIN();
127             }
128              
129 0     0 0   sub cmd_CAPABILITY { my($self)=@_;
130 0           $self->writesock("* CAPABILITY IMAP4rev1 AUTH=PLAIN");
131 0           $self->writesock("$self->{CmdID} OK Capability completed.");
132             }
133              
134 0     0 0   sub cmd_CHECK { my($self)=@_;
135 0           $self->writesock("$self->{CmdID} OK Check completed.");
136             }
137              
138 0     0 0   sub cmd_CLOSE { my($self)=@_;
139 0           $self->writesock("$self->{CmdID} OK Close completed.");
140             }
141              
142 0     0 0   sub cmd_COPY { my($self)=@_;
143 0           my($msglist,$args)=split(/\s+/,$self->{CmdArgs},2);
144 0 0         my $useuid = 1 if $args=~s/\s*UID$//;
145 0           my $folder=$args;
146 0           $folder=~s/"//g;
147            
148 0           my @msgs=@{$self->msgrange($useuid,$msglist)};
  0            
149 0           my @msgids=map($_->{id},@msgs);
150 0           $self->{CopyFolder}=$folder;
151              
152 0 0         if($folder eq 'INBOX'){
    0          
    0          
    0          
153 0           $self->logit("COPY: edit_archive(action =>'unarchive')",1);
154 0           $self->{Gmail}->edit_archive(action =>'unarchive','msgid'=>\@msgids);
155             }
156             elsif($folder eq 'Trash'){
157 0           $self->logit("COPY: delete_message (move to trash)",1);
158 0 0         if($self->{SelFolder} eq 'Spam'){
159 0           $self->{Gmail}->delete_message(msgid=>\@msgids, del_message=>0,
160             search =>'spam');
161             }
162             else{
163 0           $self->{Gmail}->delete_message(msgid=>\@msgids, del_message=>0);
164             }
165             }
166             elsif($folder eq 'All'){
167 0           $self->logit("COPY: edit_archive(action =>'archive')",1);
168 0           $self->{Gmail}->edit_archive(action =>'archive','msgid'=>\@msgids);
169             }
170             elsif($folder eq 'Starred'){
171 0           $self->logit("COPY: edit_star(action => 'add')",1);
172 0           map($self->{Gmail}->edit_star( action => 'add','msgid' => $_),@msgids);
173             }
174              
175             else{
176 0           $self->logit("COPY: edit_labels(label=> $folder)",1);
177 0           $self->{Gmail}->edit_labels(label=> $folder,action=>'add',msgid =>\@msgids);
178 0 0         if($self->{SelFolder} eq 'INBOX'){
179 0           $self->logit("COPY: edit_archive(action =>'archive')",1);
180 0           $self->{Gmail}->edit_archive(action =>'archive','msgid'=>\@msgids)
181             }
182             }
183 0           map(delete $self->{UIDList}->{$_},@msgids);
184 0           $self->writesock("$self->{CmdID} OK Copy completed.");
185             }
186              
187 0     0 0   sub cmd_CREATE { my($self)=@_;
188 0           my($folder)=$self->parseargs($self->{CmdArgs});
189 0           $self->{Gmail}->edit_labels( label => $folder, action => 'create' );
190 0           push(@{$self->{Folders}},$folder);
  0            
191 0           $self->writesock("$self->{CmdID} OK Create completed.");
192             }
193              
194 0     0 0   sub cmd_DELETE { my($self)=@_;
195 0           my($folder)=$self->parseargs($self->{CmdArgs});
196 0           $self->{Gmail}->edit_labels( label => $folder, action => 'delete' );
197 0           $self->{Folders}=[grep !/$folder/,@{$self->{Folders}}];
  0            
198 0           $self->writesock("$self->{CmdID} OK Delete completed.");
199             }
200              
201 0     0 0   sub cmd_EXPUNGE { my($self)=@_;
202 0           for my $msg (@{$self->{Msgs}}){
  0            
203 0 0 0       if($msg->{Flags} && $msg->{Flags}=~/Deleted/){
204 0           $self->writesock("* $msg->{n} EXPUNGE");
205             }
206             }
207 0           $self->writesock("$self->{CmdID} OK Expunge completed.");
208             }
209              
210 0     0 0   sub cmd_FETCH { my($self)=@_;
211 0           my($msglist,$args)=split(/\s+/,$self->{CmdArgs},2);
212 0           my $useuid=0; my @msgparts=();
  0            
213 0 0         if($args=~s/UID$//){
214 0           $useuid = 1;
215 0           push(@msgparts,'UID');
216 0           $args=~s/UID//g;
217             }
218              
219 0           for my $ent ('UID','FLAGS','ENVELOPE','INTERNALDATE',
220             'RFC822\S*','BODY[^\[]*\[[^\]]*\]'){
221 0           while($args=~s/($ent)//i){ push(@msgparts,uc($1)) }
  0            
222             }
223 0           for my $msg (@{$self->msgrange($useuid,$msglist)}){
  0            
224 0           my @resp=();
225 0           for my $part (@msgparts){
226 0 0         if($part eq 'UID'){
    0          
227 0           push(@resp,'UID ' . $msg->{uid});
228             }
229             elsif($part eq 'FLAGS'){
230 0 0         push(@resp,'FLAGS (' . ($msg->{new} ? '\Recent' : '\Seen') . ')');
231             }
232             else{
233 0           my $mime=$self->cache_get_mime_email($msg);
234 0           my $head=$self->get_header($mime);
235 0 0         if($part eq 'ENVELOPE'){
236 0           push(@resp,'ENVELOPE (' . $self->get_envelope($head) . ')' );
237             }
238 0 0         if($part eq 'INTERNALDATE'){
    0          
239 0           push(@resp,'INTERNALDATE "' . $self->get_internaldate($head) . '"');
240             }
241             elsif($part=~/^(RFC822|BODY)/){
242 0           $part=~s/\.PEEK//;
243 0 0         if($part=~/SIZE/){
    0          
244 0           push(@resp,"$part " . length($mime));
245             }
246             elsif($part=~/HEADER/){
247 0           push(@resp,"$part {" . length($head) . "}\r\n$head");
248             }
249             else{
250 0           push(@resp,"$part {" . length($mime) . "}\r\n$mime");
251             }
252             }
253             }
254              
255             }
256 0           $self->writesock("* $msg->{n} FETCH (@resp)");
257             }
258 0           $self->writesock("$self->{CmdID} OK Fetch completed.");
259             }
260              
261 0     0 0   sub cmd_IDLE { my($self)=@_;
262 0           $self->writesock("+ idling");
263 0           $self->readsock();
264 0           $self->writesock("$self->{CmdID} OK Idle completed.");
265             }
266              
267 0     0 0   sub cmd_LIST { my($self)=@_;
268 0           map($self->writesock("* LIST () \"/\" $_"),
269 0 0         map($_ eq 'INBOX' ? $_ : "\"$_\"",@{$self->{Folders}}));
270 0           $self->writesock("$self->{CmdID} OK List completed.")
271             }
272              
273 0     0 0   sub cmd_LOGIN { my($self)=@_;
274 0           $self->{CmdArgs}=~s/\"//g;
275 0           my($user,$pass)=split(/\s+/,$self->{CmdArgs});
276 0           $self->logit("LOGIN '$user'");
277 0           $self->{Gmail}=Mail::Webmail::Gmail->new(username => $user,
278             password => $pass,
279             timeout => 10,
280             cookies => {});
281 0           my $res=$self->{Gmail}->login;
282 0 0         if($res == -1){
    0          
283 0           $self->writesock("$self->{CmdID} NO Authentication failed.");
284             }
285             elsif($res == 0){
286 0           $self->logit("cmd_LOGIN: gmail error: " . $self->{Gmail}->error_msg);
287 0           $self->writesock("$self->{CmdID} NO Gmail error.");
288             }
289             else{
290 0           $self->{User}=$user;
291 0           $self->{Folders}=[@FOLDERS,$self->{Gmail}->get_labels()];
292 0 0         if($self->{CacheDBH}){
293 0           require Tie::RDBM;
294 0           $self->logit("tieing cache to table $user",1);
295 0           tie %{$self->{Cache}},'Tie::RDBM',
  0            
296             {db=>$self->{CacheDBH},table=>$user,create=>1};
297 0           $self->{Cache}->{'seed'}=1; #create table
298             }
299 0           $self->writesock("$self->{CmdID} OK Logged in.");
300             }
301             }
302              
303 0     0 0   sub cmd_LSUB { my($self)=@_;
304 0           map($self->writesock("* LSUB () \"/\" $_"),
305 0 0         map($_ eq 'INBOX' ? $_ : "\"$_\"",@{$self->{Folders}}));
306 0           $self->writesock("$self->{CmdID} OK Lsub completed.");
307             }
308              
309 0     0 0   sub cmd_NAMESPACE { my($self)=@_;
310 0           $self->writesock('* NAMESPACE (("" "/")) NIL NIL');
311 0           $self->writesock("$self->{CmdID} OK Namespace completed.");
312             }
313              
314 0     0 0   sub cmd_NOOP { my($self)=@_;
315 0           $self->fetchmsgs();
316 0           $self->writesock("* $self->{ExistMsgs} EXISTS");
317 0           $self->writesock("* $self->{RecentMsgs} RECENT");
318 0           $self->writesock("$self->{CmdID} OK NOOP completed.");
319             }
320              
321 0     0 0   sub cmd_RENAME { my($self)=@_;
322 0           my($old,$new)=$self->parseargs($self->{CmdArgs});
323 0           $self->{Gmail}->edit_labels( label => $old, action => 'rename',
324             new_name => $new );
325 0           $self->writesock("$self->{CmdID} OK Rename completed.");
326             }
327              
328 0     0 0   sub cmd_SELECT { my($self)=@_;
329 0           ($self->{SelFolder})=$self->parseargs($self->{CmdArgs});
330 0           $self->fetchmsgs();
331 0           $self->writesock('* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)');
332 0           $self->writesock('* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Limited');
333 0           $self->writesock("* $self->{ExistMsgs} EXISTS");
334 0           $self->writesock("* $self->{RecentMsgs} RECENT");
335 0 0         my $nextuid=@{$self->{Msgs}} ? $self->{Msgs}->[-1]->{uid} + 1 : 1;
  0            
336 0           my $uidvalidity=$self->strcrc32($self->{SelFolder});
337 0           $self->writesock("* OK [UIDVALIDITY $uidvalidity] UID validity status");
338 0           $self->writesock("* OK [UIDNEXT $nextuid] Predicted next UID");
339              
340 0           $self->writesock("$self->{CmdID} OK [READ-WRITE] Select completed.");
341             }
342              
343 0     0 0   sub cmd_STATUS { my($self)=@_;
344 0           my($folder,$flags)=$self->parseargs($self->{CmdArgs});
345 0           $flags=~s/(\w+)/$1 0/g; #actual status is too expensive
346 0           $self->writesock("* STATUS $folder ($flags)");
347 0           $self->writesock("$self->{CmdID} OK STATUS completed.");
348             }
349              
350 0     0 0   sub cmd_STORE { my($self)=@_;
351 0           my($msglist,$args)=split(/\s+/,$self->{CmdArgs},2);
352 0 0         my $useuid = 1 if $args=~s/\s*UID$//;
353              
354 0           my $msgs=$self->msgrange($useuid,$msglist);
355 0           my @msgids=map($_->{id},@$msgs);
356            
357 0 0         if($args=~/\+FLAGS/i){
358 0           map($_->{Flags}=$args,@$msgs);
359 0 0         if($args=~/Deleted/){
360 0 0         if($self->{SelFolder} eq 'INBOX'){
    0          
    0          
    0          
    0          
361 0 0         unless($self->{CopyFolder} eq 'Trash'){
362 0           $self->logit("STORE: edit_archive(action=>'archive')",1);
363 0           $self->{Gmail}->edit_archive(action=>'archive','msgid'=>\@msgids);
364             }
365             }
366             elsif($self->{SelFolder} eq 'Trash'){
367 0 0         unless($self->{CopyFolder}){ #delete forever
368 0           $self->logit("STORE: delete_message (permanent)",1);
369 0           $self->{Gmail}->delete_message(msgid=>\@msgids);
370             }
371             }
372              
373             elsif($self->{SelFolder} eq 'All'){
374             #Nothing needed here, unarchive done by copy
375 0           $self->logit("STORE: do nothing",1);
376             }
377             elsif($self->{SelFolder} eq 'Starred'){
378 0           $self->logit("STORE: edit_star(action => 'remove')",1);
379 0           map($self->{Gmail}->edit_star(action => 'remove','msgid' =>$_),@msgids);
380             }
381             elsif($self->{SelFolder} eq 'Spam'){
382             #Nothing needed here
383 0           $self->logit("STORE: do nothing",1);
384             }
385             else{
386 0           $self->logit("STORE: edit_labels(action=>'remove')",1);
387 0           $self->{Gmail}->edit_labels(label=>$self->{SelFolder},
388             action=>'remove',msgid=>\@msgids);
389             }
390             }
391 0 0         if($args=~/Seen/){
392 0           for my $msg (@{$msgs}){
  0            
393 0           $self->logit("STORE: get_indv_email",1);
394 0           $self->{Gmail}->get_indv_email(msg => $msg); #marks as read
395             }
396             }
397 0           $self->{CopyFolder}='';
398             }
399 0           $self->writesock("$self->{CmdID} OK Store completed.");
400             }
401              
402 0     0 0   sub cmd_SUBSCRIBE { my($self)=@_;
403 0           $self->writesock("$self->{CmdID} OK Subscribe completed.");
404             }
405              
406 0     0 0   sub cmd_UNSUBSCRIBE { my($self)=@_;
407 0           $self->writesock("$self->{CmdID} OK UnSubscribe completed.");
408             }
409              
410 0     0 0   sub mdecode { my($self,$str)=@_;
411 0           $str=~y#A-Za-z0-9+/##cd; $str=~y#A-Za-z0-9+/# -_#;
  0            
412 0           return unpack("u", pack("c", 32 + 0.75*length($str)) . $str);
413             }
414              
415 0     0 0   sub parseargs { my($self,$s)=@_;
416 0           my @args;
417 0           while($s=~s/\s*(\S+)//){ my $arg=$1;
  0            
418 0 0         if($arg=~s/^(['"(<])//){
419 0           my $q=$1; $s="$arg$s";
  0            
420 0 0         if($q eq '('){ $q='\)' }
  0 0          
421 0           elsif($q eq '<'){ $q='>' }
422 0 0         $arg=$1 if $s =~ s/([^$q]*)$q//;
423             }
424 0           push(@args,$arg);
425             }
426 0           return @args;
427             }
428              
429              
430 0     0 0   sub readsock { my($self,$fmt)=@_;
431 0           my $s=$self->{Socket};
432 0           my $line;
433 0           while(!$line){$line=<$s>};
  0            
434 0 0         $line=~s/\s+$// unless $fmt eq 'raw';
435 0           $self->logit("readsock:'$line'",2);
436 0           return $line;
437             }
438              
439 0     0 0   sub writesock { my($self,$msg,$fmt)=@_;
440 0           $self->logit("writesock:'$msg'",2);
441 0           my $s=$self->{Socket};
442 0 0         unless($s){
443 0           $self->logit("writesock: attempt to write on closed socket");
444 0           return;
445             }
446 0 0         $msg=~s/\s*$/\r\n/ unless $fmt eq 'raw';
447 0           print $s $msg;
448             }
449              
450 0     0 0   sub fetchmsgs { my($self)=@_;
451 0           ($self->{Msgs},$self->{ExistMsgs},$self->{RecentMsgs})=([],0,0);
452 0           my $msgs=$self->{Gmail}->get_messages(label => $self->{SelFolder});
453 0 0         return unless $msgs;
454 0           my $n=1;
455 0           for my $msg (sort { $a->{id} cmp $b->{id} } @$msgs){
  0            
456 0           $msg->{uid}=hex(substr($msg->{id},0,8));
457 0           $msg->{n}=$n++;
458 0           $self->logit("fetchmsgs: $msg->{n} $msg->{uid}",2);
459 0           $self->{ExistMsgs}++;
460 0 0         $self->{RecentMsgs}++ if $msg->{new};
461 0           push(@{$self->{Msgs}},$msg);
  0            
462             }
463             }
464              
465 0     0 0   sub msgrange{ my($self,$useuid,$msglist)=@_;
466 0           my $msgs=[];
467 0           for my $ent (split(',',$msglist)){
468 0           my($start,$end)=split(':',$ent);
469 0 0         if(!$end){ $end = $start }
  0 0          
470 0           elsif($end eq '*'){ $end=hex('ffffffff') }
471 0           for my $msg (@{$self->{Msgs}}){
  0            
472 0 0 0       if($useuid){
    0          
473 0 0 0       if($msg->{uid} >= $start && $msg->{uid} <= $end){ push(@$msgs,$msg) }
  0            
474             }
475 0           elsif($msg->{n}>=$start && $msg->{n} <= $end){ push(@$msgs,$msg) }
476             }
477             }
478 0           return $msgs;
479             }
480              
481 0     0 0   sub cache_get_mime_email { my($self,$msg)=@_;
482 0 0         unless($self->{Cache}->{$msg->{id}}){
483 0           $self->{Cache}->{$msg->{id}}=$self->{Gmail}->get_mime_email( msg => $msg );
484 0           select(undef, undef, undef, 0.25); #throttle
485 0           $self->{Cache}->{$msg->{id}} =~ s/\n/\r\n/gm;
486             }
487 0           return $self->{Cache}->{$msg->{id}};
488             }
489              
490 0     0 0   sub get_envelope { my($self,$head)=@_;
491 0           my @buf;
492              
493 0     0 0   sub garbleaddr { my($addr)=@_;
494 0 0         my $email=$1 if $addr=~s/\s*<*(\S+\@[^>\s]+)>*\s*//;
495 0           my $name=$addr; $name=~s/"//g;
  0            
496 0           my($em1,$em2)=split(/\@/,$email);
497 0 0         return join(' ',map( $_ ? "\"$_\"" : 'NIL',($name,'',$em1,$em2)));
498             };
499              
500 0           for my $ent ('Date','Subject'){
501 0 0         push @buf, $head=~s/^$ent: ([^\r\n]+)//m ? "\"$1\"" : 'NIL';
502             }
503 0           my @prevdata=();
504 0           for my $ent ('From','Sender','Reply\-To'){ my @data=();
  0            
505 0           push(@data,$1) while $head=~s/^$ent: ([^\r\n]+)//m;
506 0 0         if(@data){
    0          
507 0           push @buf, "(" . join(' ',map("(" . garbleaddr($_) . ")",@data))
508             . ")";
509 0           @prevdata=@data;
510             }
511             elsif(@prevdata){
512 0           push @buf, "(" . join(' ',map("(" . garbleaddr($_) . ")",@prevdata)) .")";
513             }
514             else{
515 0           push @buf,"NIL";
516             }
517             }
518 0           for my $ent ('To','Cc','Bcc'){ my @data=();
  0            
519 0           push(@data,$1) while $head=~s/^$ent: ([^\r\n]+)//m;
520 0 0         if(@data){
521 0           push @buf, "(" . join(' ',map("(" . garbleaddr($_) . ")",@data)) . ")";
522             }
523             else{
524 0           push @buf,"NIL";
525             }
526             }
527 0           for my $ent ('In\-Reply\-To','Message\-ID'){
528 0 0         push @buf, $head=~s/^$ent: ([^\r\n]+)//m ? "\"$1\"" : 'NIL';
529             }
530 0           return join(' ',@buf);
531             }
532              
533 0     0 0   sub get_internaldate { my($self,$head)=@_;
534 0           my($dates)=$head=~/^Date: (.*)/m;
535 0           my($date,$time)=$dates=~/(\d+ \w+ \d+)\s+(.*)/;
536 0           $date=~s/ /\-/g; $time=~s/\s+$//;
  0            
537 0           return "$date $time";
538             }
539              
540 0     0 0   sub get_header { my($self,$msg)=@_;
541 0 0         return $1 if $msg=~/(.*?\r\n\r\n)/ms;
542             }
543              
544             # From Digest::Crc32. Thanks Faycal Chraibi
545             sub _crc32 {
546 0     0     my ($comp) = @_;
547 0           my $poly = 0xEDB88320;
548 0           for (my $cnt = 0; $cnt < 8; $cnt++) {
549 0 0         $comp = $comp & 1 ? $poly ^ ($comp >> 1) : $comp >> 1;
550             }
551 0           return $comp;
552             }
553              
554             #from Digest::Crc32. Thanks Faycal Chraibi
555             sub strcrc32 {
556 0     0 0   my($self,$tcmp)=@_;
557 0           my $crc = 0xFFFFFFFF;
558 0           foreach (split(//,$tcmp)) {
559 0           $crc = (($crc>>8) & 0x00FFFFFF) ^ _crc32(($crc ^ ord($_)) & 0xFF);
560             }
561 0           return $crc^0xFFFFFFFF;
562             }
563              
564 0     0 0   sub sendemail { my($self,$from,$to,$msg)=@_;
565 1     1   1237 use Net::SMTP;
  1         18502  
  1         318  
566 0           my $smtp=Net::SMTP->new('127.0.0.1');
567 0 0         die "Couldn't connect to server" unless $smtp;
568 0           $smtp->mail($from);
569 0           $smtp->to($to);
570 0           $smtp->data($msg);
571 0           $smtp->quit();
572             }
573              
574 0     0 0   sub logit { my($self,$msg,$debug_level)=@_;
575 0 0         $debug_level = 0 unless $debug_level;
576 0 0         return unless $debug_level <= $self->{Debug};
577 0           my $timestamp=scalar localtime(time);
578 0 0         $msg="$self->{Peer}: $msg" if $self->{Peer};
579 0           $msg="$timestamp: $msg\n";
580 0 0         print $msg if !$self->{Detach};
581 0 0         return unless $self->{LogFile};
582 0           my $lf=new IO::File ">>$self->{LogFile}";
583 0           print $lf $msg;
584 0           close $lf;
585             }
586              
587             __END__