vmail.cgi 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  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, <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 ("", $category);
  174. }
  175. sub validmailbox()
  176. {
  177. local ($context, $mbox, $filename, $startcat) = @_;
  178. local $category = $startcat;
  179. local @fields;
  180. local (*VMAIL);
  181. if (!$context) {
  182. $context = param('context');
  183. }
  184. if (!$context) {
  185. $context = "default";
  186. }
  187. if (!$filename) {
  188. $filename = "/etc/asterisk/voicemail.conf";
  189. }
  190. if (!$category) {
  191. $category = "general";
  192. }
  193. open(VMAIL, "<$filename") || die("Bleh, no $filename");
  194. while(<VMAIL>) {
  195. chomp;
  196. if (/include\s\"([^\"]+)\"$/) {
  197. ($tmp, $category) = &validmailbox($mbox, $context, "/etc/asterisk/$1");
  198. if ($tmp) {
  199. return ($tmp, $category);
  200. }
  201. } elsif (/\[(.*)\]/) {
  202. $category = $1;
  203. } elsif ($category eq "general") {
  204. if (/([^\s]+)\s*\=\s*(.*)/) {
  205. if ($1 eq "dbname") {
  206. $dbname = $2;
  207. } elsif ($1 eq "dbpass") {
  208. $dbpass = $2;
  209. } elsif ($1 eq "dbhost") {
  210. $dbhost = $2;
  211. } elsif ($1 eq "dbuser") {
  212. $dbuser = $2;
  213. }
  214. }
  215. if ($dbname and $dbpass and $dbhost and $dbuser) {
  216. # db variables are present. Use db for authentication.
  217. my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass);
  218. my $sth = $dbh->prepare(qq{select fullname,context from voicemail where mailbox='$mbox' and password='$pass' and context='$context'});
  219. $sth->execute();
  220. if (($fullname, $category) = $sth->fetchrow_array()) {;
  221. return ($fullname ? $fullname : "unknown", $category);
  222. }
  223. }
  224. } elsif (($category ne "general") && ($category ne "zonemessages") && ($category eq $context)) {
  225. if (/([^\s]+)\s*\=\>?\s*(.*)/) {
  226. @fields = split(/\,\s*/, $2);
  227. if (($mbox eq $1) && ($context eq $category)) {
  228. return ($fields[2] ? $fields[2] : "unknown", $category);
  229. }
  230. }
  231. }
  232. }
  233. return ("", $category);
  234. }
  235. sub mailbox_options()
  236. {
  237. local($context, $current, $filename, $category) = @_;
  238. local (*VMAIL);
  239. local $tmp2;
  240. local $tmp;
  241. if (!$filename) {
  242. $filename = "/etc/asterisk/voicemail.conf";
  243. }
  244. if (!$category) {
  245. $category = "general";
  246. }
  247. # print header;
  248. # print "Including <h2>$filename</h2> while in <h2>$category</h2>...\n";
  249. open(VMAIL, "<$filename") || die("Bleh, no voicemail.conf");
  250. while(<VMAIL>) {
  251. chomp;
  252. s/\;.*$//;
  253. if (/include\s\"([^\"]+)\"$/) {
  254. ($tmp2, $category) = &mailbox_options($context, $current, "/etc/asterisk/$1", $category);
  255. # print "Got '$tmp2'...\n";
  256. $tmp .= $tmp2;
  257. } elsif (/\[(.*)\]/) {
  258. $category = $1;
  259. } elsif ($category eq "general") {
  260. if (/([^\s]+)\s*\=\s*(.*)/) {
  261. if ($1 eq "dbname") {
  262. $dbname = $2;
  263. } elsif ($1 eq "dbpass") {
  264. $dbpass = $2;
  265. } elsif ($1 eq "dbhost") {
  266. $dbhost = $2;
  267. } elsif ($1 eq "dbuser") {
  268. $dbuser = $2;
  269. }
  270. }
  271. if ($dbname and $dbpass and $dbhost and $dbuser) {
  272. # db variables are present. Use db for authentication.
  273. my $dbh = DBI->connect("DBI:mysql:$dbname:$dbhost",$dbuser,$dbpass);
  274. my $sth = $dbh->prepare(qq{select mailbox,fullname,context from voicemail where context='$context' order by mailbox});
  275. $sth->execute();
  276. while (($mailbox, $fullname, $category) = $sth->fetchrow_array()) {
  277. $text = $mailbox;
  278. if ($fullname) {
  279. $text .= " (".$fullname.")";
  280. }
  281. if ($mailbox eq $current) {
  282. $tmp .= "<OPTION SELECTED>$text</OPTION>\n";
  283. } else {
  284. $tmp .= "<OPTION>$text</OPTION>\n";
  285. }
  286. }
  287. return ($tmp, $category);
  288. }
  289. } elsif (($category ne "general") && ($category ne "zonemessages")) {
  290. if (/([^\s]+)\s*\=\>?\s*(.*)/) {
  291. @fields = split(/\,\s*/, $2);
  292. $text = "$1";
  293. if ($fields[1]) {
  294. $text .= " ($fields[1])";
  295. }
  296. if ($1 eq $current) {
  297. $tmp .= "<OPTION SELECTED>$text</OPTION>\n";
  298. } else {
  299. $tmp .= "<OPTION>$text</OPTION>\n";
  300. }
  301. }
  302. }
  303. }
  304. close(VMAIL);
  305. return ($tmp, $category);
  306. }
  307. sub mailbox_list()
  308. {
  309. local ($name, $context, $current) = @_;
  310. local $tmp;
  311. local $text;
  312. local $tmp;
  313. local $opts;
  314. if (!$context) {
  315. $context = "default";
  316. }
  317. $tmp = "<SELECT name=\"$name\">\n";
  318. ($opts) = &mailbox_options($context, $current);
  319. $tmp .= $opts;
  320. $tmp .= "</SELECT>\n";
  321. }
  322. sub msgcount()
  323. {
  324. my ($context, $mailbox, $folder) = @_;
  325. my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder";
  326. if (opendir(DIR, $path)) {
  327. my @msgs = grep(/^msg....\.txt$/, readdir(DIR));
  328. closedir(DIR);
  329. return sprintf "%d", $#msgs + 1;
  330. }
  331. return "0";
  332. }
  333. sub msgcountstr()
  334. {
  335. my ($context, $mailbox, $folder) = @_;
  336. my $count = &msgcount($context, $mailbox, $folder);
  337. if ($count > 1) {
  338. "$count messages";
  339. } elsif ($count > 0) {
  340. "$count message";
  341. } else {
  342. "no messages";
  343. }
  344. }
  345. sub messages()
  346. {
  347. my ($context, $mailbox, $folder) = @_;
  348. my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder";
  349. if (opendir(DIR, $path)) {
  350. my @msgs = sort grep(/^msg....\.txt$/, readdir(DIR));
  351. closedir(DIR);
  352. return map { s/^msg(....)\.txt$/$1/; $_ } @msgs;
  353. }
  354. return ();
  355. }
  356. sub getcookie()
  357. {
  358. my ($var) = @_;
  359. return cookie($var);
  360. }
  361. sub makecookie()
  362. {
  363. my ($format) = @_;
  364. cookie(-name => "format", -value =>["$format"], -expires=>"+1y");
  365. }
  366. sub getfields()
  367. {
  368. my ($context, $mailbox, $folder, $msg) = @_;
  369. my $fields;
  370. if (open(MSG, "</var/spool/asterisk/voicemail/$context/$mailbox/$folder/msg${msg}.txt")) {
  371. while(<MSG>) {
  372. s/\#.*$//g;
  373. if (/^(\w+)\s*\=\s*(.*)$/) {
  374. $fields->{$1} = $2;
  375. }
  376. }
  377. close(MSG);
  378. $fields->{'msgid'} = $msg;
  379. } else { print "<BR>Unable to open '$msg' in '$mailbox', '$folder'\n<B>"; }
  380. $fields;
  381. }
  382. sub message_prefs()
  383. {
  384. my ($nextaction, $msgid) = @_;
  385. my $folder = param('folder');
  386. my $mbox = param('mailbox');
  387. my $context = param('context');
  388. my $passwd = param('password');
  389. my $format = param('format');
  390. if (!$format) {
  391. $format = &getcookie('format');
  392. }
  393. print header;
  394. print <<_EOH;
  395. <TITLE>Asterisk Web-Voicemail: Preferences</TITLE>
  396. <BODY BGCOLOR="white">
  397. $stdcontainerstart
  398. <FORM METHOD="post">
  399. <table width=100% align=center>
  400. <tr><td align=right colspan=3><font size=+2>Web Voicemail Preferences</font></td></tr>
  401. <tr><td align=left><font size=+1>Preferred&nbsp;Audio&nbsp;Format:</font></td><td colspan=2></td></tr>
  402. _EOH
  403. foreach $fmt (sort { $formats{$a}->{'pref'} <=> $formats{$b}->{'pref'} } keys %formats) {
  404. my $clicked = "checked" if $fmt eq $format;
  405. 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";
  406. }
  407. print <<_EOH;
  408. <tr><td align=right colspan=3><input type=submit value="save settings..."></td></tr>
  409. </table>
  410. <input type=hidden name="action" value="$nextaction">
  411. <input type=hidden name="folder" value="$folder">
  412. <input type=hidden name="mailbox" value="$mbox">
  413. <input type=hidden name="context" value="$context">
  414. <input type=hidden name="password" value="$passwd">
  415. <input type=hidden name="msgid" value="$msgid">
  416. $stdcontainerend
  417. </BODY>\n
  418. _EOH
  419. }
  420. sub message_play()
  421. {
  422. my ($message, $msgid) = @_;
  423. my $folder = param('folder');
  424. my ($mbox, $context) = split(/\@/, param('mailbox'));
  425. my $passwd = param('password');
  426. my $format = param('format');
  427. my $fields;
  428. if (!$context) {
  429. $context = param('context');
  430. }
  431. if (!$context) {
  432. $context = "default";
  433. }
  434. my $folders = &folder_list('newfolder', $context, $mbox, $folder);
  435. my $mailboxes = &mailbox_list('forwardto', $context, $mbox);
  436. if (!$format) {
  437. $format = &getcookie('format');
  438. }
  439. if (!$format) {
  440. &message_prefs("play", $msgid);
  441. } else {
  442. print header(-cookie => &makecookie($format));
  443. $fields = &getfields($context, $mbox, $folder, $msgid);
  444. if (!$fields) {
  445. print "<BR>Bah!\n";
  446. return;
  447. }
  448. my $duration = $fields->{'duration'};
  449. if ($duration) {
  450. $duration = sprintf "%d:%02d", $duration/60, $duration % 60;
  451. } else {
  452. $duration = "<i>Unknown</i>";
  453. }
  454. print <<_EOH;
  455. <TITLE>Asterisk Web-Voicemail: $folder Message $msgid</TITLE>
  456. <BODY BGCOLOR="white">
  457. $stdcontainerstart
  458. <FORM METHOD="post">
  459. <table width=100% align=center>
  460. <tr><td align=right colspan=3><font size=+1>$folder Message $msgid</font></td></tr>
  461. _EOH
  462. print <<_EOH;
  463. <tr><td align=center colspan=3>
  464. <table>
  465. <tr><td colspan=2 align=center><font size=+1>$folder <b>$msgid</b></font></td></tr>
  466. <tr><td><b>Message:</b></td><td>$msgid</td></tr>\n
  467. <tr><td><b>Mailbox:</b></td><td>$mbox\@$context</td></tr>\n
  468. <tr><td><b>Folder:</b></td><td>$folder</td></tr>\n
  469. <tr><td><b>From:</b></td><td>$fields->{callerid}</td></tr>\n
  470. <tr><td><b>Duration:</b></td><td>$duration</td></tr>\n
  471. <tr><td><b>Original Date:</b></td><td>$fields->{origdate}</td></tr>\n
  472. <tr><td><b>Original Mailbox:</b></td><td>$fields->{origmailbox}</td></tr>\n
  473. <tr><td><b>Caller Channel:</b></td><td>$fields->{callerchan}</td></tr>\n
  474. <tr><td align=center colspan=2>
  475. <input name="action" type=submit value="index">&nbsp;
  476. <input name="action" type=submit value="delete ">&nbsp;
  477. <input name="action" type=submit value="forward to -> ">&nbsp;
  478. $mailboxes&nbsp;
  479. <input name="action" type=submit value="save to ->">
  480. $folders&nbsp;
  481. <input name="action" type=submit value="play ">
  482. <input name="action" type=submit value="download">
  483. </td></tr>
  484. <tr><td colspan=2 align=center>
  485. <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>
  486. </td></tr></table>
  487. </td></tr>
  488. </table>
  489. <input type=hidden name="folder" value="$folder">
  490. <input type=hidden name="mailbox" value="$mbox">
  491. <input type=hidden name="context" value="$context">
  492. <input type=hidden name="password" value="$passwd">
  493. <input type=hidden name="msgid" value="$msgid">
  494. $stdcontainerend
  495. </BODY>\n
  496. _EOH
  497. }
  498. }
  499. sub message_audio()
  500. {
  501. my ($forcedownload) = @_;
  502. my $folder = &untaint(param('folder'));
  503. my $msgid = &untaint(param('msgid'));
  504. my $mailbox = &untaint(param('mailbox'));
  505. my $context = &untaint(param('context'));
  506. my $format = param('format');
  507. if (!$format) {
  508. $format = &getcookie('format');
  509. }
  510. &untaint($format);
  511. my $path = "/var/spool/asterisk/voicemail/$context/$mailbox/$folder/msg${msgid}.$format";
  512. $msgid =~ /^\d\d\d\d$/ || die("Msgid Liar ($msgid)!");
  513. grep(/^${format}$/, keys %formats) || die("Format Liar ($format)!");
  514. # Mailbox and folder are already verified
  515. if (open(AUDIO, "<$path")) {
  516. $size = -s $path;
  517. $|=1;
  518. if ($forcedownload) {
  519. print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size, -attachment => "msg${msgid}.$format");
  520. } else {
  521. print header(-type=>$formats{$format}->{'mime'}, -Content_length => $size);
  522. }
  523. while(($amt = sysread(AUDIO, $data, 4096)) > 0) {
  524. syswrite(STDOUT, $data, $amt);
  525. }
  526. close(AUDIO);
  527. } else {
  528. die("Hrm, can't seem to open $path\n");
  529. }
  530. }
  531. sub message_index()
  532. {
  533. my ($folder, $message) = @_;
  534. my ($mbox, $context) = split(/\@/, param('mailbox'));
  535. my $passwd = param('password');
  536. my $message2;
  537. my $msgcount;
  538. my $hasmsg;
  539. my $newmessages, $oldmessages;
  540. my $format = param('format');
  541. if (!$format) {
  542. $format = &getcookie('format');
  543. }
  544. if (!$context) {
  545. $context = param('context');
  546. }
  547. if (!$context) {
  548. $context = "default";
  549. }
  550. if ($folder) {
  551. $msgcount = &msgcountstr($context, $mbox, $folder);
  552. $message2 = "&nbsp;&nbsp;&nbsp;Folder '$folder' has " . &msgcountstr($context, $mbox, $folder);
  553. } else {
  554. $newmessages = &msgcount($context, $mbox, "INBOX");
  555. $oldmessages = &msgcount($context, $mbox, "Old");
  556. if (($newmessages > 0) || ($oldmessages < 1)) {
  557. $folder = "INBOX";
  558. } else {
  559. $folder = "Old";
  560. }
  561. $message2 = "You have";
  562. if ($newmessages > 0) {
  563. $message2 .= " <b>$newmessages</b> NEW";
  564. if ($oldmessages > 0) {
  565. $message2 .= "and <b>$oldmessages</b> OLD";
  566. if ($oldmessages != 1) {
  567. $message2 .= " messages.";
  568. } else {
  569. $message2 .= "message.";
  570. }
  571. } else {
  572. if ($newmessages != 1) {
  573. $message2 .= " messages.";
  574. } else {
  575. $message2 .= " message.";
  576. }
  577. }
  578. } else {
  579. if ($oldmessages > 0) {
  580. $message2 .= " <b>$oldmessages</b> OLD";
  581. if ($oldmessages != 1) {
  582. $message2 .= " messages.";
  583. } else {
  584. $message2 .= " message.";
  585. }
  586. } else {
  587. $message2 .= " <b>no</b> messages.";
  588. }
  589. }
  590. }
  591. my $folders = &folder_list('newfolder', $context, $mbox, $folder);
  592. my $cfolders = &folder_list('changefolder', $context, $mbox, $folder);
  593. my $mailboxes = &mailbox_list('forwardto', $context, $mbox);
  594. print header(-cookie => &makecookie($format));
  595. print <<_EOH;
  596. <TITLE>Asterisk Web-Voicemail: $mbox\@$context $folder</TITLE>
  597. <BODY BGCOLOR="white">
  598. $stdcontainerstart
  599. <FORM METHOD="post">
  600. <table width=100% align=center>
  601. <tr><td align=center colspan=2><font size=+2><I>$message</I></font></td></tr>
  602. <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>
  603. <tr><td align=left colspan=2><font size=+1>$message2</font></td></tr>
  604. </table>
  605. <table width=100% align=center cellpadding=0 cellspacing=0>
  606. _EOH
  607. print "<tr><td>&nbsp;Msg</td><td>&nbsp;From</td><td>&nbsp;Duration</td><td>&nbsp;Date</td><td>&nbsp;</td></tr>\n";
  608. print "<tr><td><hr></td><td><hr></td><td><hr></td><td><hr></td><td></td></tr>\n";
  609. foreach $msg (&messages($context, $mbox, $folder)) {
  610. $fields = &getfields($context, $mbox, $folder, $msg);
  611. $duration = $fields->{'duration'};
  612. if ($duration) {
  613. $duration = sprintf "%d:%02d", $duration / 60, $duration % 60;
  614. } else {
  615. $duration = "<i>Unknown</i>";
  616. }
  617. $hasmsg++;
  618. 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";
  619. }
  620. if (!$hasmsg) {
  621. print "<tr><td colspan=4 align=center><P><b><i>No messages</i></b><P></td></tr>";
  622. }
  623. print <<_EOH;
  624. </table>
  625. <table width=100% align=center>
  626. <tr><td align=right colspan=2>
  627. <input type="submit" name="action" value="refresh">&nbsp;
  628. _EOH
  629. if ($hasmsg) {
  630. print <<_EOH;
  631. <input type="submit" name="action" value="delete">&nbsp;
  632. <input type="submit" name="action" value="save to ->">
  633. $folders&nbsp;
  634. <input type="submit" name="action" value="forward to ->">
  635. $mailboxes
  636. _EOH
  637. }
  638. print <<_EOH;
  639. </td></tr>
  640. <tr><td align=right colspan=2>
  641. <input type="submit" name="action" value="preferences">
  642. <input type="submit" name="action" value="logout">
  643. </td></tr>
  644. </table>
  645. <input type=hidden name="folder" value="$folder">
  646. <input type=hidden name="mailbox" value="$mbox">
  647. <input type=hidden name="context" value="$context">
  648. <input type=hidden name="password" value="$passwd">
  649. </FORM>
  650. $stdcontainerend
  651. </BODY>\n
  652. _EOH
  653. }
  654. sub validfolder()
  655. {
  656. my ($folder) = @_;
  657. return grep(/^$folder$/, @validfolders);
  658. }
  659. sub folder_list()
  660. {
  661. my ($name, $context, $mbox, $selected) = @_;
  662. my $f;
  663. my $count;
  664. my $tmp = "<SELECT name=\"$name\">\n";
  665. foreach $f (@validfolders) {
  666. $count = &msgcount($context, $mbox, $f);
  667. if ($f eq $selected) {
  668. $tmp .= "<OPTION SELECTED>$f ($count)</OPTION>\n";
  669. } else {
  670. $tmp .= "<OPTION>$f ($count)</OPTION>\n";
  671. }
  672. }
  673. $tmp .= "</SELECT>";
  674. }
  675. sub message_rename()
  676. {
  677. my ($context, $mbox, $oldfolder, $old, $newfolder, $new) = @_;
  678. my $oldfile, $newfile;
  679. return if ($old eq $new) && ($oldfolder eq $newfolder);
  680. if ($context =~ /^(\w+)$/) {
  681. $context = $1;
  682. } else {
  683. die("Invalid Context<BR>\n");
  684. }
  685. if ($mbox =~ /^(\w+)$/) {
  686. $mbox = $1;
  687. } else {
  688. die ("Invalid mailbox<BR>\n");
  689. }
  690. if ($oldfolder =~ /^(\w+)$/) {
  691. $oldfolder = $1;
  692. } else {
  693. die("Invalid old folder<BR>\n");
  694. }
  695. if ($newfolder =~ /^(\w+)$/) {
  696. $newfolder = $1;
  697. } else {
  698. die("Invalid new folder ($newfolder)<BR>\n");
  699. }
  700. if ($old =~ /^(\d\d\d\d)$/) {
  701. $old = $1;
  702. } else {
  703. die("Invalid old Message<BR>\n");
  704. }
  705. if ($new =~ /^(\d\d\d\d)$/) {
  706. $new = $1;
  707. } else {
  708. die("Invalid old Message<BR>\n");
  709. }
  710. my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$newfolder";
  711. $path =~ /^(.*)$/;
  712. $path = $1;
  713. mkdir $path, 0770;
  714. my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$oldfolder";
  715. opendir(DIR, $path) || die("Unable to open directory\n");
  716. my @files = grep /^msg${old}\.\w+$/, readdir(DIR);
  717. closedir(DIR);
  718. foreach $oldfile (@files) {
  719. my $tmp = $oldfile;
  720. if ($tmp =~ /^(msg${old}.\w+)$/) {
  721. $tmp = $1;
  722. $oldfile = $path . "/$tmp";
  723. $tmp =~ s/msg${old}/msg${new}/;
  724. $newfile = "/var/spool/asterisk/voicemail/$context/$mbox/$newfolder/$tmp";
  725. # print "Renaming $oldfile to $newfile<BR>\n";
  726. rename($oldfile, $newfile);
  727. }
  728. }
  729. }
  730. sub file_copy()
  731. {
  732. my ($orig, $new) = @_;
  733. my $res;
  734. my $data;
  735. $orig =~ /^(.*)$/;
  736. $orig = $1;
  737. $new =~ /^(.*)$/;
  738. $new = $1;
  739. open(IN, "<$orig") || die("Unable to open '$orig'\n");
  740. open(OUT, ">$new") || DIE("Unable to open '$new'\n");
  741. while(($res = sysread(IN, $data, 4096)) > 0) {
  742. syswrite(OUT, $data, $res);
  743. }
  744. close(OUT);
  745. close(IN);
  746. }
  747. sub message_copy()
  748. {
  749. my ($context, $mbox, $newmbox, $oldfolder, $old, $new) = @_;
  750. my $oldfile, $newfile;
  751. return if ($mbox eq $newmbox);
  752. if ($mbox =~ /^(\w+)$/) {
  753. $mbox = $1;
  754. } else {
  755. die ("Invalid mailbox<BR>\n");
  756. }
  757. if ($newmbox =~ /^(\w+)$/) {
  758. $newmbox = $1;
  759. } else {
  760. die ("Invalid new mailbox<BR>\n");
  761. }
  762. if ($oldfolder =~ /^(\w+)$/) {
  763. $oldfolder = $1;
  764. } else {
  765. die("Invalid old folder<BR>\n");
  766. }
  767. if ($old =~ /^(\d\d\d\d)$/) {
  768. $old = $1;
  769. } else {
  770. die("Invalid old Message<BR>\n");
  771. }
  772. if ($new =~ /^(\d\d\d\d)$/) {
  773. $new = $1;
  774. } else {
  775. die("Invalid old Message<BR>\n");
  776. }
  777. my $path = "/var/spool/asterisk/voicemail/$context/$newmbox";
  778. $path =~ /^(.*)$/;
  779. $path = $1;
  780. mkdir $path, 0770;
  781. my $path = "/var/spool/asterisk/voicemail/$context/$newmbox/INBOX";
  782. $path =~ /^(.*)$/;
  783. $path = $1;
  784. mkdir $path, 0770;
  785. my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$oldfolder";
  786. opendir(DIR, $path) || die("Unable to open directory\n");
  787. my @files = grep /^msg${old}\.\w+$/, readdir(DIR);
  788. closedir(DIR);
  789. foreach $oldfile (@files) {
  790. my $tmp = $oldfile;
  791. if ($tmp =~ /^(msg${old}.\w+)$/) {
  792. $tmp = $1;
  793. $oldfile = $path . "/$tmp";
  794. $tmp =~ s/msg${old}/msg${new}/;
  795. $newfile = "/var/spool/asterisk/voicemail/$context/$newmbox/INBOX/$tmp";
  796. # print "Copying $oldfile to $newfile<BR>\n";
  797. &file_copy($oldfile, $newfile);
  798. }
  799. }
  800. }
  801. sub message_delete()
  802. {
  803. my ($context, $mbox, $folder, $msg) = @_;
  804. if ($mbox =~ /^(\w+)$/) {
  805. $mbox = $1;
  806. } else {
  807. die ("Invalid mailbox<BR>\n");
  808. }
  809. if ($context =~ /^(\w+)$/) {
  810. $context = $1;
  811. } else {
  812. die ("Invalid context<BR>\n");
  813. }
  814. if ($folder =~ /^(\w+)$/) {
  815. $folder = $1;
  816. } else {
  817. die("Invalid folder<BR>\n");
  818. }
  819. if ($msg =~ /^(\d\d\d\d)$/) {
  820. $msg = $1;
  821. } else {
  822. die("Invalid Message<BR>\n");
  823. }
  824. my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$folder";
  825. opendir(DIR, $path) || die("Unable to open directory\n");
  826. my @files = grep /^msg${msg}\.\w+$/, readdir(DIR);
  827. closedir(DIR);
  828. foreach $oldfile (@files) {
  829. if ($oldfile =~ /^(msg${msg}.\w+)$/) {
  830. $oldfile = $path . "/$1";
  831. # print "Deleting $oldfile<BR>\n";
  832. unlink($oldfile);
  833. }
  834. }
  835. }
  836. sub message_forward()
  837. {
  838. my ($toindex, @msgs) = @_;
  839. my $folder = param('folder');
  840. my ($mbox, $context) = split(/\@/, param('mailbox'));
  841. my $newmbox = param('forwardto');
  842. my $msg;
  843. my $msgcount;
  844. if (!$context) {
  845. $context = param('context');
  846. }
  847. if (!$context) {
  848. $context = "default";
  849. }
  850. $newmbox =~ s/(\w+)(\s+.*)?$/$1/;
  851. if (!&validmailbox($context, $newmbox)) {
  852. die("Bah! Not a valid mailbox '$newmbox'\n");
  853. return "";
  854. }
  855. my $txt;
  856. $context = &untaint($context);
  857. $newmbox = &untaint($newmbox);
  858. my $path = "/var/spool/asterisk/voicemail/$context/$newmbox/INBOX";
  859. if (&lock_path($path) == 0) {
  860. $msgcount = &msgcount($context, $newmbox, "INBOX");
  861. if ($newmbox ne $mbox) {
  862. # print header;
  863. foreach $msg (@msgs) {
  864. # print "Forwarding $msg from $mbox to $newmbox<BR>\n";
  865. &message_copy($context, $mbox, $newmbox, $folder, $msg, sprintf "%04d", $msgcount);
  866. $msgcount++;
  867. }
  868. $txt = "Forwarded messages " . join(', ', @msgs) . "to $newmbox";
  869. } else {
  870. $txt = "Can't forward messages to yourself!\n";
  871. }
  872. &unlock_path($path);
  873. } else {
  874. $txt = "Cannot forward messages: Unable to lock path.\n";
  875. }
  876. if ($toindex) {
  877. &message_index($folder, $txt);
  878. } else {
  879. &message_play($txt, $msgs[0]);
  880. }
  881. }
  882. sub message_delete_or_move()
  883. {
  884. my ($toindex, $del, @msgs) = @_;
  885. my $txt;
  886. my $path;
  887. my $y, $x;
  888. my $folder = param('folder');
  889. my $newfolder = param('newfolder') unless $del;
  890. $newfolder =~ s/^(\w+)\s+.*$/$1/;
  891. my ($mbox, $context) = split(/\@/, param('mailbox'));
  892. if (!$context) {
  893. $context = param('context');
  894. }
  895. if (!$context) {
  896. $context = "default";
  897. }
  898. my $passwd = param('password');
  899. $context = &untaint($context);
  900. $mbox = &untaint($mbox);
  901. $folder = &untaint($folder);
  902. my $path = "/var/spool/asterisk/voicemail/$context/$mbox/$folder";
  903. if (&lock_path($path) == 0) {
  904. my $msgcount = &msgcount($context, $mbox, $folder);
  905. my $omsgcount = &msgcount($context, $mbox, $newfolder) if $newfolder;
  906. # print header;
  907. if ($newfolder ne $folder) {
  908. $y = 0;
  909. for ($x=0;$x<$msgcount;$x++) {
  910. my $msg = sprintf "%04d", $x;
  911. my $newmsg = sprintf "%04d", $y;
  912. if (grep(/^$msg$/, @msgs)) {
  913. if ($newfolder) {
  914. &message_rename($context, $mbox, $folder, $msg, $newfolder, sprintf "%04d", $omsgcount);
  915. $omsgcount++;
  916. } else {
  917. &message_delete($context, $mbox, $folder, $msg);
  918. }
  919. } else {
  920. &message_rename($context, $mbox, $folder, $msg, $folder, $newmsg);
  921. $y++;
  922. }
  923. }
  924. if ($del) {
  925. $txt = "Deleted messages " . join (', ', @msgs);
  926. } else {
  927. $txt = "Moved messages " . join (', ', @msgs) . " to $newfolder";
  928. }
  929. } else {
  930. $txt = "Can't move a message to the same folder they're in already";
  931. }
  932. &unlock_path($path);
  933. } else {
  934. $txt = "Cannot move/delete messages: Unable to lock path.\n";
  935. }
  936. # Not as many messages now
  937. $msgcount--;
  938. if ($toindex || ($msgs[0] >= $msgcount)) {
  939. &message_index($folder, $txt);
  940. } else {
  941. &message_play($txt, $msgs[0]);
  942. }
  943. }
  944. if (param()) {
  945. my $folder = param('folder');
  946. my $changefolder = param('changefolder');
  947. $changefolder =~ s/(\w+)\s+.*$/$1/;
  948. my $newfolder = param('newfolder');
  949. $newfolder =~ s/^(\w+)\s+.*$/$1/;
  950. if ($newfolder && !&validfolder($newfolder)) {
  951. print header;
  952. die("Bah! new folder '$newfolder' isn't a folder.");
  953. }
  954. $action = param('action');
  955. $msgid = param('msgid');
  956. if (!$action) {
  957. my ($tmp) = grep /^play\d\d\d\d\.x$/, param;
  958. if ($tmp =~ /^play(\d\d\d\d)/) {
  959. $msgid = $1;
  960. $action = "play";
  961. } else {
  962. print header;
  963. print "No message?<BR>\n";
  964. return;
  965. }
  966. }
  967. @msgs = param('msgselect');
  968. @msgs = ($msgid) unless @msgs;
  969. {
  970. ($mailbox) = &check_login();
  971. if (length($mailbox)) {
  972. if ($action eq 'login') {
  973. &message_index($folder, "Welcome, $mailbox");
  974. } elsif (($action eq 'refresh') || ($action eq 'index')) {
  975. &message_index($folder, "Welcome, $mailbox");
  976. } elsif ($action eq 'change to ->') {
  977. if (&validfolder($changefolder)) {
  978. $folder = $changefolder;
  979. &message_index($folder, "Welcome, $mailbox");
  980. } else {
  981. die("Bah! Not a valid change to folder '$changefolder'\n");
  982. }
  983. } elsif ($action eq 'play') {
  984. &message_play("$mailbox $folder $msgid", $msgid);
  985. } elsif ($action eq 'preferences') {
  986. &message_prefs("refresh", $msgid);
  987. } elsif ($action eq 'download') {
  988. &message_audio(1);
  989. } elsif ($action eq 'play ') {
  990. &message_audio(0);
  991. } elsif ($action eq 'audio') {
  992. &message_audio(0);
  993. } elsif ($action eq 'delete') {
  994. &message_delete_or_move(1, 1, @msgs);
  995. } elsif ($action eq 'delete ') {
  996. &message_delete_or_move(0, 1, @msgs);
  997. } elsif ($action eq 'forward to ->') {
  998. &message_forward(1, @msgs);
  999. } elsif ($action eq 'forward to -> ') {
  1000. &message_forward(0, @msgs);
  1001. } elsif ($action eq 'save to ->') {
  1002. &message_delete_or_move(1, 0, @msgs);
  1003. } elsif ($action eq 'save to -> ') {
  1004. &message_delete_or_move(0, 0, @msgs);
  1005. } elsif ($action eq 'logout') {
  1006. &login_screen("Logged out!\n");
  1007. }
  1008. } else {
  1009. sleep(1);
  1010. &login_screen("Login Incorrect!\n");
  1011. }
  1012. }
  1013. } else {
  1014. &login_screen("\&nbsp;");
  1015. }