Thread: recv multiple lines

  1. #1
    Registered User
    Join Date
    Jul 2004
    Posts
    9

    recv multiple lines

    Hello. I'm trying to make a smtp mail client that will send easy emails.

    I connect to the server, receive the header, and send the 'helo' but there are multiple lines of text sent back at me after that. My loop to receive looks like this:

    send(theSocket, "helo\n", 6, 0);
    char buffer[1024];
    int retcode = recv(theSocket, buffer, 1024, 0);
    while (retcode > 0)
    {
    printf("Buffer size = %d\n Buffer Message = %s\n", retcode, buffer);
    retcode = recv(theSocket, buffer, 1024, 0);
    }

    Although there are 4 lines returned by the server the only thing I get is this:

    Buffer size = 32
    Buffer Message = 250 smtp811.mail.ukl.yahoo.com
    ę§R

    Is there anyway to get all of the lines?
    Last edited by TCM; 07-11-2004 at 10:04 AM.

  2. #2
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Maybe use a readcrlf function, like in here (see the last post):
    http://cboard.cprogramming.com/showthread.php?t=46333
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  3. #3
    Registered User
    Join Date
    Jul 2004
    Posts
    9
    I tried it, it hangs after the first line is printed out to the screen.

  4. #4
    Registered User
    Join Date
    Jul 2004
    Posts
    9
    I figured it out, but now when I try to send the next line of code I get a insufficent error message.

    Code:
    send(theSocket, "MAIL FROM: [email protected]\n", 20, 0);
    501 NULL characters are not allowed in SMTP commands
    typing in 'MAIL FROM: [email protected]' and pressing enter works perfectly though.

  5. #5
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    You are sending the null character that terminates the string.
    Try sending 19 instead of 20 characters in your particular example.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  6. #6
    Registered User
    Join Date
    Jul 2004
    Posts
    9
    I tried changing it but I got the same error message. So I tried sending another helo exactly how I did it orginally, and I'm still getting the error message. Is it possible that the send buffer is filled with junk? If it was how could I clear it out?

  7. #7
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    To help determine what's going on, get yourself a sniffer app, so that you can see what your app is actually sending to the server.

    >>send buffer is filled with junk
    Just make sure you're sending data that you know is good. No need to clear a buffer, imho.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  8. #8
    Registered User
    Join Date
    Jul 2004
    Posts
    9
    This is the first packet Sent that works fine

    ..Z..}....VM..E....0.....&...d.x...0..]......TP..O....ehlo.
    here is the second one

    ..Z..}..Z..}....VM..E....1.....%...d.x...0..].......P.~.....ehlo.
    which produces the null error.
    *shrug*

  9. #9
    Registered User
    Join Date
    Apr 2002
    Posts
    110
    Just for comparison, this is the greeting function that I am currently using in my SMTP library (C++).

    Code:
    void SmtpSocket::sendGreeting()
    {
    
      const std::string greeting_command = "EHLO";
      size_t greeting_msg_len;
      const std::string crlf = "\r\n";
      int numbytes;
      char buf[MAXRECVSIZE];
      std::string received;
      std::ostringstream greeting_msg;
      fd_set listener;
      struct timeval timeout;
      
      /* set the timeout for recieving all the data */
      timeout.tv_sec = 2; /* seconds */
      timeout.tv_usec = 0; /* microsecods */ 
    
      // The greeting message is simply just a 'EHLO domain.name'  
      greeting_msg << greeting_command << " webmastermattd.net" << crlf;
      greeting_msg_len = greeting_msg.str().length();
      
      // Now it is time to send the greeting on its way 
      if((numbytes = send(sockfd, greeting_msg.str().c_str(), greeting_msg_len, 0)) == -1)
        throw SmtpSocketException("Unable to send greeting to server");
        
      // Now clear the buffer and prepare it to recieve the data
      memset((char *)&buf, '\0', MAXRECVSIZE);
      if ((numbytes = recv(sockfd, buf, MAXRECVSIZE-1, 0)) == -1) {
        throw SmtpException("unable to recieve");
      }
    
      received.insert(received.length(), (char *)&buf[0]);
      
      if (numbytes >= MAXRECVSIZE-1) {
        /* Prepare the select stuff */
        FD_ZERO(&listener);
        FD_SET(sockfd, &listener);
    
        while(1) {
          if (select(sockfd + 1, &listener, NULL, NULL, &timeout) == -1) {
            break;
    	  }
    
          if(!FD_ISSET(sockfd, &listener))
            break;
    
          memset(&buf, '\0', MAXRECVSIZE);
          if ((numbytes = recv(sockfd, buf, MAXRECVSIZE-1, 0)) == -1) {
            throw SmtpException("unable to recieve!!!");
            break;
          }
    
          received.insert(received.length(), (char *)&buf[0]);
    
        }
    
      }
    
      // Now for a simple bit of validation
      if( received.find("250") == std::string::npos )
        throw SmtpInvalidServerException("Server did not respond to the greeting correctly");
      
    } // Thus ends the SmtpSocket sendGreeting function, it takes no parameters
    The only differences is that I am using C++ and that I send a CRLF instead of a simple LF as a termination for the string. I would try to create the string outside of the send function and then send them using seperate functions. It seems that you are trashing the strings to some extent.

    As far as receiving multiple lines from the SMTP server, then it is just a matter of a single call to recv() with a sufficient buffer size or multiple calls to recv() and then working with the strings to an extent. It isn't the CRLF or LF that determines the end of the string, rather the \0 that determines it.

    Hope this helps, and feel free to bug me about any futher questions.

    Later,
    WebmasterMattD
    WebmasterMattD.NET

  10. #10
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >>here is the second one
    So why are you sending ehlo twice? Isn't ehlo supposed to have a domain name as a parameter with it too?

    >> It isn't the CRLF or LF that determines the end of the string, rather the \0 that determines it.
    In the context of a C style string, yes, but not in the context of an SMTP reply message. For the later, crlf is the terminator, afaik.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  11. #11
    Registered User
    Join Date
    Apr 2002
    Posts
    110
    Correct on both accounts there Hammer, though I believe that with recv() it will fetch as much from the buffer as you tell it too and if there is one or more CRLF in there, then when a printf() or std::cout is used to display it, then they will go to a new line. From memmory you should also make sure to recieve one less than you string can hold so that placing a \0 at the end of it is possible. The trick that I usually do is to use bzero() to set the string to all '\0' and then overwrite what is needed.

    If you get stuck on the specifics of SMTP then RFC2821 will help you out.
    (also, it depends on the server as to how pedantic they are with the domain name being sent with HELO or EHLO)

    Later,
    WebmasterMattD
    WebmasterMattD.NET

  12. #12
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    >>make sure to recieve one less than you string can hold so that placing a \0 at the end
    The "string" could be broken across two recv() calls, therefore you'd possibly (probably) want to combine it before processing it. For example, if you were receiving a line that looked like this:
    Code:
     username:hammer
    ... and it arrived across two recv()s like so:
    Code:
     recv() 1: username:ham
     recv() 2: mer
    then you'd want to combine the string before validating the password. Putting an extra \0 in the middle only serves to corrupt the data.

    Maybe this functionality isn't relevant to this project, but it certainly will be if you develop more socket programs.

    (Matt: I'm guessing you know this already, I'm posting for anyone else reading..)
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Your biggest project: how many lines have you written?
    By happyclown in forum A Brief History of Cprogramming.com
    Replies: 44
    Last Post: 04-29-2009, 07:30 AM
  2. Problem with deleting completely blank lines
    By dnguyen1022 in forum C Programming
    Replies: 3
    Last Post: 12-07-2008, 11:51 AM
  3. why Multiple define error ...
    By nilathinesh in forum C Programming
    Replies: 2
    Last Post: 10-19-2006, 06:31 AM
  4. Replies: 1
    Last Post: 05-01-2003, 02:52 PM
  5. Multiple lines on an Edit box
    By RubenJ in forum Windows Programming
    Replies: 3
    Last Post: 09-20-2001, 02:51 PM