|  | @@ -272,16 +272,14 @@ connection_write_str_to_buf(const char *s, control_connection_t *conn)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** Given a <b>len</b>-character string in <b>data</b>, made of lines
 | 
	
		
			
				|  |  | - * terminated by CRLF, allocate a new string in *<b>out</b>, and copy
 | 
	
		
			
				|  |  | - * the contents of <b>data</b> into *<b>out</b>, adding a period
 | 
	
		
			
				|  |  | - * before any period that that appears at the start of a line, and
 | 
	
		
			
				|  |  | - * adding a period-CRLF line at the end. If <b>translate_newlines</b>
 | 
	
		
			
				|  |  | - * is true, replace all LF characters sequences with CRLF.  Return the
 | 
	
		
			
				|  |  | - * number of bytes in *<b>out</b>.
 | 
	
		
			
				|  |  | + * terminated by CRLF, allocate a new string in *<b>out</b>, and copy the
 | 
	
		
			
				|  |  | + * contents of <b>data</b> into *<b>out</b>, adding a period before any period
 | 
	
		
			
				|  |  | + * that that appears at the start of a line, and adding a period-CRLF line at
 | 
	
		
			
				|  |  | + * the end. Replace all LF characters sequences with CRLF.  Return the number
 | 
	
		
			
				|  |  | + * of bytes in *<b>out</b>.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  /* static */ size_t
 | 
	
		
			
				|  |  | -write_escaped_data(const char *data, size_t len, int translate_newlines,
 | 
	
		
			
				|  |  | -                   char **out)
 | 
	
		
			
				|  |  | +write_escaped_data(const char *data, size_t len, char **out)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    size_t sz_out = len+8;
 | 
	
		
			
				|  |  |    char *outp;
 | 
	
	
		
			
				|  | @@ -297,7 +295,7 @@ write_escaped_data(const char *data, size_t len, int translate_newlines,
 | 
	
		
			
				|  |  |    start_of_line = 1;
 | 
	
		
			
				|  |  |    while (data < end) {
 | 
	
		
			
				|  |  |      if (*data == '\n') {
 | 
	
		
			
				|  |  | -      if (translate_newlines && data > start && data[-1] != '\r')
 | 
	
		
			
				|  |  | +      if (data > start && data[-1] != '\r')
 | 
	
		
			
				|  |  |          *outp++ = '\r';
 | 
	
		
			
				|  |  |        start_of_line = 1;
 | 
	
		
			
				|  |  |      } else if (*data == '.') {
 | 
	
	
		
			
				|  | @@ -325,12 +323,11 @@ write_escaped_data(const char *data, size_t len, int translate_newlines,
 | 
	
		
			
				|  |  |  /** Given a <b>len</b>-character string in <b>data</b>, made of lines
 | 
	
		
			
				|  |  |   * terminated by CRLF, allocate a new string in *<b>out</b>, and copy
 | 
	
		
			
				|  |  |   * the contents of <b>data</b> into *<b>out</b>, removing any period
 | 
	
		
			
				|  |  | - * that appears at the start of a line.  If <b>translate_newlines</b>
 | 
	
		
			
				|  |  | - * is true, replace all CRLF sequences with LF.  Return the number of
 | 
	
		
			
				|  |  | + * that appears at the start of a line, and replacing all CRLF sequences
 | 
	
		
			
				|  |  | + * with LF.   Return the number of
 | 
	
		
			
				|  |  |   * bytes in *<b>out</b>. */
 | 
	
		
			
				|  |  |  /* static */ size_t
 | 
	
		
			
				|  |  | -read_escaped_data(const char *data, size_t len, int translate_newlines,
 | 
	
		
			
				|  |  | -                  char **out)
 | 
	
		
			
				|  |  | +read_escaped_data(const char *data, size_t len, char **out)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    char *outp;
 | 
	
		
			
				|  |  |    const char *next;
 | 
	
	
		
			
				|  | @@ -341,28 +338,26 @@ read_escaped_data(const char *data, size_t len, int translate_newlines,
 | 
	
		
			
				|  |  |    end = data+len;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    while (data < end) {
 | 
	
		
			
				|  |  | +    /* we're at the start of a line. */
 | 
	
		
			
				|  |  |      if (*data == '.')
 | 
	
		
			
				|  |  |        ++data;
 | 
	
		
			
				|  |  | -    if (translate_newlines)
 | 
	
		
			
				|  |  | -      next = tor_memmem(data, end-data, "\r\n", 2);
 | 
	
		
			
				|  |  | -    else
 | 
	
		
			
				|  |  | -      next = tor_memmem(data, end-data, "\r\n.", 3);
 | 
	
		
			
				|  |  | +    next = memchr(data, '\n', end-data);
 | 
	
		
			
				|  |  |      if (next) {
 | 
	
		
			
				|  |  | -      memcpy(outp, data, next-data);
 | 
	
		
			
				|  |  | -      outp += (next-data);
 | 
	
		
			
				|  |  | -      data = next+2;
 | 
	
		
			
				|  |  | +      size_t n_to_copy = next-data;
 | 
	
		
			
				|  |  | +      /* Don't copy a CR that precedes this LF. */
 | 
	
		
			
				|  |  | +      if (n_to_copy && *(next-1) == '\r')
 | 
	
		
			
				|  |  | +        --n_to_copy;
 | 
	
		
			
				|  |  | +      memcpy(outp, data, n_to_copy);
 | 
	
		
			
				|  |  | +      outp += n_to_copy;
 | 
	
		
			
				|  |  | +      data = next+1; /* This will point at the start of the next line,
 | 
	
		
			
				|  |  | +                      * or the end of the string, or a period. */
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        memcpy(outp, data, end-data);
 | 
	
		
			
				|  |  |        outp += (end-data);
 | 
	
		
			
				|  |  |        *outp = '\0';
 | 
	
		
			
				|  |  |        return outp - *out;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    if (translate_newlines) {
 | 
	
		
			
				|  |  | -      *outp++ = '\n';
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      *outp++ = '\r';
 | 
	
		
			
				|  |  | -      *outp++ = '\n';
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +    *outp++ = '\n';
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    *outp = '\0';
 | 
	
	
		
			
				|  | @@ -1818,7 +1813,7 @@ handle_control_getinfo(control_connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        char *esc = NULL;
 | 
	
		
			
				|  |  |        size_t esc_len;
 | 
	
		
			
				|  |  | -      esc_len = write_escaped_data(v, strlen(v), 1, &esc);
 | 
	
		
			
				|  |  | +      esc_len = write_escaped_data(v, strlen(v), &esc);
 | 
	
		
			
				|  |  |        connection_printf_to_buf(conn, "250+%s=\r\n", k);
 | 
	
		
			
				|  |  |        connection_write_to_buf(esc, esc_len, TO_CONN(conn));
 | 
	
		
			
				|  |  |        tor_free(esc);
 | 
	
	
		
			
				|  | @@ -2002,6 +1997,8 @@ static int
 | 
	
		
			
				|  |  |  handle_control_setpurpose(control_connection_t *conn, int for_circuits,
 | 
	
		
			
				|  |  |                            uint32_t len, const char *body)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +  /* XXXX020 this should maybe be two functions; almost no code is acutally
 | 
	
		
			
				|  |  | +     shared. */
 | 
	
		
			
				|  |  |    origin_circuit_t *circ = NULL;
 | 
	
		
			
				|  |  |    routerinfo_t *ri = NULL;
 | 
	
		
			
				|  |  |    uint8_t new_purpose;
 | 
	
	
		
			
				|  | @@ -2170,7 +2167,7 @@ handle_control_postdescriptor(control_connection_t *conn, uint32_t len,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH(args, char *, arg, tor_free(arg));
 | 
	
		
			
				|  |  |    smartlist_free(args);
 | 
	
		
			
				|  |  | -  read_escaped_data(cp, len-(cp-body), 1, &desc);
 | 
	
		
			
				|  |  | +  read_escaped_data(cp, len-(cp-body), &desc);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    switch (router_load_single_router(desc, purpose, &msg)) {
 | 
	
		
			
				|  |  |    case -1:
 | 
	
	
		
			
				|  | @@ -2530,8 +2527,8 @@ connection_control_process_inbuf(control_connection_t *conn)
 | 
	
		
			
				|  |  |      char buf[128];
 | 
	
		
			
				|  |  |      set_uint16(buf+2, htons(0x0000)); /* type == error */
 | 
	
		
			
				|  |  |      set_uint16(buf+4, htons(0x0001)); /* code == internal error */
 | 
	
		
			
				|  |  | -    strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.2.0.x "
 | 
	
		
			
				|  |  | -            "and later; use Tor 0.1.2.x or upgrade your controller",
 | 
	
		
			
				|  |  | +    strlcpy(buf+6, "The v0 control protocol is not supported by Tor 0.1.2.17 "
 | 
	
		
			
				|  |  | +            "and later; upgrade your controller.",
 | 
	
		
			
				|  |  |              sizeof(buf)-6);
 | 
	
		
			
				|  |  |      body_len = 2+strlen(buf+6)+2; /* code, msg, nul. */
 | 
	
		
			
				|  |  |      set_uint16(buf+0, htons(body_len));
 | 
	
	
		
			
				|  | @@ -2571,11 +2568,17 @@ connection_control_process_inbuf(control_connection_t *conn)
 | 
	
		
			
				|  |  |      if (last_idx == 0 && *conn->incoming_cmd != '+')
 | 
	
		
			
				|  |  |        /* One line command, didn't start with '+'. */
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  | +    /* XXXX this code duplication is kind of dumb. */
 | 
	
		
			
				|  |  |      if (last_idx+3 == conn->incoming_cmd_cur_len &&
 | 
	
		
			
				|  |  |          !memcmp(conn->incoming_cmd + last_idx, ".\r\n", 3)) {
 | 
	
		
			
				|  |  |        /* Just appended ".\r\n"; we're done. Remove it. */
 | 
	
		
			
				|  |  |        conn->incoming_cmd_cur_len -= 3;
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  | +    } else if (last_idx+2 == conn->incoming_cmd_cur_len &&
 | 
	
		
			
				|  |  | +               !memcmp(conn->incoming_cmd + last_idx, ".\n", 2)) {
 | 
	
		
			
				|  |  | +      /* Just appended ".\n"; we're done. Remove it. */
 | 
	
		
			
				|  |  | +      conn->incoming_cmd_cur_len -= 2;
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      /* Otherwise, read another line. */
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -3309,7 +3312,7 @@ control_event_or_authdir_new_descriptor(const char *action,
 | 
	
		
			
				|  |  |                 msg ? msg : "");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Escape the server descriptor properly */
 | 
	
		
			
				|  |  | -  esclen = write_escaped_data(desc, desclen, 1, &esc);
 | 
	
		
			
				|  |  | +  esclen = write_escaped_data(desc, desclen, &esc);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    totallen = strlen(firstline) + esclen + 1;
 | 
	
		
			
				|  |  |    buf = tor_malloc(totallen);
 | 
	
	
		
			
				|  | @@ -3345,7 +3348,7 @@ control_event_networkstatus_changed(smartlist_t *statuses)
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    s = smartlist_join_strings(strs, "", 0, NULL);
 | 
	
		
			
				|  |  | -  write_escaped_data(s, strlen(s), 1, &esc);
 | 
	
		
			
				|  |  | +  write_escaped_data(s, strlen(s), &esc);
 | 
	
		
			
				|  |  |    SMARTLIST_FOREACH(strs, char *, cp, tor_free(cp));
 | 
	
		
			
				|  |  |    smartlist_free(strs);
 | 
	
		
			
				|  |  |    tor_free(s);
 |