ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Coro/mymap/mymapd
Revision: 1.3
Committed: Sat Nov 15 03:53:10 2003 UTC (20 years, 8 months ago) by pcg
Branch: MAIN
CVS Tags: rel-2_5, rel-4_91, rel-4_22, rel-4_21, rel-4_0, rel-4_3, rel-3_41, rel-5_151, rel-4_13, rel-4_11, rel-5_1, rel-5_0, rel-6_0, rel-6_5, rel-4_748, rel-3_55, rel-4_8, rel-4_9, rel-3_51, rel-4_741, rel-4_743, rel-4_742, rel-6_10, rel-4_744, rel-4_747, rel-6_13, rel-4_01, rel-4_03, rel-4_02, rel-2_0, rel-2_1, rel-1_1, rel-1_0, rel-1_9, rel-1_2, rel-3_6, rel-3_62, rel-3_63, rel-3_61, rel-1_5, rel-1_4, rel-1_7, rel-1_6, rel-3_4, rel-6_09, rel-6_08, rel-6_07, rel-6_06, rel-6_05, rel-6_04, rel-6_03, rel-6_02, rel-6_01, rel-5_161, rel-3_1, rel-4_74, rel-4_71, rel-4_72, rel-4_73, rel-5_371, rel-5_372, rel-6_512, rel-6_513, rel-6_511, rel-6_514, rel-5_22, rel-5_23, rel-5_24, rel-5_25, rel-6_32, rel-6_33, rel-6_31, rel-6_36, rel-6_37, rel-5_162, rel-5_2, rel-6_38, rel-6_39, rel-4_802, rel-4_803, rel-3_5, rel-4_801, rel-3_3, rel-3_2, rel-4_804, rel-3_0, rel-5_37, rel-5_36, rel-4_479, rel-6_23, rel-3_01, rel-6_29, rel-6_28, rel-6_46, rel-4_50, rel-4_51, rel-6_45, rel-4_4, rel-3_11, rel-1_31, rel-4_45, rel-6_51, rel-6_52, rel-6_53, rel-6_54, rel-6_55, rel-6_56, rel-6_57, rel-4_745, rel-4_901, rel-4_49, rel-4_48, rel-4_1, rel-4_2, rel-4_746, rel-5_11, rel-5_12, rel-5_15, rel-5_14, rel-5_17, rel-5_16, stack_sharing, rel-4_47, rel-4_46, rel-4_7, rel-3_501, rel-6_43, rel-6_42, rel-6_41, rel-6_47, rel-5_132, rel-5_131, rel-6_44, rel-6_49, rel-6_48, rel-4_911, rel-4_912, rel-4_31, rel-4_32, rel-4_33, rel-4_34, rel-4_35, rel-4_36, rel-4_37, HEAD
Changes since 1.2: +1 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #!/usr/bin/perl
2    
3     use Coro;
4     use Coro::Event;
5     use Coro::Socket;
6    
7     BEGIN { require "mymap.pl" };
8    
9     $/ = $CRLF;
10    
11     my $port = new Coro::Socket
12 pcg 1.2 LocalPort => "imap",
13 root 1.1 ReuseAddr => 1,
14     Listen => 1,
15     or die;
16    
17     sub slog {
18     my $level = shift;
19     my $format = shift;
20     printf "---: $format\n", @_;
21     }
22    
23     sub resp {
24     slog 9, ">>> @_";
25     my $r;
26     $r .= "* $_[$_]$CRLF" for 2 .. $#_-1;
27     $r .= "$_[1] $_[$#_]$CRLF";
28     print {$_[0]} $r;
29     }
30    
31     $RE_pgrp = qr{
32     (?:
33     [^()]*
34     | \( (??{ $RE_pgrp }) \)
35     )*
36     }x;
37    
38     sub expand_list {
39     my @r;
40     $_[0] =~ s/\*/$_[1]/g;
41     for (split /,/, $_[0]) {
42     if (/(\d+):(\d+)/) {
43     push @r, $_ for $1 .. $2;
44     } else {
45     push @r, $_;
46     }
47     }
48     \@r;
49     }
50    
51     sub split_pgrp {
52     my @r;
53     while ($_[0] =~ /\G(?:([^( ]+)|\(($RE_pgrp)\)) ?/mg) {
54     push @r, defined $1 ? $1 : $2;
55     }
56     \@r;
57     }
58    
59     sub literal {
60 pcg 1.2 "{" . (length $_[0]) . "}\015\012$_[0]";
61 root 1.1 }
62    
63     sub handle_connection {
64     my $fh = shift;
65    
66     eval {
67    
68     my $uid; # user-id
69     my $bid; # mailbox-id
70     my $readonly; # mailbox read-only?
71     my @mid; # message numbers
72    
73     my $expunge = sub {
74     my $st = sql_exec \my($id),
75     "select id from msg
76     where flags & ($F_D|$F_deleted) = ($F_deleted)
77     and bid = ?",
78     $bid;
79     while ($st->fetch) {
80     my %rev;
81     @rev{@mid} = (1..@mid);
82     my $idx = $rev{$id}
83     or next;
84     print $fh "* $idx EXPUNGE\015\012";
85     splice @mid, $idx-1, 1;
86     sql_exec "update msg set flags = flags | $F_D where id = ?", $id;
87     }
88     };
89    
90     my $close = sub {
91     return unless $bid;
92     sql_exec "update box set ctime = ? where id = ?", time, $bid;
93     $bid = 0;
94     @mid = ();
95     };
96    
97     #resp $fh, "*", "OK IMAP4 service ready.";
98 pcg 1.2 resp $fh, "*", "PREAUTH IMAP4 service ready."; #$uid = 1;
99 root 1.1 CMD:
100     while (<$fh>) {
101 pcg 1.3 warn $_;#d#
102 root 1.1 /^(\S+)(?: (\S+)([^\015\012]*))?$CRLF$/os or last;
103     my ($tag, $cmd, $arg) = ($1, $2, $3);
104     my @arg;
105     $cmd = lc $cmd;
106     while () {
107     if ($arg =~ /\G "((?:[^"\\]*|\\.))"/gc
108 pcg 1.2 #|| $arg =~ /\G ([^"(){ \x00-\x1f*%\\]+)/gc # ] is allowed...
109     || $arg =~ /\G ([^"(){ \x00-\x1f%\\]+)/gc # evolution-fix
110 root 1.1 || $arg =~ /\G \(($RE_pgrp)\)/gc) {
111     push @arg, $1;
112     } elsif ($arg =~ /\G {(\d+)}$/gc) {
113     resp $fh, $tag, "literals not yet implemented";
114     next CMD;
115     } elsif ($arg =~ /\G$/gc) {
116     last;
117     } elsif ($arg =~ /\G(.*)$/gc) {
118     $arg = $1;
119     $arg =~ y/\015\012//d;
120     resp $fh, $tag, "BAD parse error at '$arg' (@arg)";
121     next CMD;
122     } else {
123     die;
124     }
125     }
126    
127 pcg 1.2 slog 9, "<<< $tag|$cmd|@arg";#d#
128 root 1.1 if ($cmd eq "capability") {
129     resp $fh, $tag, "CAPABILITY IMAP4", "OK";
130     } elsif ($cmd eq "noop") {
131     resp $fh, $tag, "OK";
132     # bah!
133     } elsif ($cmd eq "login" && !$uid) {
134     my $st = sql_exec \$uid, "select id from user where name = ? and pass = ?", $arg[0], $arg[1];
135     if ($st->fetch) {
136     resp $fh, $tag, "OK";
137     } else {
138     resp $fh, $tag, "NO user unknown or authenticitation failure";
139     }
140     } elsif ($cmd eq "authenticitate" && !$uid) {
141     resp $fh, "NO";
142     } elsif ($cmd eq "logout") {
143     resp $fh, $tag, "BYE", "OK";
144     last CMD;
145     } elsif ($uid) {
146     my $U;
147    
148     if ($cmd eq "uid") {
149     $cmd = lc shift @arg;
150     $U = 1;
151     }
152    
153     if ($cmd eq "select" || $cmd eq "examine") {
154     &$close;
155    
156     $arg[0] = "INBOX" if lc $arg[0] eq "inbox";
157    
158     my $st = sql_exec \$bid, \my($ctime, $uidv),
159     "select id, unix_timestamp(ctime), unix_timestamp(uidvalidity)
160     from box where uid = ? and name = ?",
161     $uid, $arg[0];
162     if ($st->fetch) {
163     my $r = 0;
164     $st = sql_exec \my($mid, $ntime),
165     "select id, ntime
166     from msg
167     where bid = ? and flags & $F_D = 0",
168     $bid;
169     while ($st->fetch) {
170     $r++ if $ntime >= $ctime;
171     push @mid, $mid;
172     }
173     $readonly = $cmd eq "examine";
174     resp $fh, $tag,
175     (scalar@mid) . " EXISTS",
176     "$r RECENT",
177     "FLAGS (\\D \\Answered \\Flagged \\Deleted \\Seen \\Draft)",
178     "PERMANENTFLAGS (\\D \\Answered \\Flagged \\Deleted \\Seen \\Draft)",
179     "OK [UID-VALIDITY $uidv]",
180     "OK [READ-".($readonly ? "ONLY]" : "WRITE]");
181     } else {
182     resp $fh, $tag, "NO mailbox does not exist";
183     }
184    
185     # mailbox management
186     } elsif ($cmd eq "create") {
187     $arg[0] =~ s/\///;
188     eval {
189     sql_exec "insert into box (uid, name) values (?, ?)", $uid, $arg[0];
190     };
191     if ($@) {
192     $@ =~ y/\015\012//d;
193     resp $fh, $tag, "NO $@";
194     } else {
195     resp $fh, $tag, "OK";
196     }
197     } elsif ($cmd eq "delete") {
198     if (lc $arg[0] ne "inbox" and sql_exec "delete from box where uid = ? and name = ?", $uid, $arg[0]) {
199     resp $fh, $tag, "OK";
200     } else {
201     resp $fh, $tag, "NO";
202     }
203     } elsif ($cmd eq "rename") {
204     eval {
205     sql_exec "update box set name = ? where uid = ? and name = ?", $arg[1], $uid, $arg[0];
206     };
207     if ($@) {
208     $@ =~ y/\015\012//d;
209     resp $fh, $tag, "NO $@";
210     } else {
211     resp $fh, $tag, "OK";
212     }
213     } elsif ($cmd eq "subscribe" || $cmd eq "unsubscribe" || $cmd eq "lsub") {
214     resp $fh, $tag, "NO not supported";
215     } elsif ($cmd eq "list") {
216     if ($arg[0] != "") {
217     resp $fh, $tag, "NO reference not supported";
218     } else {
219     #$arg[1] =~ y/%/%/; #% not supported yet
220     $arg[1] =~ y/*/%/;
221     my $st = sql_exec \my($name),
222     "select name from box
223     where uid = ? and name like ?",
224     $uid, $arg[1];
225     my @r;
226     while ($st->fetch) {
227     push @r, "LIST () \"/\" $name";
228     }
229     resp $fh, $tag, @r, "OK";
230     }
231     } elsif ($cmd eq "append") {
232     resp $fh, $tag, "BAD not supported yet!";
233    
234     # message handling
235     } elsif ($bid) {
236     if ($cmd eq "close") {
237     &$expunge;
238     &$close;
239     resp $fh, $tag, "OK";
240     } elsif ($cmd eq "expunge") {
241     die if $U;
242     &$expunge;
243     resp $fh, $tag, "OK";
244     } elsif ($cmd eq "fetch") {
245     my $list = expand_list($arg[0], scalar @mid);
246     my ($mid, $flags, $date, $head, $body);
247     my @exec;
248     my ($sql_body, $sql_head) = (0, 0);
249     my $sel = split_pgrp lc $arg[1];
250    
251     while (my $s = shift @$sel) {
252     if ($s eq "all") {
253     push @$sel, qw(flags internaldate rfc822.size); next;
254     } elsif ($s eq "full") {
255     push @$sel, qw(flags internaldate rfc822.size envelope body); next;
256     } elsif ($s eq "uid") {
257     $s = sub { "UID $mid" };
258     } elsif ($s eq "flags") {
259     $s = sub {
260     "FLAGS (" . (join " ", map "\\" . ucfirst $_, split /,/, $flags) . ")";
261     };
262     } elsif ($s eq "internaldate") {
263     $s = sub { "INTERNALDATE \"$date\"" };
264     } elsif ($s eq "rfc822.size") {
265     $sql_body = "body";
266     $s = sub { "RFC822.SIZE ".length $body };
267     } elsif ($s eq "rfc822.header") {
268     $sql_head = "header";
269     $s = sub { "RFC822.HEADER ".literal($head) };
270     } elsif ($s eq "rfc822") {
271     $sql_body = "body"; $sql_head = "header";
272     $s = sub { "RFC822 ".literal($head.$CRLF.$body) };
273 pcg 1.2 } elsif ($s eq "body.peek[0]") {#d# evolution-bug
274     $sql_head = "header";
275     $s = sub { "BODY[0] ".literal($head) };
276 root 1.1 } elsif ($s eq "rfc822.header.lines") {
277     $sql_head = "header";
278     my $re;
279     $re = '(?i:^((?:'
280     . (join "|", @{split_pgrp shift @$sel})
281     . '):[^\012\015]*))';
282     $re = qr($re);
283    
284     $s = sub {
285     "RFC822.HEADER.LINES ".literal (join $CRLF, $head =~ /$re/mg);
286     };
287     } else {
288     $s = sub { '""' };
289     }
290     push @exec, $s;
291     }
292    
293     my %rev;
294     unless ($U) {
295     for (@$list) {
296     $mid = $mid[$_ - 1];
297     $rev{$mid} = $_;
298     $_ = $mid;
299     }
300     }
301    
302     my $st = sql_exec \($mid, $flags, $date, $head, $body),
303     "select id, flags, date_format(ntime, '%d-%m-%Y %h:%i:%s +0000'), $sql_head, $sql_body
304     from msg
305     where id in (".(join ",", @$list).")";
306    
307     my $r;
308     while ($st->fetch) {
309     my $id = $U ? $mid : $rev{$mid};
310     $r .= "* $id FETCH (".(join " ", map &$_, @exec).")\015\12";
311     if (length $r > 32768) {
312     print $fh $r;
313     $r = "";
314     }
315     }
316     print $fh "$r$tag OK\015\012";
317     #resp $fh, $tag, "OK";
318    
319     } elsif ($cmd eq "store") {
320     my $list = expand_list($arg[0], scalar @mid);
321     my $cmd = lc $arg[1];
322     my $flags = flags2bitmask(@{split_pgrp $arg[2]});
323    
324     my %rev;
325     unless ($U) {
326     for (@$list) {
327     $mid = $mid[$_ - 1];
328     $rev{$mid} = $_;
329     $_ = $mid;
330     }
331     }
332    
333     my $ids = join ",", @$list;
334    
335     my $silent = $cmd =~ s/\.silent$//;
336    
337     if ($cmd eq "flags") {
338     sql_exec "update msg set flags = ? where id in ($ids)", $flags;
339     } elsif ($cmd eq "+flags") {
340     sql_exec "update msg set flags = flags | ? where id in ($ids)", $flags;
341     } elsif ($cmd eq "-flags") {
342     sql_exec "update msg set flags = flags & ~? where id in ($ids)", $flags;
343     }
344    
345     if ($silent) {
346     resp $fh, $tag, "OK";
347     } else {
348     my $st = sql_exec \($mid, $flags),
349     "select id, flags
350     from msg
351     where id in ($ids)";
352    
353     my $r;
354     while ($st->fetch) {
355     my $id = $U ? $mid : $rev{$mid};
356     $r .= "* $id FLAGS (" . (join " ", map "\\" . ucfirst $_, split /,/, $flags) . ")\015\012";
357     }
358     print $fh "$r$tag OK\015\012";
359     #resp $fh, $tag, "OK";
360     }
361    
362     } else {
363 pcg 1.2 resp $fh, $tag, "BAD command not understood (nocommand)";
364 root 1.1 }
365    
366     # well...
367     } else {
368 pcg 1.2 resp $fh, $tag, "BAD command not understood (notmailbox)";
369 root 1.1 }
370    
371     } else {
372 pcg 1.2 resp $fh, $tag, "BAD command not understood (notauth)";
373 root 1.1 }
374     }
375     };
376     if ($@) {
377     resp $fh, "*", "BYE";
378     slog 0, "$@";
379     }
380     slog 3, "$fh: closed connection\n";#d#
381     }
382    
383     async {
384     slog 1, "accepting connections";
385     while () {
386     my $fh = $port->accept;
387     slog 3, "accepted $fh on $port";
388     async \&handle_connection, $fh;
389     undef $fh;
390     }
391     };
392    
393     loop;
394