2 # Display a form for replying to or composing an email
4 require './mailboxes-lib.pl';
6 &can_user($in{'user'}) || &error($text{'mail_ecannot'});
7 @uinfo = &get_mail_user($in{'user'});
8 @uinfo || &error($text{'view_eugone'});
9 $euser = &urlize($in{'user'});
11 @folders = &list_user_folders($in{'user'});
12 $folder = $folders[$in{'folder'}];
14 # Composing a new email
15 if (defined($in{'html'})) {
16 $html_edit = $in{'html'};
19 $html_edit = $config{'html_edit'} == 2 ? 1 : 0;
21 $sig = &get_signature($in{'user'});
23 $sig =~ s/\n/<br>\n/g;
24 $quote = "<html><body></body></html>";
27 $quote = "\n\n$sig" if ($sig);
30 &mail_page_header($text{'compose_title'}, undef,
31 $html_edit ? "onload='xinha_init()'" : "",
32 &folder_link($in{'user'}, $folder));
35 # Replying or forwarding
36 if ($in{'mailforward'} ne '') {
38 @mailforward = sort { $a <=> $b }
39 split(/\0/, $in{'mailforward'});
40 @mails = &mailbox_list_mails(
41 $mailforward[0], $mailforward[@mailforward-1],
43 $mail = $mails[$mailforward[0]];
44 @fwdmail = map { $mails[$_] } @mailforward;
48 @mails = &mailbox_list_mails($in{'idx'}, $in{'idx'},
50 $mail = $mails[$in{'idx'}];
53 &check_modification($folder) if ($in{'delete'});
54 $mail || &error($text{'mail_eexists'});
56 # Find the body parts and set the character set
57 ($textbody, $htmlbody, $body) =
58 &find_body($mail, $config{'view_html'});
59 $main::force_charset = &get_mail_charset($mail, $body);
62 # Just delete the email
63 if (!$in{'confirm'} && &need_delete_warn($folder)) {
64 # Need to ask for confirmation before deleting
65 &mail_page_header($text{'confirm_title'}, undef, undef,
66 &folder_link($in{'user'}, $folder));
67 print &ui_confirmation_form(
69 $text{'confirm_warn3'}."<br>".
70 ($config{'delete_warn'} ne 'y' ?
71 $text{'confirm_warn2'} :
72 $text{'confirm_warn4'}),
73 [ &inputs_to_hiddens(\%in) ],
74 [ [ 'confirm', $text{'confirm_ok'} ] ],
76 &mail_page_footer("view_mail.cgi?idx=$in{'idx'}&folder=$in{'folder'}&user=$euser",
78 "list_mail.cgi?folder=$in{'folder'}&user=$euser",
80 "", $text{'index_return'});
83 &lock_folder($folder);
84 &mailbox_delete_mail($folder, $mail);
85 &unlock_folder($folder);
86 &webmin_log("delmail", undef, undef,
87 { 'from' => $folder->{'file'},
89 &redirect("list_mail.cgi?folder=$in{'folder'}&user=$euser");
92 elsif ($in{'print'}) {
93 # Show email for printing
95 &ui_print_header(undef, &decode_mimewords(
96 $mail->{'header'}->{'subject'}));
97 &show_mail_printable($mail, $body, $textbody, $htmlbody);
98 print "<script>window.print();</script>\n";
102 elsif ($in{'mark1'} || $in{'mark2'}) {
103 # Just mark the message
104 $mode = $in{'mark1'} ? $in{'mode1'} : $in{'mode2'};
105 &set_mail_read($folder, $mail, $mode);
106 $perpage = $folder->{'perpage'} || $config{'perpage'};
107 $s = int((@mails - $in{'idx'} - 1) / $perpage) * $perpage;
108 &redirect("list_mail.cgi?start=$s&folder=$in{'folder'}&user=$euser");
111 elsif ($in{'detach'}) {
112 # Detach some attachment to a directory on the server
113 &error_setup($text{'detach_err'});
114 $in{'dir'} || &error($text{'detach_edir'});
115 $in{'dir'} = "$uinfo[7]/$in{'dir'}"
116 if ($in{'dir'} !~ /^\//);
119 if ($in{'attach'} eq '*') {
120 # Detaching all attachments, under their filenames
121 @dattach = grep { $_->{'idx'} ne $in{'bindex'} }
122 @{$mail->{'attach'}};
125 # Just one attachment
126 @dattach = ( $mail->{'attach'}->[$in{'attach'}] );
130 foreach $attach (@dattach) {
133 # Just write to the filename in the directory
135 if ($attach->{'filename'}) {
136 $fn = &decode_mimewords(
137 $attach->{'filename'});
140 $attach->{'type'} =~ /\/(\S+)$/;
143 $path = "$in{'dir'}/$fn";
146 # Assume a full path was given
152 &switch_to_user($in{'user'});
153 for($i=0; $i<@dattach; $i++) {
154 # Try to write the files
155 &open_tempfile(FILE, ">$paths[$i]", 1, 1) ||
156 &error(&text('detach_eopen',
157 "<tt>$paths[$i]</tt>", $!));
158 (print FILE $dattach[$i]->{'data'}) ||
159 &error(&text('detach_ewrite',
160 "<tt>$paths[$i]</tt>", $!));
162 &error(&text('detach_ewrite',
163 "<tt>$paths[$i]</tt>", $!));
167 # Show a message about the new files
168 &mail_page_header($text{'detach_title'}, undef, undef,
169 &folder_link($in{'user'}, $folder));
171 for($i=0; $i<@dattach; $i++) {
172 local $sz = (int(length($dattach[$i]->{'data'}) /
174 print "<p>",&text('detach_ok',
175 "<tt>$paths[$i]</tt>", $sz),"<p>\n";
178 &mail_page_footer("view_mail.cgi?idx=$in{'idx'}&folder=$in{'folder'}&user=$euser", $text{'view_return'},
179 "list_mail.cgi?folder=$in{'folder'}&user=$euser", $text{'mail_return'},
180 "", $text{'index_return'});
183 elsif ($in{'black'}) {
184 # Add sender to global SpamAssassin blacklist, and tell user
185 &mail_page_header($text{'black_title'});
187 &foreign_require("spam", "spam-lib.pl");
188 local $conf = &spam::get_config();
189 local @from = map { @{$_->{'words'}} }
190 &spam::find("blacklist_from", $conf);
191 local %already = map { $_, 1 } @from;
192 local ($spamfrom) = &address_parts($mail->{'header'}->{'from'});
193 if ($already{$spamfrom}) {
194 print "<b>",&text('black_already',
195 "<tt>$spamfrom</tt>"),"</b><p>\n";
198 push(@from, $spamfrom);
199 &spam::save_directives($conf, 'blacklist_from',
202 print "<b>",&text('black_done',
203 "<tt>$spamfrom</tt>"),"</b><p>\n";
206 &mail_page_footer("list_mail.cgi?folder=$in{'folder'}&user=$euser", $text{'mail_return'}, "", $text{'index_return'});
209 elsif ($in{'razor'}) {
210 # Report message to Razor and tell user
211 &mail_page_header($text{'razor_title'});
213 print "<b>$text{'razor_report'}</b>\n";
215 local $cmd = &spam_report_cmd($in{'user'});
216 local $temp = &transname();
217 &send_mail($mail, $temp, 0, 1);
218 &open_execute_command(OUT, "$cmd <$temp 2>&1", 1);
221 print &html_escape($_);
222 $error++ if (/failed/i);
228 print "<b>$text{'razor_err'}</b><p>\n";
231 if ($config{'spam_del'}) {
233 &lock_folder($folder);
234 &mailbox_delete_mail($folder, $mail);
235 &unlock_folder($folder);
236 print "<b>$text{'razor_deleted'}</b><p>\n";
239 print "<b>$text{'razor_done'}</b><p>\n";
243 &mail_page_footer("list_mail.cgi?folder=$in{'folder'}&user=$euser", $text{'mail_return'}, "", $text{'index_return'});
249 @attach = @{$mail->{'attach'}};
253 # Remove all non-body attachments
254 local $newmail = { 'headers' => $mail->{'headers'},
255 'header' => $mail->{'header'},
256 'fromline' => $mail->{'fromline'} };
257 foreach $a (@attach) {
258 if ($a->{'type'} eq 'text/plain' ||
259 $a->{'type'} eq 'text') {
260 $newmail->{'attach'} = [ $a ];
264 &lock_folder($folder);
265 &mailbox_modify_mail($mail, $newmail, $folder);
266 &unlock_folder($folder);
267 &redirect("list_mail.cgi?user=$euser&folder=$in{'folder'}");
272 # Editing an existing message, so keep same fields
273 $to = $mail->{'header'}->{'to'};
274 $rto = $mail->{'header'}->{'reply-to'};
275 $from = $mail->{'header'}->{'from'};
276 $cc = $mail->{'header'}->{'cc'};
277 $ouser = $1 if ($from =~ /^(\S+)\@/);
280 if (!$in{'forward'} && !@mailforward) {
281 # Replying to a message, so set To: field
282 $to = $mail->{'header'}->{'reply-to'};
283 $to = $mail->{'header'}->{'from'} if (!$to);
286 # If replying to all, add any addresses in the original
287 # To: or Cc: to our new Cc: address.
288 $cc = $mail->{'header'}->{'to'};
289 $cc .= ", ".$mail->{'header'}->{'cc'}
290 if ($mail->{'header'}->{'cc'});
294 # Convert MIMEwords in headers to 8 bit for display
295 $to = &decode_mimewords($to);
296 $rto = &decode_mimewords($rto);
297 $cc = &decode_mimewords($cc);
298 $bcc = &decode_mimewords($bcc);
300 # Work out new subject, depending on whether we are replying
301 # our forwarding a message (or neither)
302 local $qu = !$in{'enew'} &&
303 (!$in{'forward'} || !$config{'fwd_mode'});
304 $subject = &html_escape(&decode_mimewords(
305 $mail->{'header'}->{'subject'}));
306 $subject = "Re: ".$subject if ($subject !~ /^Re/i && !$in{'forward'} &&
307 !@mailforward && !$in{'enew'});
308 $subject = "Fwd: ".$subject if ($subject !~ /^Fwd/i &&
309 ($in{'forward'} || @mailforward));
311 # Construct the initial mail text
312 $sig = &get_signature($in{'user'});
313 ($quote, $html_edit, $body) = "ed_message($mail, $qu, $sig);
314 if ($in{'forward'} || $in{'enew'}) {
315 @attach = grep { $_ ne $body } @attach;
323 $in{'forward'} || @mailforward ? $text{'forward_title'} :
324 $in{'enew'} ? $text{'enew_title'} :
325 $text{'reply_title'}, undef,
326 $html_edit ? "onload='xinha_init()'" : "",
327 &folder_link($in{'user'}, $folder));
330 # Show form start, with upload progress tracker hook
332 $onsubmit = &read_parse_mime_javascript($upid, [ map { "attach$_" } (0..10) ]);
333 print &ui_form_start("send_mail.cgi?id=$upid", "form-data", undef, $onsubmit);
335 # Output various hidden fields
336 print &ui_hidden("user", $in{'user'});
337 print &ui_hidden("ouser", $ouser);
338 print &ui_hidden("idx", $in{'idx'});
339 print &ui_hidden("folder", $in{'folder'});
340 print &ui_hidden("new", $in{'new'});
341 print &ui_hidden("enew", $in{'enew'});
343 print &ui_hidden("sub", $s);
345 print &ui_hidden("charset", $main::force_charset);
347 # Start tabs for from / to / cc / bcc
348 # Subject is separate
349 print &ui_table_start($text{'reply_headers'}, "width=100%", 2);
350 @tds = ( "width=10%", "width=90% nowrap" );
351 @tabs = ( [ "from", $text{'reply_tabfrom'} ],
352 [ "to", $text{'reply_tabto'} ],
353 [ "cc", $text{'reply_tabcc'} ],
354 [ "bcc", $text{'reply_tabbcc'} ],
355 [ "options", $text{'reply_taboptions'} ] );
356 print &ui_table_row(undef, &ui_tabs_start(\@tabs, "tab", "to", 0), 2);
359 $from ||= &get_user_from_address(\@uinfo);
360 @froms = split(/\s+/, $access{'from'});
361 if ($access{'fmode'} == 0) {
363 $frominput = &ui_address_field("from", $from, 1, 0);
365 elsif ($access{'fmode'} == 1) {
366 # Current username at some domains
367 local $u = $from || $ouser || $in{'user'};
369 $frominput = &ui_select("from", $from,
370 $access{'fromname'} ?
371 [ map { [ "$access{'fromname'} <$u\@$_>",
372 "$u\@$_" ] } @froms ] :
373 [ map { "$u\@$_" } @froms ]);
375 elsif ($access{'fmode'} == 2) {
376 # Listed from addresses
377 $frominput = &ui_select("from", $from,
378 $access{'fromname'} ?
379 [ map { [ "$access{'fromname'} <$_>", $_ ] }
383 elsif ($access{'fmode'} == 3) {
384 # Fixed address in fixed domain
385 $frominput = "<tt>$ouser\@$access{'from'}</tt>".
386 &ui_hidden("from", "$ouser\@$access{'from'}");
388 print &ui_tabs_start_tabletab("tab", "from");
389 print &ui_table_row($text{'mail_from'}, $frominput, 1, \@tds);
390 print &ui_tabs_end_tabletab();
393 print &ui_tabs_start_tabletab("tab", "to");
394 print &ui_table_row($text{'mail_to'}, &ui_address_field("to", $to, 0, 1),
396 print &ui_tabs_end_tabletab();
399 print &ui_tabs_start_tabletab("tab", "cc");
400 print &ui_table_row($text{'mail_cc'}, &ui_address_field("cc", $cc, 0, 1),
402 print &ui_tabs_end_tabletab();
405 $bcc ||= $config{'bcc_to'};
406 print &ui_tabs_start_tabletab("tab", "bcc");
407 print &ui_table_row($text{'mail_bcc'}, &ui_address_field("bcc", $bcc, 0, 1),
409 print &ui_tabs_end_tabletab();
411 # Show tab for options
412 print &ui_tabs_start_tabletab("tab", "options");
413 print &ui_table_row($text{'mail_pri'},
414 &ui_select("pri", "",
415 [ [ 1, $text{'mail_highest'} ],
416 [ 2, $text{'mail_high'} ],
417 [ "", $text{'mail_normal'} ],
418 [ 4, $text{'mail_low'} ],
419 [ 5, $text{'mail_lowest'} ] ]), 1, \@tds);
420 print &ui_tabs_end_tabletab();
421 print &ui_tabs_end();
423 # Subject field, outside tabs
424 print &ui_table_row($text{'mail_subject'},
425 &ui_textbox("subject", $subject, 40, 0, undef,
426 "style='width:95%'"), 1, \@tds);
427 print &ui_table_end();
429 # Create link for switching to HTML/text mode for new mail
433 push(@bodylinks, "<a href='reply_mail.cgi?folder=$in{'folder'}&user=$euser&new=1&html=0'>$text{'reply_html0'}</a>");
436 push(@bodylinks, "<a href='reply_mail.cgi?folder=$in{'folder'}&user=$euser&new=1&html=1'>$text{'reply_html1'}</a>");
440 # Output message body input
441 print &ui_table_start($text{'reply_body'}, "width=100%", 2, undef,
442 &ui_links_row(\@bodylinks));
444 # Output HTML editor textarea
446 <script type="text/javascript">
447 _editor_url = "$gconfig{'webprefix'}/$module_name/xinha/";
450 <script type="text/javascript" src="xinha/XinhaCore.js"></script>
452 <script type="text/javascript">
453 xinha_init = function()
455 xinha_editors = [ "body" ];
457 xinha_config = new Xinha.Config();
458 xinha_config.hideSomeButtons(" print showhelp about killword toggleborders ");
459 xinha_editors = Xinha.makeEditors(xinha_editors, xinha_config, xinha_plugins);
460 Xinha.startEditors(xinha_editors);
464 print &ui_table_row(undef,
465 &ui_textarea("body", $quote, 40, 80, undef, 0,
466 "style='width:99%' id=body"), 2);
469 # Show text editing area
470 $wm = $config{'wrap_mode'};
472 $wcols = $config{'wrap_compose'};
473 print &ui_table_row(undef,
474 &ui_textarea("body", $quote, 20,
476 $wcols ? "hard" : "",
478 $wcols ? "" : "style='width:100%'"), 2);
480 if (&has_command("ispell")) {
481 print &ui_table_row(undef,
482 &ui_checkbox("spell", 1, $text{'reply_spell'}, 0), 2);
484 print &ui_table_end();
485 print &ui_hidden("html_edit", $html_edit);
487 # Display forwarded attachments
488 $viewurl = "view_mail.cgi?idx=$in{'idx'}&user=$euser&".
489 "&folder=$folder->{'index'}$subs";
490 $detachurl = "detach.cgi?idx=$in{'idx'}&user=$euser&".
491 "&folder=$folder->{'index'}$subs";
492 $mailurl = "view_mail.cgi?user=$euser&folder=$folder->{'index'}$subs";
494 &attachments_table(\@attach, $folder, $viewurl, $detachurl,
495 $mailurl, 'idx', "forward");
498 # Display forwarded mails
500 &attachments_table(\@fwdmail, $folder, $viewurl, $detachurl,
502 foreach $f (@mailforward) {
503 print &ui_hidden("mailforward", $f);
507 # Display new attachment fields
508 &show_attachments_fields(3, $access{'canattach'});
510 print &ui_form_end([ [ undef, $text{'reply_send'} ] ]);
512 &mail_page_footer("list_mail.cgi?folder=$in{'folder'}&user=$in{'user'}",
513 $text{'mail_return'},
514 "", $text{'index_return'});
520 @sub = split(/\0/, $in{'sub'});
521 $subs = join("", map { "&sub=$_" } @sub);
523 # We are looking at a mail within a mail ..
524 local $amail = &extract_mail(
525 $mail->{'attach'}->[$s]->{'data'});