vmail.cgi 29 KB

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