* Copyright (c) 2004 Novell, Inc. All Rights Reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA #define NO_ESCAPE(ch) ((ch == 0x20) || (ch >= 0x30 && ch <= 0x39) || \ (ch >= 0x41 && ch <= 0x5a) || (ch >= 0x61 && ch <= 0x7a)) /* Read data from conn until the end of a line */ read_line(NMConn * conn, char *buff, int len) while ((rc == NM_OK) && (total_bytes < (len - 1))) { rc = nm_read_all(conn, &buff[total_bytes], 1); if (buff[total_bytes - 1] == '\n') { buff[total_bytes] = '\0'; url_escape_string(char *src) static const char hex_table[16] = "0123456789abcdef"; /* Find number of chars to escape */ for (p = src; *p != '\0'; p++) { encoded = g_malloc((p - src) + (escape * 2) + 1); for (p = src, q = encoded; *p != '\0'; p++) { encode_method(guint8 method) case NMFIELD_METHOD_EQUAL: case NMFIELD_METHOD_UPDATE: case NMFIELD_METHOD_EXIST: case NMFIELD_METHOD_NOTEXIST: case NMFIELD_METHOD_SEARCH: case NMFIELD_METHOD_MATCHBEGIN: case NMFIELD_METHOD_MATCHEND: case NMFIELD_METHOD_NOT_ARRAY: case NMFIELD_METHOD_OR_ARRAY: case NMFIELD_METHOD_AND_ARRAY: case NMFIELD_METHOD_DELETE_ALL: case NMFIELD_METHOD_DELETE: default: /* NMFIELD_METHOD_VALID */ nm_create_conn(const char *addr, int port) NMConn *conn = g_new0(NMConn, 1); conn->addr = g_strdup(addr); void nm_release_conn(NMConn *conn) for (node = conn->requests; node; node = node->next) { nm_release_request(node->data); g_slist_free(conn->requests); nm_tcp_write(NMConn * conn, const void *buff, int len) if (conn == NULL || buff == NULL) return (write(conn->fd, buff, len)); else if (conn->ssl_conn && conn->ssl_conn->write) return (conn->ssl_conn->write(conn->ssl_conn->data, buff, len)); nm_tcp_read(NMConn * conn, void *buff, int len) if (conn == NULL || buff == NULL) return (read(conn->fd, buff, len)); else if (conn->ssl_conn && conn->ssl_conn->read) return ((conn->ssl_conn->read)(conn->ssl_conn->data, buff, len)); nm_read_all(NMConn * conn, char *buff, int len) if (conn == NULL || buff == NULL) /* Keep reading until buffer is full */ bytes_read = nm_tcp_read(conn, &buff[total_bytes], bytes_left); bytes_left -= bytes_read; total_bytes += bytes_read; nm_read_uint32(NMConn *conn, guint32 *val) rc = nm_read_all(conn, (char *)val, sizeof(*val)); *val = GUINT32_FROM_LE(*val); nm_read_uint16(NMConn *conn, guint16 *val) rc = nm_read_all(conn, (char *)val, sizeof(*val)); *val = GUINT16_FROM_LE(*val); nm_write_fields(NMConn * conn, NMField * fields) if (conn == NULL || fields == NULL) { /* Format each field as valid "post" data and write it out */ for (field = fields; (rc == NM_OK) && (field->tag); field++) { /* We don't currently handle binary types */ if (field->method == NMFIELD_METHOD_IGNORE || field->type == NMFIELD_TYPE_BINARY) { /* Write the field tag */ bytes_to_send = g_snprintf(buffer, sizeof(buffer), "&tag=%s", field->tag); ret = nm_tcp_write(conn, buffer, bytes_to_send); /* Write the field method */ method = encode_method(field->method); bytes_to_send = g_snprintf(buffer, sizeof(buffer), "&cmd=%s", method); ret = nm_tcp_write(conn, buffer, bytes_to_send); /* Write the field value */ value = url_escape_string((char *) field->ptr_value); bytes_to_send = g_snprintf(buffer, sizeof(buffer), if (bytes_to_send > (int)sizeof(buffer)) { ret = nm_tcp_write(conn, buffer, sizeof(buffer)); ret = nm_tcp_write(conn, buffer, bytes_to_send); val = nm_count_fields((NMField *) field->ptr_value); bytes_to_send = g_snprintf(buffer, sizeof(buffer), ret = nm_tcp_write(conn, buffer, bytes_to_send); bytes_to_send = g_snprintf(buffer, sizeof(buffer), "&val=%u", field->value); ret = nm_tcp_write(conn, buffer, bytes_to_send); /* Write the field type */ bytes_to_send = g_snprintf(buffer, sizeof(buffer), "&type=%u", field->type); ret = nm_tcp_write(conn, buffer, bytes_to_send); /* If the field is a sub array then post its fields */ if (rc == NM_OK && val > 0) { if (field->type == NMFIELD_TYPE_ARRAY || field->type == NMFIELD_TYPE_MV) { rc = nm_write_fields(conn, (NMField *) field->ptr_value); nm_send_request(NMConn *conn, char *cmd, NMField *fields, nm_response_cb cb, gpointer data, NMRequest **request) NMField *request_fields = NULL; if (conn == NULL || cmd == NULL) bytes_to_send = g_snprintf(buffer, sizeof(buffer), "POST /%s HTTP/1.0\r\n", cmd); ret = nm_tcp_write(conn, buffer, bytes_to_send); if (strcmp("login", cmd) == 0) { bytes_to_send = g_snprintf(buffer, sizeof(buffer), "Host: %s:%d\r\n\r\n", conn->addr, conn->port); ret = nm_tcp_write(conn, buffer, bytes_to_send); bytes_to_send = g_snprintf(buffer, sizeof(buffer), "\r\n"); ret = nm_tcp_write(conn, buffer, bytes_to_send); /* Add the transaction id to the request fields */ request_fields = nm_copy_field_array(fields); str = g_strdup_printf("%d", ++(conn->trans_id)); request_fields = nm_field_add_pointer(request_fields, NM_A_SZ_TRANSACTION_ID, 0, /* Send the request to the server */ rc = nm_write_fields(conn, request_fields); /* Write the CRLF to terminate the data */ ret = nm_tcp_write(conn, "\r\n", strlen("\r\n")); /* Create a request struct, add it to our queue, and return it */ NMRequest *new_request = nm_create_request(cmd, conn->trans_id, time(0), cb, NULL, data); nm_conn_add_request_item(conn, new_request); /* Set the out param if it was sent in, otherwise release the request */ nm_release_request(new_request); if (request_fields != NULL) nm_free_fields(&request_fields); nm_read_header(NMConn * conn) rc = read_line(conn, buffer, sizeof(buffer)); /* Find the return code */ ptr = strchr(buffer, ' '); while (isdigit(*ptr) && (i < 3)) { rtn_code = atoi(rtn_buf); /* Finish reading header, in the future we might want to do more processing here */ /* TODO: handle more general redirects in the future */ while ((rc == NM_OK) && (strcmp(buffer, "\r\n") != 0)) { rc = read_line(conn, buffer, sizeof(buffer)); if (rc == NM_OK && rtn_code == 301) rc = NMERR_SERVER_REDIRECT; nm_read_fields(NMConn * conn, int count, NMField ** fields) NMField *sub_fields = NULL; if (conn == NULL || fields == NULL) /* Read the field type, method, and tag */ rc = nm_read_all(conn, (char *)&type, sizeof(type)); if (rc != NM_OK || type == 0) rc = nm_read_all(conn, (char *)&method, sizeof(method)); rc = nm_read_uint32(conn, &val); rc = nm_read_all(conn, tag, val); if (type == NMFIELD_TYPE_MV || type == NMFIELD_TYPE_ARRAY) { /* Read the subarray (first read the number of items in the array) */ rc = nm_read_uint32(conn, &val); rc = nm_read_fields(conn, val, &sub_fields); *fields = nm_field_add_pointer(*fields, tag, 0, method, } else if (type == NMFIELD_TYPE_UTF8 || type == NMFIELD_TYPE_DN) { /* Read the string (first read the length) */ rc = nm_read_uint32(conn, &val); if (val >= NMFIELD_MAX_STR_LENGTH) { str = g_new0(char, val + 1); rc = nm_read_all(conn, str, val); *fields = nm_field_add_pointer(*fields, tag, 0, method, /* Read the numerical value */ rc = nm_read_uint32(conn, &val); *fields = nm_field_add_number(*fields, tag, 0, method, } while ((type != 0) && (count != 0)); if (sub_fields != NULL) { nm_free_fields(&sub_fields); nm_conn_add_request_item(NMConn * conn, NMRequest * request) if (conn == NULL || request == NULL) nm_request_add_ref(request); conn->requests = g_slist_append(conn->requests, request); nm_conn_remove_request_item(NMConn * conn, NMRequest * request) if (conn == NULL || request == NULL) conn->requests = g_slist_remove(conn->requests, request); nm_release_request(request); nm_conn_find_request(NMConn * conn, int trans_id) req = (NMRequest *) itr->data; if (req != NULL && nm_request_get_trans_id(req) == trans_id) { nm_conn_get_addr(NMConn * conn) nm_conn_get_port(NMConn * conn)