4 * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
35 #define NO_ESCAPE(ch) ((ch == 0x20) || (ch >= 0x30 && ch <= 0x39) || \
36 (ch >= 0x41 && ch <= 0x5a) || (ch >= 0x61 && ch <= 0x7a))
38 /* Read data from conn until the end of a line */
40 read_line(NMConn
* conn
, char *buff
, int len
)
45 while ((rc
== NM_OK
) && (total_bytes
< (len
- 1))) {
46 rc
= nm_read_all(conn
, &buff
[total_bytes
], 1);
49 if (buff
[total_bytes
- 1] == '\n') {
54 buff
[total_bytes
] = '\0';
60 url_escape_string(char *src
)
68 static const char hex_table
[16] = "0123456789abcdef";
74 /* Find number of chars to escape */
75 for (p
= src
; *p
!= '\0'; p
++) {
82 encoded
= g_malloc((p
- src
) + (escape
* 2) + 1);
84 /* Escape the string */
85 for (p
= src
, q
= encoded
; *p
!= '\0'; p
++) {
99 *q
= hex_table
[ch
>> 4];
102 *q
= hex_table
[ch
& 15];
112 encode_method(guint8 method
)
117 case NMFIELD_METHOD_EQUAL
:
120 case NMFIELD_METHOD_UPDATE
:
123 case NMFIELD_METHOD_GTE
:
126 case NMFIELD_METHOD_LTE
:
129 case NMFIELD_METHOD_NE
:
132 case NMFIELD_METHOD_EXIST
:
135 case NMFIELD_METHOD_NOTEXIST
:
138 case NMFIELD_METHOD_SEARCH
:
141 case NMFIELD_METHOD_MATCHBEGIN
:
144 case NMFIELD_METHOD_MATCHEND
:
147 case NMFIELD_METHOD_NOT_ARRAY
:
150 case NMFIELD_METHOD_OR_ARRAY
:
153 case NMFIELD_METHOD_AND_ARRAY
:
156 case NMFIELD_METHOD_DELETE_ALL
:
159 case NMFIELD_METHOD_DELETE
:
162 case NMFIELD_METHOD_ADD
:
165 default: /* NMFIELD_METHOD_VALID */
174 nm_create_conn(const char *addr
, int port
)
176 NMConn
*conn
= g_new0(NMConn
, 1);
177 conn
->addr
= g_strdup(addr
);
182 void nm_release_conn(NMConn
*conn
)
185 g_slist_free_full(conn
->requests
, (GDestroyNotify
)nm_release_request
);
186 conn
->requests
= NULL
;
187 g_free(conn
->ssl_conn
);
188 conn
->ssl_conn
= NULL
;
196 nm_tcp_write(NMConn
* conn
, const void *buff
, int len
)
198 if (conn
== NULL
|| buff
== NULL
)
202 return (write(conn
->fd
, buff
, len
));
203 else if (conn
->ssl_conn
&& conn
->ssl_conn
->write
)
204 return (conn
->ssl_conn
->write(conn
->ssl_conn
->data
, buff
, len
));
210 nm_tcp_read(NMConn
* conn
, void *buff
, int len
)
212 if (conn
== NULL
|| buff
== NULL
)
216 return (read(conn
->fd
, buff
, len
));
217 else if (conn
->ssl_conn
&& conn
->ssl_conn
->read
)
218 return ((conn
->ssl_conn
->read
)(conn
->ssl_conn
->data
, buff
, len
));
224 nm_read_all(NMConn
* conn
, char *buff
, int len
)
227 int bytes_left
= len
;
232 if (conn
== NULL
|| buff
== NULL
)
233 return NMERR_BAD_PARM
;
235 /* Keep reading until buffer is full */
237 bytes_read
= nm_tcp_read(conn
, &buff
[total_bytes
], bytes_left
);
238 if (bytes_read
> 0) {
239 bytes_left
-= bytes_read
;
240 total_bytes
+= bytes_read
;
242 if (errno
== EAGAIN
) {
262 nm_read_uint32(NMConn
*conn
, guint32
*val
)
266 rc
= nm_read_all(conn
, (char *)val
, sizeof(*val
));
268 *val
= GUINT32_FROM_LE(*val
);
275 nm_read_uint16(NMConn
*conn
, guint16
*val
)
279 rc
= nm_read_all(conn
, (char *)val
, sizeof(*val
));
281 *val
= GUINT16_FROM_LE(*val
);
288 nm_write_fields(NMConn
* conn
, NMField
* fields
)
299 if (conn
== NULL
|| fields
== NULL
) {
300 return NMERR_BAD_PARM
;
303 /* Format each field as valid "post" data and write it out */
304 for (field
= fields
; (rc
== NM_OK
) && (field
->tag
); field
++) {
306 /* We don't currently handle binary types */
307 if (field
->method
== NMFIELD_METHOD_IGNORE
||
308 field
->type
== NMFIELD_TYPE_BINARY
) {
312 /* Write the field tag */
313 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
), "&tag=%s", field
->tag
);
314 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
316 rc
= NMERR_TCP_WRITE
;
319 /* Write the field method */
321 method
= encode_method(field
->method
);
322 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
), "&cmd=%s", method
);
323 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
325 rc
= NMERR_TCP_WRITE
;
329 /* Write the field value */
331 switch (field
->type
) {
332 case NMFIELD_TYPE_UTF8
:
333 case NMFIELD_TYPE_DN
:
335 value
= url_escape_string((char *) field
->ptr_value
);
336 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
338 if (bytes_to_send
> (int)sizeof(buffer
)) {
339 ret
= nm_tcp_write(conn
, buffer
, sizeof(buffer
));
341 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
345 rc
= NMERR_TCP_WRITE
;
352 case NMFIELD_TYPE_ARRAY
:
353 case NMFIELD_TYPE_MV
:
355 val
= nm_count_fields((NMField
*) field
->ptr_value
);
356 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
358 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
360 rc
= NMERR_TCP_WRITE
;
367 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
368 "&val=%u", field
->value
);
369 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
371 rc
= NMERR_TCP_WRITE
;
378 /* Write the field type */
380 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
381 "&type=%u", field
->type
);
382 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
384 rc
= NMERR_TCP_WRITE
;
388 /* If the field is a sub array then post its fields */
389 if (rc
== NM_OK
&& val
> 0) {
390 if (field
->type
== NMFIELD_TYPE_ARRAY
||
391 field
->type
== NMFIELD_TYPE_MV
) {
393 rc
= nm_write_fields(conn
, (NMField
*) field
->ptr_value
);
403 nm_send_request(NMConn
*conn
, char *cmd
, NMField
*fields
,
404 nm_response_cb cb
, gpointer data
, NMRequest
**request
)
410 NMField
*request_fields
= NULL
;
413 if (conn
== NULL
|| cmd
== NULL
)
414 return NMERR_BAD_PARM
;
417 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
418 "POST /%s HTTP/1.0\r\n", cmd
);
419 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
421 rc
= NMERR_TCP_WRITE
;
426 if (purple_strequal("login", cmd
)) {
427 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
428 "Host: %s:%d\r\n\r\n", conn
->addr
, conn
->port
);
429 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
431 rc
= NMERR_TCP_WRITE
;
434 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
), "\r\n");
435 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
437 rc
= NMERR_TCP_WRITE
;
442 /* Add the transaction id to the request fields */
445 request_fields
= nm_copy_field_array(fields
);
447 str
= g_strdup_printf("%d", ++(conn
->trans_id
));
448 request_fields
= nm_field_add_pointer(request_fields
, NM_A_SZ_TRANSACTION_ID
, 0,
449 NMFIELD_METHOD_VALID
, 0,
450 str
, NMFIELD_TYPE_UTF8
);
453 /* Send the request to the server */
455 rc
= nm_write_fields(conn
, request_fields
);
458 /* Write the CRLF to terminate the data */
460 ret
= nm_tcp_write(conn
, "\r\n", strlen("\r\n"));
462 rc
= NMERR_TCP_WRITE
;
466 /* Create a request struct, add it to our queue, and return it */
468 NMRequest
*new_request
= nm_create_request(cmd
, conn
->trans_id
,
469 time(0), cb
, NULL
, data
);
470 nm_conn_add_request_item(conn
, new_request
);
472 /* Set the out param if it was sent in, otherwise release the request */
474 *request
= new_request
;
476 nm_release_request(new_request
);
479 if (request_fields
!= NULL
)
480 nm_free_fields(&request_fields
);
486 nm_read_header(NMConn
* conn
)
496 return NMERR_BAD_PARM
;
499 rc
= read_line(conn
, buffer
, sizeof(buffer
));
502 /* Find the return code */
503 ptr
= strchr(buffer
, ' ');
508 while (isdigit(*ptr
) && (i
< 3)) {
516 rtn_code
= atoi(rtn_buf
);
520 /* Finish reading header, in the future we might want to do more processing here */
521 /* TODO: handle more general redirects in the future */
522 while ((rc
== NM_OK
) && (!purple_strequal(buffer
, "\r\n"))) {
523 rc
= read_line(conn
, buffer
, sizeof(buffer
));
526 if (rc
== NM_OK
&& rtn_code
== 301)
527 rc
= NMERR_SERVER_REDIRECT
;
533 nm_read_fields(NMConn
* conn
, int count
, NMField
** fields
)
540 NMField
*sub_fields
= NULL
;
543 if (conn
== NULL
|| fields
== NULL
)
544 return NMERR_BAD_PARM
;
551 /* Read the field type, method, and tag */
552 rc
= nm_read_all(conn
, (char *)&type
, sizeof(type
));
553 if (rc
!= NM_OK
|| type
== 0)
556 rc
= nm_read_all(conn
, (char *)&method
, sizeof(method
));
560 rc
= nm_read_uint32(conn
, &val
);
564 if (val
> sizeof(tag
)) {
569 rc
= nm_read_all(conn
, tag
, val
);
573 if (type
== NMFIELD_TYPE_MV
|| type
== NMFIELD_TYPE_ARRAY
) {
575 /* Read the subarray (first read the number of items in the array) */
576 rc
= nm_read_uint32(conn
, &val
);
581 rc
= nm_read_fields(conn
, val
, &sub_fields
);
586 *fields
= nm_field_add_pointer(*fields
, tag
, 0, method
,
587 0, sub_fields
, type
);
591 } else if (type
== NMFIELD_TYPE_UTF8
|| type
== NMFIELD_TYPE_DN
) {
593 /* Read the string (first read the length) */
594 rc
= nm_read_uint32(conn
, &val
);
598 if (val
>= NMFIELD_MAX_STR_LENGTH
) {
604 str
= g_new0(char, val
+ 1);
606 rc
= nm_read_all(conn
, str
, val
);
610 *fields
= nm_field_add_pointer(*fields
, tag
, 0, method
,
617 /* Read the numerical value */
618 rc
= nm_read_uint32(conn
, &val
);
622 *fields
= nm_field_add_number(*fields
, tag
, 0, method
,
626 } while (count
!= 0);
630 if (sub_fields
!= NULL
) {
631 nm_free_fields(&sub_fields
);
638 nm_conn_add_request_item(NMConn
* conn
, NMRequest
* request
)
640 if (conn
== NULL
|| request
== NULL
)
643 nm_request_add_ref(request
);
644 conn
->requests
= g_slist_append(conn
->requests
, request
);
648 nm_conn_remove_request_item(NMConn
* conn
, NMRequest
* request
)
650 if (conn
== NULL
|| request
== NULL
)
653 conn
->requests
= g_slist_remove(conn
->requests
, request
);
654 nm_release_request(request
);
658 nm_conn_find_request(NMConn
* conn
, int trans_id
)
660 NMRequest
*req
= NULL
;
666 itr
= conn
->requests
;
668 req
= (NMRequest
*) itr
->data
;
669 if (req
!= NULL
&& nm_request_get_trans_id(req
) == trans_id
) {
672 itr
= g_slist_next(itr
);
678 nm_conn_get_addr(NMConn
* conn
)
687 nm_conn_get_port(NMConn
* conn
)