vmail.cgi updates
[asterisk/asterisk.git] / contrib / scripts / vmail.cgi
1 #!/usr/bin/perl
2 #
3 # Web based Voicemail for Asterisk
4 #
5 # Copyright (C) 2002, Linux Support Services, Inc.
6 #
7 # Distributed under the terms of the GNU General Public License
8 #
9 # Written by Mark Spencer <markster@linux-support.net>
10 #
11 # (icky, I know....  if you know better perl please help!)
12 #
13 #
14 use CGI qw/:standard/;
15 use Carp::Heavy;
16 use CGI::Carp qw(fatalsToBrowser);
17
18 @validfolders = ( "INBOX", "Old", "Work", "Family", "Friends", "Cust1", "Cust2", "Cust3", "Cust4", "Cust5" );
19
20 %formats = (
21         "wav" => {
22                 name => "Uncompressed WAV",
23                 mime => "audio/x-wav",
24                 pref => 1
25         },
26         "WAV" => {
27                 name => "GSM Compressed WAV",
28                 mime => "audio/x-wav",
29                 pref => 2
30         },
31         "gsm" => {
32                 name => "Raw GSM Audio",
33                 mime => "audio/x-gsm",
34                 pref => 3
35         }
36 );
37
38 $astpath = "/_asterisk";
39
40 $stdcontainerstart = "<table align=center width=600><tr><td>\n";
41 $footer = "<hr><font size=-1><a href=\"http://www.asterisk.org\">The Asterisk Open Source PBX</a> Copyright 2002, <a href=\"http://www.digium.com\">Digium, Inc.</a></a>";
42 $stdcontainerend = "</td></tr><tr><td align=right>$footer</td></tr></table>\n";
43
44 sub login_screen() {
45         print header;
46         my ($message) = @_;
47         print <<_EOH;
48
49 <TITLE>Asterisk Web-Voicemail</TITLE>
50 <BODY BGCOLOR="white">
51 $stdcontainerstart
52 <FORM METHOD="post">
53 <input type=hidden name="action" value="login">
54 <table align=center>
55 <tr><td valign=top align=center rowspan=6><img align=center src="$astpath/animlogo.gif"></td></tr>
56 <tr><td align=center colspan=2><font size=+2>Comedian Mail Login</font></td></tr>
57 <tr><td align=center colspan=2><font size=+1>$message</font></td></tr>
58 <tr><td>Mailbox:</td><td><input type=text name="mailbox"></td></tr>
59 <tr><td>Password:</td><td><input type=password name="password"></td></tr>
60 <tr><td align=right colspan=2><input value="Login" type=submit></td></tr>
61 </table>
62 </FORM>
63 $stdcontainerend
64 </BODY>\n
65 _EOH
66
67 }
68
69 sub check_login()
70 {
71         local ($filename, $startcat) = @_;
72         local ($mbox, $context) = split(/\@/, param('mailbox'));
73         local $pass = param('password');
74         local $category = $startcat;
75         local @fields;
76         local $tmp;
77         local (*VMAIL);
78         if (!$category) {
79                 $category = "general";
80         }
81         if (!$context) {
82                 $context = param('context');
83         }
84         if (!$context) {
85                 $context = "default";
86         }
87         if (!$filename) {
88                 $filename = "/etc/asterisk/voicemail.conf";
89         }
90 #       print header;
91 #       print "Including <h2>$filename</h2> while in <h2>$category</h2>...\n";
92         open(VMAIL, "<$filename") || die("Bleh, no $filename");
93         while(<VMAIL>) {
94                 chomp;
95                 if (/include\s\"([^\"]+)\"$/) {
96                         ($tmp, $category) = &check_login("/etc/asterisk/$1", $category);
97                         if (length($tmp)) {
98 #                               print "Got '$tmp'\n";
99                                 return ($tmp, $category);
100                         }
101                 } elsif (/\[(.*)\]/) {
102                         $category = $1;
103                 } elsif (($category ne "general") && ($category ne "zonemessages")) { 
104                         if (/([^\s]+)\s*\=\>?\s*(.*)/) {
105                                 @fields = split(/\,\s*/, $2);
106 #                               print "<p>Mailbox is $1\n";
107                                 if (($mbox eq $1) && ($pass eq $fields[0]) && ($context eq $category)) {
108                                         return ($fields[1] ? $fields[1] : "Extension $mbox in $context", $category);
109                                 }
110                         }
111                 }
112         }
113         close(VMAIL);
114         return ("", $category);
115 }
116
117 sub validmailbox()
118 {
119         local ($context, $mbox, $filename, $startcat) = @_;
120         local $category = $startcat;
121         local @fields;
122         local (*VMAIL);
123         if (!$context) {
124                 $context = param('context');
125         }
126         if (!$context) {
127                 $context = "default";
128         }
129         if (!$filename) {
130                 $filename = "/etc/asterisk/voicemail.conf";
131         }
132         if (!$category) {
133                 $category = "general";
134         }
135         open(VMAIL, "<$filename") || die("Bleh, no $filename");
136         while(<VMAIL>) {
137                 chomp;
138                 if (/include\s\"([^\"]+)\"$/) {
139                         ($tmp, $category) = &validmailbox($mbox, $context, "/etc/asterisk/$1");
140                         if ($tmp) {
141                                 return ($tmp, $category);
142                         }
143                 } elsif (/\[(.*)\]/) {
144                         $category = $1;
145                 } elsif (($category ne "general") && ($category ne "zonemessages") && ($category eq $context)) {
146                         if (/([^\s]+)\s*\=\>?\s*(.*)/) {
147                                 @fields = split(/\,\s*/, $2);
148                                 if (($mbox eq $1) && ($context eq $category)) {
149                                         return ($fields[2] ? $fields[2] : "unknown", $category);
150                                 }
151                         }
152                 }
153         }
154         return ("", $category);
155 }
156
157 sub mailbox_options()
158 {
159         local($context, $current, $filename, $category) = @_;
160         local (*VMAIL);
161         local $tmp2;
162         local $tmp;
163         if (!$filename) {
164                 $filename = "/etc/asterisk/voicemail.conf";
165         }
166         if (!$category) {
167                 $category = "general";
168         }
169 #       print header;
170 #       print "Including <h2>$filename</h2> while in <h2>$category</h2>...\n";
171         open(VMAIL, "<$filename") || die("Bleh, no voicemail.conf");
172         while(<VMAIL>) {
173                 chomp;
174                 s/\;.*$//;
175                 if (/include\s\"([^\"]+)\"$/) {
176                         ($tmp2, $category) = &mailbox_options($context, $current, "/etc/asterisk/$1", $category);
177 #                       print "Got '$tmp2'...\n";
178                         $tmp .= $tmp2;
179                 } elsif (/\[(.*)\]/) {
180                         $category = $1;
181                 } elsif (($category ne "general") && ($category ne "zonemessages")) {
182                         if (/([^\s]+)\s*\=\>?\s*(.*)/) {
183                                 @fields = split(/\,\s*/, $2);
184                                 $text = "$1";
185                                 if ($fields[1]) {
186                                         $text .= " ($fields[1])";
187                                 }
188                                 if ($1 eq $current) {
189                                         $tmp .= "<OPTION SELECTED>$text</OPTION>\n";
190                                 } else {
191                                         $tmp .= "<OPTION>$text</OPTION>\n";
192                                 }
193                                 
194                         }
195                 }
196         }
197         close(VMAIL);
198         return ($tmp, $category);
199 }
200
201 sub mailbox_list()
202 {
203         local ($name, $context, $current) = @_;
204         local $tmp;
205         local $text;
206         local $tmp;
207         local $opts;
208         if (!$context) {
209                 $context = "default";
210         }
211         $tmp = "<SELECT name=\"$name\">\n";
212         ($opts) = &mailbox_options($context, $current);
213         $tmp .= $opts;
214         $tmp .= "</SELECT>\n";
215         
216 }
217
218 sub msgcount() 
219 {
220         my ($context, $mailbox, $folder) = @_;
221         my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder";
222         if (opendir(DIR, $path)) {
223                 my @msgs = grep(/^msg....\.txt$/, readdir(DIR));
224                 closedir(DIR);
225                 return sprintf "%d", $#msgs + 1;
226         }
227         return "0";
228 }
229
230 sub msgcountstr()
231 {
232         my ($context, $mailbox, $folder) = @_;
233         my $count = &msgcount($context, $mailbox, $folder);
234         if ($count > 1) {
235                 "$count messages";
236         } elsif ($count > 0) {
237                 "$count message";
238         } else {
239                 "no messages";
240         }
241 }
242 sub messages()
243 {
244         my ($context, $mailbox, $folder) = @_;
245         my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder";
246         if (opendir(DIR, $path)) {
247                 my @msgs = sort grep(/^msg....\.txt$/, readdir(DIR));
248                 closedir(DIR);
249                 return map { s/^msg(....)\.txt$/$1/; $_ } @msgs;
250         }
251         return ();
252 }
253
254 sub getcookie()
255 {
256         my ($var) = @_;
257         return cookie($var);
258 }
259
260 sub makecookie()
261 {
262         my ($format) = @_;
263         cookie(-name => "format", -value =>["$format"], -expires=>"+1y");
264 }
265
266 sub getfields()
267 {
268         my ($context, $mailbox, $folder, $msg) = @_;
269         my $fields;
270         if (open(MSG, "</var/spool/asterisk/voicemail/$context/$mailbox/$folder/msg${msg}.txt")) {
271                 while(<MSG>) {
272                         s/\#.*$//g;
273                         if (/^(\w+)\s*\=\s*(.*)$/) {
274                                 $fields->{$1} = $2;
275                         }
276                 }
277                 close(MSG);
278                 $fields->{'msgid'} = $msg;
279         } else { print "<BR>Unable to open '$msg' in '$mailbox', '$folder'\n<B>"; }
280         $fields;
281 }
282
283 sub message_prefs()
284 {
285         my ($nextaction, $msgid) = @_;
286         my $folder = param('folder');
287         my $mbox = param('mailbox');
288         my $context = param('context');
289         my $passwd = param('password');
290         my $format = param('format');
291         if (!$format) {
292                 $format = &getcookie('format');
293         }
294         print header;
295         print <<_EOH;
296
297 <TITLE>Asterisk Web-Voicemail: Preferences</TITLE>
298 <BODY BGCOLOR="white">
299 $stdcontainerstart
300 <FORM METHOD="post">
301 <table width=100% align=center>
302 <tr><td align=right colspan=3><font size=+2>Web Voicemail Preferences</font></td></tr>
303 <tr><td align=left><font size=+1>Preferred&nbsp;Audio&nbsp;Format:</font></td><td colspan=2></td></tr>
304 _EOH
305
306 foreach $fmt (sort { $formats{$a}->{'pref'} <=> $formats{$b}->{'pref'} } keys %formats) {
307         my $clicked = "checked" if $fmt eq $format;
308         print "<tr><td></td><td align=left><input type=radio name=\"format\" $clicked value=\"$fmt\"></td><td width=100%>&nbsp;$formats{$fmt}->{name}</td></tr>\n";
309 }
310
311 print <<_EOH;
312 <tr><td align=right colspan=3><input type=submit value="save settings..."></td></tr>
313 </table>
314 <input type=hidden name="action" value="$nextaction">
315 <input type=hidden name="folder" value="$folder">
316 <input type=hidden name="mailbox" value="$mbox">
317 <input type=hidden name="context" value="$context">
318 <input type=hidden name="password" value="$passwd">
319 <input type=hidden name="msgid" value="$msgid">
320 $stdcontainerend
321 </BODY>\n
322 _EOH
323
324 }
325
326 sub message_play()
327 {
328         my ($message, $msgid) = @_;
329         my $folder = param('folder');
330         my ($mbox, $context) = split(/\@/, param('mailbox'));
331         my $passwd = param('password');
332         my $format = param('format');
333         
334         my $fields;
335         if (!$context) {
336                 $context = param('context');
337         }
338         if (!$context) {
339                 $context = "default";
340         }
341         
342         my $folders = &folder_list('newfolder', $context, $mbox, $folder);
343         my $mailboxes = &mailbox_list('forwardto', $context, $mbox);
344         if (!$format) {
345                 $format = &getcookie('format');
346         }
347         if (!$format) {
348                 &message_prefs("play", $msgid);
349         } else {
350                 print header(-cookie => &makecookie($format));
351                 $fields = &getfields($context, $mbox, $folder, $msgid);
352                 if (!$fields) {
353                         print "<BR>Bah!\n";
354                         return;
355                 }
356                 my $duration = $fields->{'duration'};
357                 if ($duration) {
358                         $duration = sprintf "%d:%02d", $duration/60, $duration % 60; 
359                 } else {
360                         $duration = "<i>Unknown</i>";
361                 }
362                 print <<_EOH;
363         
364 <TITLE>Asterisk Web-Voicemail: $folder Message $msgid</TITLE>
365 <BODY BGCOLOR="white">
366 $stdcontainerstart
367 <FORM METHOD="post">
368 <table width=100% align=center>
369 <tr><td align=right colspan=3><font size=+1>$folder Message $msgid</font></td></tr>
370 _EOH
371
372                 print <<_EOH;
373 <tr><td align=center colspan=3>
374 <table>
375         <tr><td colspan=2 align=center><font size=+1>$folder <b>$msgid</b></font></td></tr>
376         <tr><td><b>Message:</b></td><td>$msgid</td></tr>\n
377         <tr><td><b>Mailbox:</b></td><td>$mbox\@$context</td></tr>\n
378         <tr><td><b>Folder:</b></td><td>$folder</td></tr>\n
379         <tr><td><b>From:</b></td><td>$fields->{callerid}</td></tr>\n
380         <tr><td><b>Duration:</b></td><td>$duration</td></tr>\n
381         <tr><td><b>Original Date:</b></td><td>$fields->{origdate}</td></tr>\n
382         <tr><td><b>Original Mailbox:</b></td><td>$fields->{origmailbox}</td></tr>\n
383         <tr><td><b>Caller Channel:</b></td><td>$fields->{callerchan}</td></tr>\n
384         <tr><td align=center colspan=2>
385         <input name="action" type=submit value="index">&nbsp;
386         <input name="action" type=submit value="delete ">&nbsp;
387         <input name="action" type=submit value="forward to -> ">&nbsp;
388         $mailboxes&nbsp;
389         <input name="action" type=submit value="save to ->">
390         $folders&nbsp;
391         <input name="action" type=submit value="play ">
392         <input name="action" type=submit value="download">
393 </td></tr>
394 <tr><td colspan=2 align=center>
395 <embed width=400 height=40 src="vmail.cgi?action=audio&folder=$folder&mailbox=$mbox&context=$context&password=$passwd&msgid=$msgid&format=$format&dontcasheme=$$.$format" autostart=yes loop=false></embed>
396 </td></tr></table>
397 </td></tr>
398 </table>
399 <input type=hidden name="folder" value="$folder">
400 <input type=hidden name="mailbox" value="$mbox">
401 <input type=hidden name="context" value="$context">
402 <input type=hidden name="password" value="$passwd">
403 <input type=hidden name="msgid" value="$msgid">
404 $stdcontainerend
405 </BODY>\n
406 _EOH
407         }
408 }
409
410 sub message_audio()
411 {
412         my ($forcedownload) = @_;
413         my $folder = param('folder');
414         my $msgid = param('msgid');
415         my $mailbox = param('mailbox');
416         my $context = param('context');
417         my $format = param('format');
418         if (!$format) {
419                 $format = &getcookie('format');
420         }
421         my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder/msg${msgid}.$format";
422
423         $msgid =~ /^\d\d\d\d$/ || die("Msgid Liar ($msgid)!");
424         grep(/^${format}$/, keys %formats) || die("Format Liar ($format)!");
425
426         # Mailbox and folder are already verified
427         if (open(AUDIO, "<$path")) {
428                 $size = -s $path;
429                 $|=1;
430                 if ($forcedownload) {
431                         print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size, -attachment => "msg${msgid}.$format");
432                 } else {                
433                         print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size);
434                 }
435                 
436                 while(($amt = sysread(AUDIO, $data, 4096)) > 0) {
437                         syswrite(STDOUT, $data, $amt);
438                 }
439                 close(AUDIO);
440         } else {
441                 die("Hrm, can't seem to open $path\n");
442         }
443 }
444
445 sub message_index() 
446 {
447         my ($folder, $message) = @_;
448         my ($mbox, $context) = split(/\@/, param('mailbox'));
449         my $passwd = param('password');
450         my $message2;
451         my $msgcount;   
452         my $hasmsg;
453         my $newmessages, $oldmessages;
454         my $format = param('format');
455         if (!$format) {
456                 $format = &getcookie('format');
457         }
458         if (!$context) {
459                 $context = param('context');
460         }
461         if (!$context) {
462                 $context = "default";
463         }
464         if ($folder) {
465                 $msgcount = &msgcountstr($context, $mbox, $folder);
466                 $message2 = "&nbsp;&nbsp;&nbsp;Folder '$folder' has " . &msgcountstr($context, $mbox, $folder);
467         } else {
468                 $newmessages = &msgcount($context, $mbox, "INBOX");
469                 $oldmessages = &msgcount($context, $mbox, "Old");
470                 if (($newmessages > 0) || ($oldmessages < 1)) {
471                         $folder = "INBOX";
472                 } else {
473                         $folder = "Old";
474                 }
475                 $message2 = "You have";
476                 if ($newmessages > 0) {
477                         $message2 .= " <b>$newmessages</b> NEW";
478                         if ($oldmessages > 0) {
479                                 $message2 .= "and <b>$oldmessages</b> OLD";
480                                 if ($oldmessages != 1) {
481                                         $message2 .= " messages.";
482                                 } else {
483                                         $message2 .= "message.";
484                                 }
485                         } else {
486                                 if ($newmessages != 1) {
487                                         $message2 .= " messages.";
488                                 } else {
489                                         $message2 .= " message.";
490                                 }
491                         }
492                 } else {
493                         if ($oldmessages > 0) {
494                                 $message2 .= " <b>$oldmessages</b> OLD";
495                                 if ($oldmessages != 1) {
496                                         $message2 .= " messages.";
497                                 } else {
498                                         $message2 .= " message.";
499                                 }
500                         } else {
501                                 $message2 .= " <b>no</b> messages.";
502                         }
503                 }
504         }
505         
506         my $folders = &folder_list('newfolder', $context, $mbox, $folder);
507         my $cfolders = &folder_list('changefolder', $context, $mbox, $folder);
508         my $mailboxes = &mailbox_list('forwardto', $context, $mbox);
509         print header(-cookie => &makecookie($format));
510         print <<_EOH;
511
512 <TITLE>Asterisk Web-Voicemail: $mbox\@$context $folder</TITLE>
513 <BODY BGCOLOR="white">
514 $stdcontainerstart
515 <FORM METHOD="post">
516 <table width=100% align=center>
517 <tr><td align=center colspan=2><font size=+2><I>$message</I></font></td></tr>
518 <tr><td align=right colspan=2><font size=+1><b>$folder</b> Messages</font> <input type=submit name="action" value="change to ->">$cfolders</td></tr>
519 <tr><td align=left colspan=2><font size=+1>$message2</font></td></tr>
520 </table>
521 <table width=100% align=center cellpadding=0 cellspacing=0>
522 _EOH
523
524 print "<tr><td>&nbsp;Msg</td><td>&nbsp;From</td><td>&nbsp;Duration</td><td>&nbsp;Date</td><td>&nbsp;</td></tr>\n";
525 print "<tr><td><hr></td><td><hr></td><td><hr></td><td><hr></td><td></td></tr>\n";
526 foreach $msg (&messages($context, $mbox, $folder)) {
527
528         $fields = &getfields($context, $mbox, $folder, $msg);
529         $duration = $fields->{'duration'};
530         if ($duration) {
531                 $duration = sprintf "%d:%02d", $duration / 60, $duration % 60;
532         } else {
533                 $duration = "<i>Unknown</i>";
534         }
535         $hasmsg++;
536         print "<tr><td><input type=checkbox name=\"msgselect\" value=\"$msg\">&nbsp;<b>$msg</b></td><td>$fields->{'callerid'}</td><td>$duration</td><td>$fields->{'origdate'}</td><td><input name='play$msg' alt=\"Play message $msg\" border=0 type=image align=left src=\"$astpath/play.gif\"></td></tr>\n";
537
538 }
539 if (!$hasmsg) {
540         print "<tr><td colspan=4 align=center><P><b><i>No messages</i></b><P></td></tr>";
541 }
542
543 print <<_EOH;
544 </table>
545 <table width=100% align=center>
546 <tr><td align=right colspan=2>
547         <input type="submit" name="action" value="refresh">&nbsp;
548 _EOH
549
550 if ($hasmsg) {
551 print <<_EOH;
552         <input type="submit" name="action" value="delete">&nbsp;
553         <input type="submit" name="action" value="save to ->">
554         $folders&nbsp;
555         <input type="submit" name="action" value="forward to ->">
556         $mailboxes
557 _EOH
558 }
559
560 print <<_EOH;
561 </td></tr>
562 <tr><td align=right colspan=2>
563         <input type="submit" name="action" value="preferences">
564         <input type="submit" name="action" value="logout">
565 </td></tr>
566 </table>
567 <input type=hidden name="folder" value="$folder">
568 <input type=hidden name="mailbox" value="$mbox">
569 <input type=hidden name="context" value="$context">
570 <input type=hidden name="password" value="$passwd">
571 </FORM>
572 $stdcontainerend
573 </BODY>\n
574 _EOH
575 }
576
577 sub validfolder()
578 {
579         my ($folder) = @_;
580         return grep(/^$folder$/, @validfolders);
581 }
582
583 sub folder_list()
584 {
585         my ($name, $context, $mbox, $selected) = @_;
586         my $f;
587         my $count;
588         my $tmp = "<SELECT name=\"$name\">\n";
589         foreach $f (@validfolders) {
590                 $count =  &msgcount($context, $mbox, $f);
591                 if ($f eq $selected) {
592                         $tmp .= "<OPTION SELECTED>$f ($count)</OPTION>\n";
593                 } else {
594                         $tmp .= "<OPTION>$f ($count)</OPTION>\n";
595                 }
596         }
597         $tmp .= "</SELECT>";
598 }
599
600 sub message_rename()
601 {
602         my ($context, $mbox, $oldfolder, $old, $newfolder, $new) = @_;
603         my $oldfile, $newfile;
604         return if ($old eq $new) && ($oldfolder eq $newfolder);
605
606         if ($context =~ /^(\w+)$/) {
607                 $context = $1;
608         } else {
609                 die("Invalid Context<BR>\n");
610         }
611         
612         if ($mbox =~ /^(\w+)$/) {
613                 $mbox = $1;
614         } else {
615                 die ("Invalid mailbox<BR>\n");
616         }
617         
618         if ($oldfolder =~ /^(\w+)$/) {
619                 $oldfolder = $1;
620         } else {
621                 die("Invalid old folder<BR>\n");
622         }
623         
624         if ($newfolder =~ /^(\w+)$/) {
625                 $newfolder = $1;
626         } else {
627                 die("Invalid new folder ($newfolder)<BR>\n");
628         }
629         
630         if ($old =~ /^(\d\d\d\d)$/) {
631                 $old = $1;
632         } else {
633                 die("Invalid old Message<BR>\n");
634         }
635         
636         if ($new =~ /^(\d\d\d\d)$/) {
637                 $new = $1;
638         } else {
639                 die("Invalid old Message<BR>\n");
640         }
641         
642         my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$newfolder";
643         mkdir $path, 0770;
644         my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$oldfolder";
645         opendir(DIR, $path) || die("Unable to open directory\n");
646         my @files = grep /^msg${old}\.\w+$/, readdir(DIR);
647         closedir(DIR);
648         foreach $oldfile (@files) {
649                 my $tmp = $oldfile;
650                 if ($tmp =~ /^(msg${old}.\w+)$/) {
651                         $tmp = $1;
652                         $oldfile = $path . "/$tmp";
653                         $tmp =~ s/msg${old}/msg${new}/;
654                         $newfile = "/var/spool/asterisk/voicemail/$context/$mbox/$newfolder/$tmp";
655 #                       print "Renaming $oldfile to $newfile<BR>\n";
656                         rename($oldfile, $newfile);
657                 }
658         }
659 }
660
661 sub file_copy()
662 {
663         my ($orig, $new) = @_;
664         my $res;
665         my $data;
666         open(IN, "<$orig") || die("Unable to open '$orig'\n");
667         open(OUT, ">$new") || DIE("Unable to open '$new'\n");
668         while(($res = sysread(IN, $data, 4096)) > 0) {
669                 syswrite(OUT, $data, $res);
670         }
671         close(OUT);
672         close(IN);
673 }
674
675 sub message_copy()
676 {
677         my ($context, $mbox, $newmbox, $oldfolder, $old, $new) = @_;
678         my $oldfile, $newfile;
679         return if ($mbox eq $newmbox);
680         
681         if ($mbox =~ /^(\w+)$/) {
682                 $mbox = $1;
683         } else {
684                 die ("Invalid mailbox<BR>\n");
685         }
686
687         if ($newmbox =~ /^(\w+)$/) {
688                 $newmbox = $1;
689         } else {
690                 die ("Invalid new mailbox<BR>\n");
691         }
692         
693         if ($oldfolder =~ /^(\w+)$/) {
694                 $oldfolder = $1;
695         } else {
696                 die("Invalid old folder<BR>\n");
697         }
698         
699         if ($old =~ /^(\d\d\d\d)$/) {
700                 $old = $1;
701         } else {
702                 die("Invalid old Message<BR>\n");
703         }
704         
705         if ($new =~ /^(\d\d\d\d)$/) {
706                 $new = $1;
707         } else {
708                 die("Invalid old Message<BR>\n");
709         }
710         
711         my $path = "/var/spool/asterisk/voicemail/$context/$newmbox";
712         mkdir $path, 0770;
713         my $path = "/var/spool/asterisk/voicemail/$context/$newmbox/INBOX";
714         mkdir $path, 0770;
715         my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$oldfolder";
716         opendir(DIR, $path) || die("Unable to open directory\n");
717         my @files = grep /^msg${old}\.\w+$/, readdir(DIR);
718         closedir(DIR);
719         foreach $oldfile (@files) {
720                 my $tmp = $oldfile;
721                 if ($tmp =~ /^(msg${old}.\w+)$/) {
722                         $tmp = $1;
723                         $oldfile = $path . "/$tmp";
724                         $tmp =~ s/msg${old}/msg${new}/;
725                         $newfile = "/var/spool/asterisk/voicemail/$context/$newmbox/INBOX/$tmp";
726 #                       print "Copying $oldfile to $newfile<BR>\n";
727                         &file_copy($oldfile, $newfile);
728                 }
729         }
730 }
731
732 sub message_delete()
733 {
734         my ($context, $mbox, $folder, $msg) = @_;
735         if ($mbox =~ /^(\w+)$/) {
736                 $mbox = $1;
737         } else {
738                 die ("Invalid mailbox<BR>\n");
739         }
740         if ($context =~ /^(\w+)$/) {
741                 $context = $1;
742         } else {
743                 die ("Invalid context<BR>\n");
744         }
745         if ($folder =~ /^(\w+)$/) {
746                 $folder = $1;
747         } else {
748                 die("Invalid folder<BR>\n");
749         }
750         if ($msg =~ /^(\d\d\d\d)$/) {
751                 $msg = $1;
752         } else {
753                 die("Invalid Message<BR>\n");
754         }
755         my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$folder";
756         opendir(DIR, $path) || die("Unable to open directory\n");
757         my @files = grep /^msg${msg}\.\w+$/, readdir(DIR);
758         closedir(DIR);
759         foreach $oldfile (@files) {
760                 if ($oldfile =~ /^(msg${msg}.\w+)$/) {
761                         $oldfile = $path . "/$1";
762 #                       print "Deleting $oldfile<BR>\n";
763                         unlink($oldfile);
764                 }
765         }
766 }
767
768 sub message_forward()
769 {
770         my ($toindex, @msgs) = @_;
771         my $folder = param('folder');
772         my ($mbox, $context) = split(/\@/, param('mailbox'));
773         my $newmbox = param('forwardto');
774         my $msg;
775         my $msgcount;
776         if (!$context) {
777                 $context = param('context');
778         }
779         if (!$context) {
780                 $context = "default";
781         }
782         $newmbox =~ s/(\w+)(\s+.*)?$/$1/;
783         if (!&validmailbox($context, $newmbox)) {
784                 die("Bah! Not a valid mailbox '$newmbox'\n");
785                 return "";
786         }
787         $msgcount = &msgcount($context, $newmbox, "INBOX");
788         my $txt;
789         if ($newmbox ne $mbox) {
790 #               print header;
791                 foreach $msg (@msgs) {
792 #                       print "Forwarding $msg from $mbox to $newmbox<BR>\n";
793                         &message_copy($context, $mbox, $newmbox, $folder, $msg, sprintf "%04d", $msgcount);
794                         $msgcount++;
795                 }
796                 $txt = "Forwarded messages " . join(', ', @msgs) . "to $newmbox";
797         } else {
798                 $txt = "Can't forward messages to yourself!\n";
799         } 
800         if ($toindex) {
801                 &message_index($folder, $txt);
802         } else {
803                 &message_play($txt, $msgs[0]);
804         }
805 }
806
807 sub message_delete_or_move()
808 {
809         my ($toindex, $del, @msgs) = @_;
810         my $txt;
811         my $path;
812         my $y, $x;
813         my $folder = param('folder');
814         my $newfolder = param('newfolder') unless $del;
815         $newfolder =~ s/^(\w+)\s+.*$/$1/;
816         my ($mbox, $context) = split(/\@/, param('mailbox'));
817         if (!$context) {
818                 $context = param('context');
819         }
820         if (!$context) {
821                 $context = "default";
822         }
823         my $passwd = param('password');
824         my $msgcount = &msgcount($context, $mbox, $folder);
825         my $omsgcount = &msgcount($context, $mbox, $newfolder) if $newfolder;
826 #       print header;
827         if ($newfolder ne $folder) {
828                 $y = 0;
829                 for ($x=0;$x<$msgcount;$x++) {
830                         my $msg = sprintf "%04d", $x;
831                         my $newmsg = sprintf "%04d", $y;
832                         if (grep(/^$msg$/, @msgs)) {
833                                 if ($newfolder) {
834                                         &message_rename($context, $mbox, $folder, $msg, $newfolder, sprintf "%04d", $omsgcount);
835                                         $omsgcount++;
836                                 } else {
837                                         &message_delete($context, $mbox, $folder, $msg);
838                                 }
839                         } else {
840                                 &message_rename($context, $mbox, $folder, $msg, $folder, $newmsg);
841                                 $y++;
842                         }
843                 }
844                 if ($del) {
845                         $txt = "Deleted messages "  . join (', ', @msgs);
846                 } else {
847                         $txt = "Moved messages "  . join (', ', @msgs) . " to $newfolder";
848                 }
849         } else {
850                 $txt = "Can't move a message to the same folder they're in already";
851         }
852         # Not as many messages now
853         $msgcount--;
854         if ($toindex || ($msgs[0] >= $msgcount)) {
855                 &message_index($folder, $txt);  
856         } else {
857                 &message_play($txt, $msgs[0]);
858         }
859 }
860
861 if (param()) {
862         my $folder = param('folder');
863         my $changefolder = param('changefolder');
864         $changefolder =~ s/(\w+)\s+.*$/$1/;
865         
866         my $newfolder = param('newfolder');
867         $newfolder =~ s/^(\w+)\s+.*$/$1/;
868         if ($newfolder && !&validfolder($newfolder)) {
869                 print header;
870                 die("Bah! new folder '$newfolder' isn't a folder.");
871         }
872         $action = param('action');
873         $msgid = param('msgid');
874         if (!$action) {
875                 my ($tmp) = grep /^play\d\d\d\d\.x$/, param;
876                 if ($tmp =~ /^play(\d\d\d\d)/) {
877                         $msgid = $1;
878                         $action = "play";
879                 } else {
880                         print header;
881                         print "No message?<BR>\n";
882                         return;
883                 }
884         }
885         @msgs = param('msgselect');
886         @msgs = ($msgid) unless @msgs;
887         {
888                 ($mailbox) = &check_login();
889                 if (length($mailbox)) {
890                         if ($action eq 'login') {
891                                 &message_index($folder, "Welcome, $mailbox");
892                         } elsif (($action eq 'refresh') || ($action eq 'index')) {
893                                 &message_index($folder, "Welcome, $mailbox");
894                         } elsif ($action eq 'change to ->') {
895                                 if (&validfolder($changefolder)) {
896                                         $folder = $changefolder;
897                                         &message_index($folder, "Welcome, $mailbox");
898                                 } else {
899                                         die("Bah!  Not a valid change to folder '$changefolder'\n");
900                                 }
901                         } elsif ($action eq 'play') {
902                                 &message_play("$mailbox $folder $msgid", $msgid);
903                         } elsif ($action eq 'preferences') {
904                                 &message_prefs("refresh", $msgid);
905                         } elsif ($action eq 'download') {
906                                 &message_audio(1);
907                         } elsif ($action eq 'play ') {
908                                 &message_audio(0);
909                         } elsif ($action eq 'audio') {
910                                 &message_audio(0);
911                         } elsif ($action eq 'delete') {
912                                 &message_delete_or_move(1, 1, @msgs);
913                         } elsif ($action eq 'delete ') {
914                                 &message_delete_or_move(0, 1, @msgs);
915                         } elsif ($action eq 'forward to ->') {
916                                 &message_forward(1, @msgs);
917                         } elsif ($action eq 'forward to -> ') {
918                                 &message_forward(0, @msgs);
919                         } elsif ($action eq 'save to ->') {
920                                 &message_delete_or_move(1, 0, @msgs);
921                         } elsif ($action eq 'save to -> ') {
922                                 &message_delete_or_move(0, 0, @msgs);
923                         } elsif ($action eq 'logout') {
924                                 &login_screen("Logged out!\n");
925                         }
926                 } else {
927                         sleep(1);
928                         &login_screen("Login Incorrect!\n");
929                 }
930         }
931 } else {
932         &login_screen("\&nbsp;");
933 }