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