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
)
186 for (node
= conn
->requests
; node
; node
= node
->next
) {
188 nm_release_request(node
->data
);
190 g_slist_free(conn
->requests
);
191 conn
->requests
= NULL
;
192 g_free(conn
->ssl_conn
);
193 conn
->ssl_conn
= NULL
;
201 nm_tcp_write(NMConn
* conn
, const void *buff
, int len
)
203 if (conn
== NULL
|| buff
== NULL
)
207 return (write(conn
->fd
, buff
, len
));
208 else if (conn
->ssl_conn
&& conn
->ssl_conn
->write
)
209 return (conn
->ssl_conn
->write(conn
->ssl_conn
->data
, buff
, len
));
215 nm_tcp_read(NMConn
* conn
, void *buff
, int len
)
217 if (conn
== NULL
|| buff
== NULL
)
221 return (read(conn
->fd
, buff
, len
));
222 else if (conn
->ssl_conn
&& conn
->ssl_conn
->read
)
223 return ((conn
->ssl_conn
->read
)(conn
->ssl_conn
->data
, buff
, len
));
229 nm_read_all(NMConn
* conn
, char *buff
, int len
)
232 int bytes_left
= len
;
237 if (conn
== NULL
|| buff
== NULL
)
238 return NMERR_BAD_PARM
;
240 /* Keep reading until buffer is full */
242 bytes_read
= nm_tcp_read(conn
, &buff
[total_bytes
], bytes_left
);
243 if (bytes_read
> 0) {
244 bytes_left
-= bytes_read
;
245 total_bytes
+= bytes_read
;
247 if (errno
== EAGAIN
) {
267 nm_read_uint32(NMConn
*conn
, guint32
*val
)
271 rc
= nm_read_all(conn
, (char *)val
, sizeof(*val
));
273 *val
= GUINT32_FROM_LE(*val
);
280 nm_read_uint16(NMConn
*conn
, guint16
*val
)
284 rc
= nm_read_all(conn
, (char *)val
, sizeof(*val
));
286 *val
= GUINT16_FROM_LE(*val
);
293 nm_write_fields(NMConn
* conn
, NMField
* fields
)
304 if (conn
== NULL
|| fields
== NULL
) {
305 return NMERR_BAD_PARM
;
308 /* Format each field as valid "post" data and write it out */
309 for (field
= fields
; (rc
== NM_OK
) && (field
->tag
); field
++) {
311 /* We don't currently handle binary types */
312 if (field
->method
== NMFIELD_METHOD_IGNORE
||
313 field
->type
== NMFIELD_TYPE_BINARY
) {
317 /* Write the field tag */
318 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
), "&tag=%s", field
->tag
);
319 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
321 rc
= NMERR_TCP_WRITE
;
324 /* Write the field method */
326 method
= encode_method(field
->method
);
327 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
), "&cmd=%s", method
);
328 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
330 rc
= NMERR_TCP_WRITE
;
334 /* Write the field value */
336 switch (field
->type
) {
337 case NMFIELD_TYPE_UTF8
:
338 case NMFIELD_TYPE_DN
:
340 value
= url_escape_string((char *) field
->ptr_value
);
341 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
343 if (bytes_to_send
> (int)sizeof(buffer
)) {
344 ret
= nm_tcp_write(conn
, buffer
, sizeof(buffer
));
346 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
350 rc
= NMERR_TCP_WRITE
;
357 case NMFIELD_TYPE_ARRAY
:
358 case NMFIELD_TYPE_MV
:
360 val
= nm_count_fields((NMField
*) field
->ptr_value
);
361 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
363 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
365 rc
= NMERR_TCP_WRITE
;
372 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
373 "&val=%u", field
->value
);
374 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
376 rc
= NMERR_TCP_WRITE
;
383 /* Write the field type */
385 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
386 "&type=%u", field
->type
);
387 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
389 rc
= NMERR_TCP_WRITE
;
393 /* If the field is a sub array then post its fields */
394 if (rc
== NM_OK
&& val
> 0) {
395 if (field
->type
== NMFIELD_TYPE_ARRAY
||
396 field
->type
== NMFIELD_TYPE_MV
) {
398 rc
= nm_write_fields(conn
, (NMField
*) field
->ptr_value
);
408 nm_send_request(NMConn
*conn
, char *cmd
, NMField
*fields
,
409 nm_response_cb cb
, gpointer data
, NMRequest
**request
)
415 NMField
*request_fields
= NULL
;
418 if (conn
== NULL
|| cmd
== NULL
)
419 return NMERR_BAD_PARM
;
422 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
423 "POST /%s HTTP/1.0\r\n", cmd
);
424 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
426 rc
= NMERR_TCP_WRITE
;
431 if (purple_strequal("login", cmd
)) {
432 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
),
433 "Host: %s:%d\r\n\r\n", conn
->addr
, conn
->port
);
434 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
436 rc
= NMERR_TCP_WRITE
;
439 bytes_to_send
= g_snprintf(buffer
, sizeof(buffer
), "\r\n");
440 ret
= nm_tcp_write(conn
, buffer
, bytes_to_send
);
442 rc
= NMERR_TCP_WRITE
;
447 /* Add the transaction id to the request fields */
450 request_fields
= nm_copy_field_array(fields
);
452 str
= g_strdup_printf("%d", ++(conn
->trans_id
));
453 request_fields
= nm_field_add_pointer(request_fields
, NM_A_SZ_TRANSACTION_ID
, 0,
454 NMFIELD_METHOD_VALID
, 0,
455 str
, NMFIELD_TYPE_UTF8
);
458 /* Send the request to the server */
460 rc
= nm_write_fields(conn
, request_fields
);
463 /* Write the CRLF to terminate the data */
465 ret
= nm_tcp_write(conn
, "\r\n", strlen("\r\n"));
467 rc
= NMERR_TCP_WRITE
;
471 /* Create a request struct, add it to our queue, and return it */
473 NMRequest
*new_request
= nm_create_request(cmd
, conn
->trans_id
,
474 time(0), cb
, NULL
, data
);
475 nm_conn_add_request_item(conn
, new_request
);
477 /* Set the out param if it was sent in, otherwise release the request */
479 *request
= new_request
;
481 nm_release_request(new_request
);
484 if (request_fields
!= NULL
)
485 nm_free_fields(&request_fields
);
491 nm_read_header(NMConn
* conn
)
501 return NMERR_BAD_PARM
;
504 rc
= read_line(conn
, buffer
, sizeof(buffer
));
507 /* Find the return code */
508 ptr
= strchr(buffer
, ' ');
513 while (isdigit(*ptr
) && (i
< 3)) {
521 rtn_code
= atoi(rtn_buf
);
525 /* Finish reading header, in the future we might want to do more processing here */
526 /* TODO: handle more general redirects in the future */
527 while ((rc
== NM_OK
) && (!purple_strequal(buffer
, "\r\n"))) {
528 rc
= read_line(conn
, buffer
, sizeof(buffer
));
531 if (rc
== NM_OK
&& rtn_code
== 301)
532 rc
= NMERR_SERVER_REDIRECT
;
538 nm_read_fields(NMConn
* conn
, int count
, NMField
** fields
)
545 NMField
*sub_fields
= NULL
;
548 if (conn
== NULL
|| fields
== NULL
)
549 return NMERR_BAD_PARM
;
556 /* Read the field type, method, and tag */
557 rc
= nm_read_all(conn
, (char *)&type
, sizeof(type
));
558 if (rc
!= NM_OK
|| type
== 0)
561 rc
= nm_read_all(conn
, (char *)&method
, sizeof(method
));
565 rc
= nm_read_uint32(conn
, &val
);
569 if (val
> sizeof(tag
)) {
574 rc
= nm_read_all(conn
, tag
, val
);
578 if (type
== NMFIELD_TYPE_MV
|| type
== NMFIELD_TYPE_ARRAY
) {
580 /* Read the subarray (first read the number of items in the array) */
581 rc
= nm_read_uint32(conn
, &val
);
586 rc
= nm_read_fields(conn
, val
, &sub_fields
);
591 *fields
= nm_field_add_pointer(*fields
, tag
, 0, method
,
592 0, sub_fields
, type
);
596 } else if (type
== NMFIELD_TYPE_UTF8
|| type
== NMFIELD_TYPE_DN
) {
598 /* Read the string (first read the length) */
599 rc
= nm_read_uint32(conn
, &val
);
603 if (val
>= NMFIELD_MAX_STR_LENGTH
) {
609 str
= g_new0(char, val
+ 1);
611 rc
= nm_read_all(conn
, str
, val
);
615 *fields
= nm_field_add_pointer(*fields
, tag
, 0, method
,
622 /* Read the numerical value */
623 rc
= nm_read_uint32(conn
, &val
);
627 *fields
= nm_field_add_number(*fields
, tag
, 0, method
,
631 } while ((type
!= 0) && (count
!= 0));
636 if (sub_fields
!= NULL
) {
637 nm_free_fields(&sub_fields
);
644 nm_conn_add_request_item(NMConn
* conn
, NMRequest
* request
)
646 if (conn
== NULL
|| request
== NULL
)
649 nm_request_add_ref(request
);
650 conn
->requests
= g_slist_append(conn
->requests
, request
);
654 nm_conn_remove_request_item(NMConn
* conn
, NMRequest
* request
)
656 if (conn
== NULL
|| request
== NULL
)
659 conn
->requests
= g_slist_remove(conn
->requests
, request
);
660 nm_release_request(request
);
664 nm_conn_find_request(NMConn
* conn
, int trans_id
)
666 NMRequest
*req
= NULL
;
672 itr
= conn
->requests
;
674 req
= (NMRequest
*) itr
->data
;
675 if (req
!= NULL
&& nm_request_get_trans_id(req
) == trans_id
) {
678 itr
= g_slist_next(itr
);
684 nm_conn_get_addr(NMConn
* conn
)
693 nm_conn_get_port(NMConn
* conn
)