Results 1 to 10 of 10

Thread: Bug found in ImapMailReceiver

  1. #1
    Join Date
    Feb 2013
    Posts
    17

    Default Bug found in ImapMailReceiver

    If the password contains @, the parseString(String url) in URLName will not return host correctly. Any way to walk around this without waiting for the bug fix? Thanks!

    Code:
       // examine the fullhost, for username password etc.
    	    int i = fullhost.indexOf('@');
    	    if (i != -1) {
    		String fulluserpass = fullhost.substring(0, i);
    		fullhost = fullhost.substring(i + 1);
    The complete parseString implementation is as below:
    Code:
       /**
         * Method which does all of the work of parsing the string.
         */
        protected void parseString(String url) {
    	// initialize everything in case called from subclass
    	// (URLName really should be a final class)
    	protocol = file = ref = host = username = password = null;
    	port = -1;
    
    	int len = url.length();
    
    	// find the protocol
    	// XXX - should check for only legal characters before the colon
    	// (legal: a-z, A-Z, 0-9, "+", ".", "-")
    	int protocolEnd = url.indexOf(':');
            if (protocolEnd != -1)
    	    protocol = url.substring(0, protocolEnd);
    
    	// is this an Internet standard URL that contains a host name?
    	if (url.regionMatches(protocolEnd + 1, "//", 0, 2)) {
    	    // find where the file starts
    	    String fullhost = null;
    	    int fileStart = url.indexOf('/', protocolEnd + 3);
    	    if (fileStart != -1) {
    		fullhost = url.substring(protocolEnd + 3, fileStart);
    		if (fileStart + 1 < len)
    		    file = url.substring(fileStart + 1);
    		else
    		    file = "";
    	    } else
    		fullhost = url.substring(protocolEnd + 3);
    
    	    // examine the fullhost, for username password etc.
    	    int i = fullhost.indexOf('@');
    	    if (i != -1) {
    		String fulluserpass = fullhost.substring(0, i);
    		fullhost = fullhost.substring(i + 1);
    
    		// get user and password
    		int passindex = fulluserpass.indexOf(':');
    		if (passindex != -1) {
    		    username = fulluserpass.substring(0, passindex);
    		    password = fulluserpass.substring(passindex + 1);
    		} else {
    		    username = fulluserpass;
    		}
    	    }
    	    
    	    // get the port (if there)
    	    int portindex;
    	    if (fullhost.length() > 0 && fullhost.charAt(0) == '[') {
    		// an IPv6 address?
    		portindex = fullhost.indexOf(':', fullhost.indexOf(']'));
    	    } else {
    		portindex = fullhost.indexOf(':');
    	    }
    	    if (portindex != -1) {
    		String portstring = fullhost.substring(portindex + 1);
    		if (portstring.length() > 0) {
    		    try {
    			port = Integer.parseInt(portstring);
    		    } catch (NumberFormatException nfex) {
    			port = -1;
    		    }
    		}
    		
    		host = fullhost.substring(0, portindex);
    	    } else {
    		host = fullhost;
    	    }
    	} else {
    	    if (protocolEnd + 1 < len)
    		file = url.substring(protocolEnd + 1);
    	}
    Last edited by FDM; Mar 7th, 2013 at 12:51 AM.

  2. #2
    Join Date
    Oct 2005
    Location
    Boston, MA
    Posts
    2,844

    Default

    Thank you for reporting this. Could you please create a JIRA issue for it?, and even better issue a PR as well:
    https://github.com/SpringSource/spri...ONTRIBUTING.md

    Thanks,
    -Mark

  3. #3
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,038

    Default

    Because it's a URL, you can use normal URL escaping (%40 for @)...

    Code:
    store-uri="pop3://foo:123%4045@pop.gmail.com/INBOX"
    
    ...
    
    S: +OK Gpop ready for requests from xx.xx.xx.xx dw6pf46669172qab.16
    ...
    C: USER foo
    S: +OK send PASS
    C: PASS 123@45
    S: -ERR [AUTH] Username and password not accepted.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  4. #4
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,038

    Default

    Just to add also, so this thread will be found by a search, this same technique is used if the mail server needs the user id in the form of foo@bar.com (such as Apache James), for example...

    Code:
    store-uri="imap://foo%40bar.com:pass@localhost:143/INBOX"
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  5. #5
    Join Date
    Feb 2013
    Posts
    17

    Default

    Thanks for the reply! I will go test this. Will that be better if the code also does some validation and be more robust? javax.mail.URLName does a good job. I was wondering why ImapMailReceiver does not do something similar.
    Last edited by FDM; Mar 7th, 2013 at 02:24 PM.

  6. #6
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,038

    Default

    I am a little confused by your question; the code you cited above (in post#1) is in javax.mail.URLName. The mail receiver delegates to javax.mail.URLName to do the parsing.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  7. #7
    Join Date
    Feb 2013
    Posts
    17

    Default

    Sorry for the confusion.

    public ImapMailReceiver(String url) {} only accept url. URLName has a constructor which does the encoding for the caller. With the existing ImapMailReceiver code, it is the caller responsibility to encode username and password and make sure everything is correct. If something gets wrong, the only way to figure out the problem is to turn on java mail debugging.

    Code:
       public URLName(
    	String protocol,
    	String host,
    	int port,
    	String file,
    	String username,
    	String password
    	)
        {
    	this.protocol = protocol;
    	this.host = host;
    	this.port = port;
    	int refStart;
    	if (file != null && (refStart = file.indexOf('#')) != -1) {
    	    this.file = file.substring(0, refStart);
    	    this.ref = file.substring(refStart + 1);
    	} else {
    	    this.file = file;
    	    this.ref = null;
    	}
    	this.username = doEncode ? encode(username) : username;
    	this.password = doEncode ? encode(password) : password;
        }

  8. #8
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,038

    Default

    So, if I now understand you, you are asking for an alternative to using a uri - specifying each part of the uri separately?

    i.e. instead of

    Code:
    <int-mail:imap-idle-channel-adapter id="customAdapter"
    			store-uri="imap://foo%40bar.com:p%40ss@localhost:143/INBOX"
    ...
    You want to see something like...

    Code:
    <int-mail:imap-idle-channel-adapter id="customAdapter"
    			host="localhost"
                            port="143"
                            folder="INBOX"
                            user="foo@bar.com"
                            password="p@ss"
    ...
    ???

    As Mark said, feel free to open a JIRA issue (and even better, submit a pull request).

    However, I think there's an easy way to do what you want today...

    Code:
    <bean id="url" class="javax.mail.URLName">
    	<constructor-arg value="imap"/>
    	<constructor-arg value="localhost"/>
    	<constructor-arg value="143"/>
    	<constructor-arg value="INBOX"/>
    	<constructor-arg value="foo@bar.com"/>
    	<constructor-arg value="123@45"/>
    </bean>
    ...
    <int-mail:imap-idle-channel-adapter id="customAdapter"
    			store-uri="#{url.toString()}"
    			channel="receiveChannel"
    			auto-startup="true"
    			should-delete-messages="false"
    			should-mark-messages-as-read="false"
    			java-mail-properties="javaMailProperties"/>
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  9. #9
    Join Date
    Feb 2013
    Posts
    17

    Default

    Thanks again for your patience!

    will do. will start and try to make some contributions back to Spring Community.

    Regarding our use case, we are not able to go with configuration file as the mail servers may change at run-time.

    I would really appreciate that if you could also take a look at below problem and let me know your gut felling where the problem could be...

    It seems to me the underlying timeout settings seem to be infinite? I tried to change the default behavior by setting below properties and it does not help.

    properties.put("mail.imap.connectiontimeout", "3000");
    properties.put("mail.imap.timeout", "3000");

    JavaMail Debugging log:

    DEBUG IMAPS: trying to connect to host "imap.gmail.com", port 993, isSSL true

    After the above logging, things will get stuck. What I have done so far to analyze this problem:

    On the SAME machine, Spring integration test using ImapMailReceiver works well and I can fetch emails from gmail server. However once I deploy the same to tomcat and using the same configured ImapMailReceiver, it will get stuck at "trying to connect to host "imap.gmail.com", port 993, isSSL true". Do you have any idea where the problem could be?

    Again many thanks!!!

  10. #10
    Join Date
    Feb 2013
    Posts
    17

    Default

    It turned out that the issue I reported in #9 is related to SSL/Certificate. After adding the below property, everything just works inside tomcat.

    props.setProperty(“mail.imapS.ssl.trust”, “*”);

    One thing I do not understand is 1) The same ImapMailReceiver works in spring integration test but does not work when deployed in tomcat. In tomcat, I have to set trust all hosts.

    Any comments?

    Thanks!
    Last edited by FDM; Mar 8th, 2013 at 12:29 AM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •