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