roundcube / roundcubemail

The Roundcube Webmail suite
https://roundcube.net
GNU General Public License v3.0
5.79k stars 1.62k forks source link

Attachment not displayed if Content-Disposition header value is an extension #3086

Closed rcubetrac closed 13 years ago

rcubetrac commented 13 years ago

Reported by Xanco on 13 Oct 2010 09:46 UTC as Trac ticket #1487051

Roundcube not displays mail attachments if the Content-Disposition header is neither "inline" nor "attachment", but an extension.

RFC 2183 allow for Content-Disposition header to have an IANA registered extension (or a custom x- prefixed value) beside "inline" and "attachment" values. Roudcube only checks for "inline" and "attach*" values and discards attchments that have an extension value.

I have successfully created a workaround by inserting the next extra statement into rcube_message.php at line 439 in RoudCube version 0.4.2:

...
// part is a file/attachment
else if (preg_match('/^(inline|attach)/', $mail_part->disposition) ||
$mail_part->headers[|| (empty($mail_part->disposition) && $mail_part->filename)
# WORKAROUND STATEMENT:
|| preg_match('/[-a-zA-Z0-9_+.]('content-id'])+\/[-a-zA-Z0-9+_.]+/', $mail_part->disposition)
) {
...

Migrated-From: http://trac.roundcube.net/ticket/1487051

rcubetrac commented 13 years ago

Comment by @alecpl on 13 Oct 2010 10:59 UTC

And the RFC says:

   Unrecognized parameters should be ignored. Unrecognized disposition
   types should be treated as `attachment'. The choice of `attachment'
   for unrecognized types is made because a sender who goes to the
   trouble of producing a Content-Disposition header with a new
   disposition type is more likely aiming for something more elaborate
   than inline presentation.

About the change, maybe we should just change

(empty($mail_part->disposition) && $mail_part->filename)

to

($mail_part->filename)
rcubetrac commented 13 years ago

Milestone changed by @alecpl on 13 Oct 2010 10:59 UTC

later => 0.5-beta

rcubetrac commented 13 years ago

Comment by @thomascube on 15 Oct 2010 15:55 UTC

Just removing empty($mail_part->disposition) could have some unwanted side effects. I'd just extend the checking regex with

preg_match('/^(inline|attach|[-a-z0-9_+.]+\/[-a-z0-9+_.]+)/i', $mail_part->disposition)

BTW: I couldn't find a list of IANA registered extension tokens...

rcubetrac commented 13 years ago

Owner changed by @thomascube on 15 Oct 2010 15:55 UTC

=> none

rcubetrac commented 13 years ago

Severity changed by @thomascube on 15 Oct 2010 15:55 UTC

major => normal

rcubetrac commented 13 years ago

Comment by nick lock on 18 Oct 2010 14:55 UTC

I am having a very similar problem: Some versions of Outlook create garbage "Content-Type:" lines in the MIME boundaries, which causes RoundCube not to display an attachment.

For example:

X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2911.0)
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3664

...

Content-Type: application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608;
        name="Advert.doc"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
        filename="Advert.doc"

The RFC that I found (http://www.w3.org/Protocols/rfc1341/4_Content-Type.html) says that "." in the subtype field is disallowed... but other mail clients "gracefully ignore" this and allow the attachment to be handled. RoundCube only shows the attachment when you hit "forward" on the mail; in the "forward" compose window the attachment is present in the left hand pane.

Manually editing the mail to read:

Content-Transfer-Encoding: base64
Content-Type: application/pdf;
 charset=UTF-8;
 name=Advert.doc
Content-Disposition: attachment;
 filename=Advert.doc

allows RoundCube to display the attachment download link.

Whilst it appears that Outlook is to blame for generating non-RFC compliant MIME boundaries, it would be nice if RoundCube could handle this as other mail clients do. A historic build of RoundCube (20ccd472 which we have for legacy purposes) handles the invalid line "correctly" and allows downloading of the attachment.

rcubetrac commented 13 years ago

Comment by @alecpl on 20 Oct 2010 10:47 UTC

@nick.lock: RFC2045 doesn't forbids a dot in content-type name. So, we cannot just truncate the string after a dot. However, I think we could do an exception for known types as application/pdf.

rcubetrac commented 13 years ago

Comment by nick lock on 20 Oct 2010 11:38 UTC

Alec, thank you for the guidance as to the correct RFC to be used here - I see that the "." was indeed removed from the list of disallowed characters, and the information I was reading was outdated.

Just to clarify, I am not asking for RC to alter the content of a mail in any way. I was able to work around the non-displaying of an attachment download link by removing what seemed to me to be garbage in the "Content-Type" line... so if this "garbage" is RFC compliant, then something may have changed in the way that RC handles the "Content-Type" line?

I also withdraw my statement that Outlook is creating non-RFC compliant output :)

rcubetrac commented 13 years ago

Comment by @alecpl on 20 Oct 2010 11:43 UTC

@nick.lock: Your issue fixed in [2ae58f1b(8bac7e98],), e0bd7054. I have a one question is this string ("A520491B_3BF7_494D_8855_7FAC2C6C0608") used somewhere in the message? Is this maybe a boundary string? Please, attach the whole sample message.

rcubetrac commented 13 years ago

Comment by @alecpl on 20 Oct 2010 12:10 UTC

@thomasb: http://www.iana.org/assignments/mail-cont-disp/

rcubetrac commented 13 years ago

Comment by @alecpl on 20 Oct 2010 12:24 UTC

Fixed in 8794f16c.

rcubetrac commented 13 years ago

Status changed by @alecpl on 20 Oct 2010 12:24 UTC

new => closed

rcubetrac commented 13 years ago

Comment by nick lock on 20 Oct 2010 14:47 UTC

Alec, I can confirm that [fixes my problem. Thank you again for your prompt attention!

The string appended to the Content-Type line does not occur anywhere else in the mail. I have included below the bulk of the email, suitably redacted to protect the readability of this page and the identity of our customer ;)

Return-Path: <xx@xspa.org.uk>
Delivered-To: xspa.org.uk-xx@xspa.org.uk
Delivered-To: xspa.org.uk-xx@xspa.org.uk
Received: (qmail 29091 invoked from network); 18 Oct 2010 11:48:44 +0100
Received: from scanner-3.mail.exa.net.uk (HELO scanner-3.tcm.exa.net.uk) (82.219.5.147)
  by fs-3.mail.exa.net.uk with SMTP; 18 Oct 2010 11:48:44 +0100
X-Spam-Flag: NO
X-Spam-Score: -1.9
X-Spam-Level: 
X-Spam-Status: No, score=-1.9 tagged_above=-100 required=5
    tests=[BAYES_00=-1.9](8794f16c]) autolearn=ham
Received: from 750-6.tcm.exa.net.uk (smtp-1.mail.exa.net.uk [TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
    (No client certificate requested)
    by scanner-3.tcm.exa.net.uk (ExaSMTPD) with ESMTPS id B64582DCA6
    for <xx@xspa.org.uk>; Mon, 18 Oct 2010 11:48:42 +0100 (BST)
Received: (qmail 10759 invoked from network); 18 Oct 2010 10:48:42 -0000
Received: from ptr-xx.xx.219.82.rev.exa.net.uk (HELO business) ([82.219.xx.xx](82.219.5.1])
    (using))
          (envelope-sender <xx@xspa.org.uk>)
          by smtp.exa-networks.co.uk (qmail-ldap-1.03) with SMTP
          for <xx@xspa.org.uk>; 18 Oct 2010 10:48:41 -0000
From: "xx" <xx@xspa.org.uk>
To: "xx" <xx@xspa.org.uk>
Subject: attachment...
Date: Mon, 18 Oct 2010 11:46:39 +0100
Message-ID: <GMEJLOLMPDCCEDNEOAAMKEIOCDAA.xx@xspa.org.uk>
MIME-Version: 1.0
Content-Type: multipart/mixed;
    boundary="----=_NextPart_000_000B_01CB6EBA.2004D0B0"
X-Priority: 3 (Normal)
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2911.0)
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3664
Importance: Normal

This is a multi-part message in MIME format.

------=_NextPart_000_000B_01CB6EBA.2004D0B0
Content-Type: text/plain;
    charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

...hopefully!!

xx

BUSINESS MANAGER

x
x
x
x
x
x

Tel : 019x

------=_NextPart_000_000B_01CB6EBA.2004D0B0
Content-Type: application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608;
    name="Advert.doc"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
    filename="Advert.doc"

0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAABAAAANwAAAAAAAAAA
EAAAOQAAAAEAAAD+_//AAAAADYAAAD__/__/__/__/__/__/__/__/_///
_/__/__/__/__/__/__/__/__/__/__/__/__/__/__/_/
_/__/__/__/__/__/__/__/__/__/__/__/__/__/__/_/

...

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

------=_NextPart_000_000B_01CB6EBA.2004D0B0--
SanTester commented 5 years ago

Attachment is not displayed in mail.. please rectify

<?php session_start(); include("config.php");

$_POST = $_SESSION; $user = $_SESSION['login_user']; $table = $_SESSION['user_type']; $back=$_SESSION['back'];

$sql = "SELECT email FROM $table WHERE name = '$user'"; $result = mysqli_query($db,$sql)or die( mysqli_error($db)); $row = mysqli_fetch_array($result,MYSQLI_ASSOC);

$cc="wwwwtest@dff.com"; $cc.=",".$row['email']; $to=$row['email'];

if($_SESSION['user_type']=="adminlogin" and !empty($_SESSION['post_data']['memail']) ) { $cc.=",".$_SESSION['post_data']['memail']; }

$subject = "information Info of Employee Name : ".$_SESSION['post_data']['firstname']." [".$_SESSION['post_data']['empid']." ]" ;

$empid = $_SESSION['post_data']['empid']; $firstname = $_SESSION['post_data']['firstname']; $lastname = $_SESSION['post_data']['lastname']; $middlename = $_SESSION['post_data']['middlename']; $gender = $_SESSION['post_data']['gender']; $email = $_SESSION['post_data']['email']; $qualification = $_SESSION['post_data']['qualification']; $dob = $_SESSION['post_data']['dob']; $startdate = $_SESSION['post_data']['startdate']; $prevemp = $_SESSION['post_data']['prevemp']; $band = $_SESSION['post_data']['band']; $rectype = $_SESSION['post_data']['rectype']; $cproj = $_SESSION['post_data']['ciscoproj']; $billing = $_SESSION['post_data']['billing']; $pan = $_SESSION['post_data']['pan']; $phno = $_SESSION['post_data']['phno'];

$city = $_SESSION['post_data']['city']; $state = $_SESSION['post_data']['state']; $country = $_SESSION['post_data']['country'];

$zip = $_SESSION['post_data']['zip'];

$address = $_SESSION['post_data']['address']; $raisedby = $_SESSION['login_user']; $file=$_SESSION['post_data']['file']; echo "The file we got is : ".$file; $filename=basename($file); echo "The file name we got is : ".$filename;

$query="INSERT INTO hit.employee(empid ,firstname ,lastname ,middlename,gender ,mail ,qualification,dob, industryexp, ciscoemployeeflag, band, recruitmenttype, ciscoproject, billableflag,pan, phno, city,state,zip,country, address, raisedby) VALUES('$empid', '$firstname', '$lastname', '$middlename', '$gender', '$email' , '$qualification', '$dob', '$startdate', '$prevemp', '$band', '$rectype', '$cproj', '$billing', '$pan', '$phno', '$city', '$state', '$zip', '$country', '$address', '$raisedby')";

$result = mysqli_query($db,$query)or die( mysqli_error($db));

if($result==1) {

echo "";

$query1="SELECT * FROM employee where empid='$empid'";

$result1 = mysqli_query($db,$query1)or die( mysqli_error($db));

$op = mysqli_fetch_array($result1);

$message = "HTML email

TECHM EMP ID FIRST NAME LAST NAME EMAIL
".strip_tags($op[0])."".strip_tags($op[1])."". strip_tags($op[2])." ".strip_tags($op[5])."

Employee Details Summary:

"."

" ."" ."" ."" . "" ."" . "" . "" . "" . "" . "" . "" . "" . "" . "" . "" . "" . "" . "" . "" . "" . "" ."
Emp Number : ".strip_tags(($_SESSION['post_data']['empid']))."
Gender : ".strip_tags(($_SESSION['post_data']['gender']))."
First Name :".strip_tags(($_SESSION['post_data']['firstname']))."
Middle Name : ".strip_tags(($_SESSION['post_data']['middlename']))."
Last Name : ".strip_tags(($_SESSION['post_data']['lastname']))."
Qualification : ".strip_tags(($_SESSION['post_data']['qualification']))."
Industry Exp(Start Date) (dd/mm/yyyy) : ".strip_tags(($_SESSION['post_data']['startdate']))."
TechM E-mail ID : ".strip_tags(($_SESSION['post_data']['email']))."
Previous Cisco Employee number (If available) : ".strip_tags(($_SESSION['post_data']['prevemp']))."
TechM-Grade : ".strip_tags(($_SESSION['post_data']['band']))."
External/Internal Recruitment : ".strip_tags(($_SESSION['post_data']['rectype']))."
Billable / Non-billable : ".strip_tags(($_SESSION['post_data']['billing']))."
BATS Cisco Project : ".strip_tags(($_SESSION['post_data']['ciscoproj']))."
Address : ".strip_tags(($_SESSION['post_data']['address']))."
Country : ".strip_tags(($_SESSION['post_data']['country']))."
City : ".strip_tags(($_SESSION['post_data']['city']))."
State : ".strip_tags(($_SESSION['post_data']['state']))."
Zip Code : ".strip_tags(($_SESSION['post_data']['zip']))."
Phone Number : ".strip_tags(($_SESSION['post_data']['phno']))."
PAN Number/Social Security : ".strip_tags(($_SESSION['post_data']['pan']))."
Date of Birth (dd/mm/yyyy) : ".strip_tags(($_SESSION['post_data']['dob']))."

"."

This email has been copied to .......

"; //if(isset($_POST['file'])){ $file = $_POST['file']; } $file_tmp_name = $_FILES['$file']['tmp_name']; $file_name = $_FILES['$file']['name']; $file_size = $_FILES['$file']['size']; $file_type = $_FILES['$file']['type']; $file_error = $_FILES['$file']['error']; $user_email = filter_var($_POST["email"], FILTER_SANITIZE_EMAIL); if($file_error > 0) { die('Upload error or No files uploaded'); } //read from the uploaded file & base64_encode content for the mail //$handle = fopen($file_tmp_name , "r"); //$content = fread($handle, $file_size); $content=file_get_contents($file_tmp_name); // fclose($handle); $encoded_content = chunk_split(base64_encode($content)); $boundary = md5("sanwebe"); // Always set content-type when sending HTML email $headers = "MIME-Version: 1.0" . "\r\n"; $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n"; // More headers //$headers .= 'From: ' . "\r\n"; $headers .= 'From: ' . "\r\n"; $headers .= 'Cc: '.$cc.'' . "\r\n"; //attachment $message .= "--$boundary\r\n"; $message .="Content-Type: $file_type; name=".$file_name."\r\n"; $message .="Content-Disposition: attachment; filename=".$file_name."\r\n"; $message .="Content-Transfer-Encoding: base64\r\n"; $message .="X-Attachment-Id: ".rand(1000,99999)."\r\n\r\n"; $message .= $encoded_content; /* //attachment $body .= "--$boundary\r\n"; $body .="Content-Type: $file_type; name=\"$file_name\"\r\n"; $body .="Content-Disposition: attachment; filename=\"$file_name\"\r\n"; $body .="Content-Transfer-Encoding: base64\r\n"; $body .="X-Attachment-Id: ".rand(1000,99999)."\r\n\r\n"; $body .= $encoded_content; */ if(mail($to,$subject,$message,$headers)) echo ""; else ""; } else { echo ""; } ?>
alecpl commented 5 years ago

Please, do not hijack old tickets. Provide complete message source and some info about your Roundcube installation (version, php, os, etc.).