Announcement Announcement Module
Collapse
No announcement yet.
Bug found in ImapMailReceiver Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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, 01:51 AM.

  • #2
    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

    Comment


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

      Code:
      store-uri="pop3://foo:123%[email protected]/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.

      Comment


      • #4
        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 [email protected] (such as Apache James), for example...

        Code:
        store-uri="imap://foo%40bar.com:pass@localhost:143/INBOX"

        Comment


        • #5
          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, 03:24 PM.

          Comment


          • #6
            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.

            Comment


            • #7
              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;
                  }

              Comment


              • #8
                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="[email protected]"
                                        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="[email protected]"/>
                	<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"/>

                Comment


                • #9
                  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!!!

                  Comment


                  • #10
                    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, 01:29 AM.

                    Comment

                    Working...
                    X