Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
John McEleney
/
mailutils
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
f7942ced
...
f7942ced21d97774e678be261cc5b9094e47e8da
authored
2011-11-18 13:00:05 +0200
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Rewrite existing imap client support using imapio.
1 parent
a4a3755e
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
546 additions
and
316 deletions
include/mailutils/imap.h
include/mailutils/sys/imap.h
libproto/imap/Makefile.am
libproto/imap/capability.c
libproto/imap/carrier.c
libproto/imap/connect.c
libproto/imap/create.c
libproto/imap/destroy.c
libproto/imap/disconnect.c
libproto/imap/id.c
libproto/imap/login.c
libproto/imap/logout.c
libproto/imap/resplist.c
libproto/imap/response.c
libproto/imap/trace.c
mu/imap.c
include/mailutils/imap.h
View file @
f7942ce
...
...
@@ -53,7 +53,7 @@ int mu_imap_capability_test (mu_imap_t imap, const char *name,
int
mu_imap_login
(
mu_imap_t
imap
,
const
char
*
user
,
const
char
*
pass
);
int
mu_imap_logout
(
mu_imap_t
imap
);
int
mu_imap_id
(
mu_imap_t
imap
,
char
**
idenv
,
mu_
list_t
*
plist
);
int
mu_imap_id
(
mu_imap_t
imap
,
char
**
idenv
,
mu_
assoc_t
*
passoc
);
int
mu_imap_set_carrier
(
mu_imap_t
imap
,
mu_stream_t
carrier
);
int
mu_imap_get_carrier
(
mu_imap_t
imap
,
mu_stream_t
*
pcarrier
);
...
...
include/mailutils/sys/imap.h
View file @
f7942ce
...
...
@@ -22,6 +22,7 @@
# include <mailutils/sys/mailbox.h>
# include <mailutils/sys/registrar.h>
# include <mailutils/sys/auth.h>
# include <mailutils/imapio.h>
# include <mailutils/imap.h>
# ifdef __cplusplus
...
...
@@ -29,7 +30,7 @@ extern "C" {
# endif
#define MU_IMAP_RESP 0x01
#define MU_IMAP_TRACE 0x02
#define MU_IMAP_TRACE 0x02
#define MU_IMAP_XSCRIPT_MASK(n) (1<<((n)+1))
enum
mu_imap_client_state
...
...
@@ -56,9 +57,7 @@ struct _mu_imap
{
int
flags
;
/* Holds the tagged response to the last command */
char
*
tagbuf
;
size_t
tagsize
;
/* Holds the recect response code */
enum
mu_imap_response
resp_code
;
/* Untagged responses */
...
...
@@ -68,10 +67,6 @@ struct _mu_imap
char
*
errstr
;
size_t
errsize
;
/* Input line buffer */
char
*
rdbuf
;
size_t
rdsize
;
enum
mu_imap_state
state
;
enum
mu_imap_state
imap_state
;
...
...
@@ -81,7 +76,23 @@ struct _mu_imap
char
*
tag_str
;
/* String representation (tag_len + 1 bytes, asciiz) */
mu_list_t
capa
;
mu_stream_t
carrier
;
mu_imapio_t
io
;
};
enum
imap_eltype
{
imap_eltype_string
,
imap_eltype_list
};
struct
imap_list_element
{
enum
imap_eltype
type
;
union
{
mu_list_t
list
;
char
*
string
;
}
v
;
};
#define MU_IMAP_FSET(p,f) ((p)->flags |= (f))
...
...
@@ -137,6 +148,9 @@ int _mu_imap_tag_next (mu_imap_t imap);
int
_mu_imap_tag_clr
(
mu_imap_t
imap
);
int
_mu_imap_response
(
mu_imap_t
imap
);
int
_mu_imap_untagged_response_clear
(
mu_imap_t
imap
);
int
_mu_imap_untagged_response_add
(
mu_imap_t
imap
);
# ifdef __cplusplus
}
...
...
libproto/imap/Makefile.am
View file @
f7942ce
...
...
@@ -39,6 +39,7 @@ libmu_imap_la_SOURCES = \
id.c
\
login.c
\
logout.c
\
resplist.c
\
response.c
\
state.c
\
tag.c
\
...
...
libproto/imap/capability.c
View file @
f7942ce
...
...
@@ -19,13 +19,14 @@
# include <config.h>
#endif
#include <string.h>
#include <mailutils/types.h>
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/list.h>
#include <mailutils/
wordsplit
.h>
#include <mailutils/
iterator
.h>
#include <mailutils/sys/imap.h>
static
int
...
...
@@ -50,7 +51,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
if
(
imap
==
NULL
)
return
EINVAL
;
if
(
!
imap
->
carrier
)
if
(
!
imap
->
io
)
return
MU_ERR_NO_TRANSPORT
;
if
(
imap
->
state
!=
MU_IMAP_CONNECTED
)
return
MU_ERR_SEQ
;
...
...
@@ -78,7 +79,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
case
MU_IMAP_CONNECTED
:
status
=
_mu_imap_tag_next
(
imap
);
MU_IMAP_CHECK_EAGAIN
(
imap
,
status
);
status
=
mu_
stream_printf
(
imap
->
carrier
,
"%s CAPABILITY
\r\n
"
,
status
=
mu_
imapio_printf
(
imap
->
io
,
"%s CAPABILITY
\r\n
"
,
imap
->
tag_str
);
MU_IMAP_CHECK_EAGAIN
(
imap
,
status
);
MU_IMAP_FCLR
(
imap
,
MU_IMAP_RESP
);
...
...
@@ -92,35 +93,35 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
else
{
size_t
count
;
char
*
str
;
struct
imap_list_element
*
elt
;
imap
->
state
=
MU_IMAP_CONNECTED
;
mu_list_count
(
imap
->
untagged_resp
,
&
count
);
if
(
mu_list_get
(
imap
->
untagged_resp
,
0
,
(
void
*
)
&
str
)
==
0
)
if
(
mu_list_get
(
imap
->
untagged_resp
,
0
,
(
void
*
)
&
elt
)
==
0
)
{
size_t
i
;
/* Top-level elements are always of imap_eltype_list type. */
mu_iterator_t
itr
;
struct
mu_wordsplit
ws
;
if
(
mu_wordsplit
(
str
,
&
ws
,
MU_WRDSF_NOVAR
|
MU_WRDSF_NOCMD
|
MU_WRDSF_QUOTE
|
MU_WRDSF_SQUEEZE_DELIMS
))
{
int
ec
=
errno
;
mu_error
(
"mu_imap_capability: cannot split line: %s"
,
mu_wordsplit_strerror
(
&
ws
));
return
ec
;
}
if
(
ws
.
ws_wordc
>
1
&&
mu_c_strcasecmp
(
ws
.
ws_wordv
[
0
],
"CAPABILITY"
)
==
0
)
mu_list_get_iterator
(
elt
->
v
.
list
,
&
itr
);
mu_iterator_first
(
itr
);
if
(
mu_iterator_is_done
(
itr
))
return
MU_ERR_PARSE
;
mu_iterator_current
(
itr
,
(
void
**
)
&
elt
);
if
(
elt
->
type
==
imap_eltype_string
&&
strcmp
(
elt
->
v
.
string
,
"CAPABILITY"
)
==
0
)
{
for
(
i
=
1
;
i
<
ws
.
ws_wordc
;
i
++
)
for
(
mu_iterator_next
(
itr
);
!
mu_iterator_is_done
(
itr
);
mu_iterator_next
(
itr
))
{
mu_list_append
(
imap
->
capa
,
ws
.
ws_wordv
[
i
]);
ws
.
ws_wordv
[
i
]
=
NULL
;
mu_iterator_current
(
itr
,
(
void
**
)
&
elt
);
if
(
elt
->
type
==
imap_eltype_string
)
{
mu_list_append
(
imap
->
capa
,
elt
->
v
.
string
);
elt
->
v
.
string
=
NULL
;
}
}
}
mu_
wordsplit_free
(
&
ws
);
mu_
iterator_destroy
(
&
itr
);
}
if
(
piter
)
status
=
mu_list_get_iterator
(
imap
->
capa
,
piter
);
...
...
libproto/imap/carrier.c
View file @
f7942ce
...
...
@@ -23,23 +23,30 @@
#include <stdlib.h>
#include <errno.h>
#include <mailutils/errno.h>
#include <mailutils/imapio.h>
#include <mailutils/sys/imap.h>
#include <mailutils/sys/imapio.h>
int
mu_imap_set_carrier
(
mu_imap_t
imap
,
mu_stream_t
carrier
)
{
int
rc
;
mu_imapio_t
io
;
/* Sanity checks. */
if
(
imap
==
NULL
)
return
EINVAL
;
if
(
imap
->
carrier
)
rc
=
mu_imapio_create
(
&
io
,
carrier
);
if
(
rc
)
return
rc
;
if
(
imap
->
io
)
{
/* Close any old carrier. */
mu_imap_disconnect
(
imap
);
mu_
stream_destroy
(
&
imap
->
carrier
);
mu_
imapio_free
(
imap
->
io
);
}
mu_stream_ref
(
carrier
);
imap
->
carrier
=
carrier
;
imap
->
io
=
io
;
if
(
MU_IMAP_FISSET
(
imap
,
MU_IMAP_TRACE
))
_mu_imap_trace_enable
(
imap
);
imap
->
state
=
MU_IMAP_CONNECT
;
...
...
@@ -55,8 +62,8 @@ mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier)
if
(
pcarrier
==
NULL
)
return
MU_ERR_OUT_PTR_NULL
;
mu_stream_ref
(
imap
->
carrier
);
*
pcarrier
=
imap
->
carrier
;
mu_stream_ref
(
imap
->
io
->
_imap_stream
);
*
pcarrier
=
imap
->
io
->
_imap_stream
;
return
0
;
}
...
...
libproto/imap/connect.c
View file @
f7942ce
...
...
@@ -24,18 +24,23 @@
#include <sys/select.h>
#include <sys/time.h>
#include <mailutils/errno.h>
#include <mailutils/
wordsplit
.h>
#include <mailutils/
imapio
.h>
#include <mailutils/sys/imap.h>
#include <mailutils/sys/imapio.h>
int
mu_imap_connect
(
mu_imap_t
imap
)
{
int
status
;
size_t
wc
;
char
**
wv
;
char
*
bufptr
;
size_t
bufsize
;
if
(
imap
==
NULL
)
return
EINVAL
;
if
(
imap
->
carrier
==
NULL
)
if
(
imap
->
io
==
NULL
)
return
EINVAL
;
switch
(
imap
->
state
)
{
...
...
@@ -54,66 +59,48 @@ mu_imap_connect (mu_imap_t imap)
case
MU_IMAP_CONNECT
:
/* Establish the connection. */
if
(
!
mu_stream_is_open
(
imap
->
carrier
))
if
(
!
mu_stream_is_open
(
imap
->
io
->
_imap_stream
))
{
status
=
mu_stream_open
(
imap
->
carrier
);
status
=
mu_stream_open
(
imap
->
io
->
_imap_stream
);
MU_IMAP_CHECK_EAGAIN
(
imap
,
status
);
MU_IMAP_FCLR
(
imap
,
MU_IMAP_RESP
);
}
imap
->
state
=
MU_IMAP_GREETINGS
;
case
MU_IMAP_GREETINGS
:
status
=
mu_stream_getline
(
imap
->
carrier
,
&
imap
->
rdbuf
,
&
imap
->
rdsize
,
NULL
);
status
=
mu_imapio_getline
(
imap
->
io
);
MU_IMAP_CHECK_EAGAIN
(
imap
,
status
);
if
(
imap
->
rdsize
<
2
||
!
(
imap
->
rdbuf
[
0
]
==
'*'
&&
imap
->
rdbuf
[
1
]
==
' '
))
mu_imapio_get_words
(
imap
->
io
,
&
wc
,
&
wv
);
if
(
wc
<
2
||
strcmp
(
wv
[
0
],
"*"
))
{
mu_imapio_getbuf
(
imap
->
io
,
&
bufptr
,
&
bufsize
);
mu_error
(
"mu_imap_connect: invalid server response: %s"
,
imap
->
rdbuf
);
bufptr
);
imap
->
state
=
MU_IMAP_ERROR
;
return
MU_ERR_BADREPLY
;
}
else
if
(
strcmp
(
wv
[
1
],
"BYE"
)
==
0
)
{
status
=
EACCES
;
mu_imapio_getbuf
(
imap
->
io
,
&
bufptr
,
&
bufsize
);
_mu_imap_seterrstr
(
imap
,
bufptr
+
2
,
bufsize
-
2
);
}
else
if
(
strcmp
(
wv
[
1
],
"PREAUTH"
)
==
0
)
{
status
=
0
;
imap
->
state
=
MU_IMAP_CONNECTED
;
imap
->
imap_state
=
MU_IMAP_STATE_AUTH
;
}
else
if
(
strcmp
(
wv
[
1
],
"OK"
)
==
0
)
{
status
=
0
;
imap
->
state
=
MU_IMAP_CONNECTED
;
imap
->
imap_state
=
MU_IMAP_STATE_NONAUTH
;
}
else
{
struct
mu_wordsplit
ws
;
if
(
mu_wordsplit
(
imap
->
rdbuf
,
&
ws
,
MU_WRDSF_NOVAR
|
MU_WRDSF_NOCMD
|
MU_WRDSF_SQUEEZE_DELIMS
))
{
int
ec
=
errno
;
mu_error
(
"mu_imap_connect: cannot split line: %s"
,
mu_wordsplit_strerror
(
&
ws
));
imap
->
state
=
MU_IMAP_ERROR
;
return
ec
;
}
if
(
ws
.
ws_wordc
<
2
)
status
=
MU_ERR_BADREPLY
;
else
if
(
strcmp
(
ws
.
ws_wordv
[
1
],
"BYE"
)
==
0
)
{
status
=
EACCES
;
_mu_imap_seterrstr
(
imap
,
imap
->
rdbuf
+
2
,
strlen
(
imap
->
rdbuf
+
2
));
}
else
if
(
strcmp
(
ws
.
ws_wordv
[
1
],
"PREAUTH"
)
==
0
)
{
status
=
0
;
imap
->
state
=
MU_IMAP_CONNECTED
;
imap
->
imap_state
=
MU_IMAP_STATE_AUTH
;
}
else
if
(
strcmp
(
ws
.
ws_wordv
[
1
],
"OK"
)
==
0
)
{
status
=
0
;
imap
->
state
=
MU_IMAP_CONNECTED
;
imap
->
imap_state
=
MU_IMAP_STATE_NONAUTH
;
}
else
{
status
=
MU_ERR_BADREPLY
;
imap
->
state
=
MU_IMAP_ERROR
;
}
mu_wordsplit_free
(
&
ws
);
status
=
MU_ERR_BADREPLY
;
imap
->
state
=
MU_IMAP_ERROR
;
}
}
...
...
libproto/imap/create.c
View file @
f7942ce
...
...
@@ -49,7 +49,7 @@ _mu_imap_init (mu_imap_t imap)
{
if
(
imap
==
NULL
)
return
EINVAL
;
if
(
imap
->
carrier
==
0
)
if
(
!
imap
->
io
)
{
int
rc
;
...
...
libproto/imap/destroy.c
View file @
f7942ce
...
...
@@ -31,13 +31,6 @@ mu_imap_destroy (mu_imap_t *pimap)
{
mu_imap_t
imap
=
*
pimap
;
/* Free the response buffer. */
if
(
imap
->
tagbuf
)
free
(
imap
->
tagbuf
);
/* Free the read buffer. */
if
(
imap
->
rdbuf
)
free
(
imap
->
rdbuf
);
if
(
imap
->
errstr
)
free
(
imap
->
errstr
);
...
...
@@ -49,7 +42,7 @@ mu_imap_destroy (mu_imap_t *pimap)
mu_list_destroy
(
&
imap
->
untagged_resp
);
mu_list_destroy
(
&
imap
->
capa
);
mu_
stream_destroy
(
&
imap
->
carrier
);
mu_
imapio_destroy
(
&
imap
->
io
);
free
(
imap
);
...
...
libproto/imap/disconnect.c
View file @
f7942ce
...
...
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mailutils/imapio.h>
#include <mailutils/sys/imap.h>
int
...
...
@@ -34,14 +35,11 @@ mu_imap_disconnect (mu_imap_t imap)
imap
->
state
=
MU_IMAP_NO_STATE
;
MU_IMAP_FCLR
(
imap
,
MU_IMAP_RESP
);
if
(
imap
->
rdbuf
)
imap
->
rdbuf
[
0
]
=
0
;
mu_list_clear
(
imap
->
untagged_resp
);
mu_list_clear
(
imap
->
capa
);
/* Close the stream. */
if
(
mu_stream_is_open
(
imap
->
carrier
))
return
mu_stream_close
(
imap
->
carrier
);
mu_imapio_destroy
(
&
imap
->
io
);
return
0
;
}
...
...
libproto/imap/id.c
View file @
f7942ce
...
...
@@ -22,93 +22,109 @@
#include <stdlib.h>
#include <string.h>
#include <mailutils/errno.h>
#include <mailutils/cstr.h>
#include <mailutils/wordsplit.h>
#include <mailutils/assoc.h>
#include <mailutils/stream.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
static
int
id_comp
(
const
void
*
item
,
const
void
*
value
)
void
_id_free
(
void
*
data
)
{
const
char
*
id
=
item
;
const
char
*
needle
=
value
;
return
mu_c_strcasecmp
(
id
,
needle
);
char
*
s
=
*
(
char
**
)
data
;
free
(
s
);
}
struct
id_convert_state
{
int
item
;
mu_assoc_t
assoc
;
int
ret
;
};
static
int
parse_id_reply
(
mu_imap_t
imap
,
mu_list_t
*
plist
)
_id_convert
(
void
*
item
,
void
*
data
)
{
struct
imap_list_element
*
elt
=
item
;
struct
id_convert_state
*
stp
=
data
;
switch
(
stp
->
item
)
{
case
0
:
if
(
!
(
elt
->
type
==
imap_eltype_string
&&
strcmp
(
elt
->
v
.
string
,
"ID"
)
==
0
))
{
stp
->
ret
=
MU_ERR_PARSE
;
return
1
;
}
stp
->
item
++
;
return
0
;
case
1
:
if
(
elt
->
type
==
imap_eltype_list
)
{
mu_iterator_t
itr
;
mu_list_get_iterator
(
elt
->
v
.
list
,
&
itr
);
for
(
mu_iterator_first
(
itr
);
!
mu_iterator_is_done
(
itr
);
mu_iterator_next
(
itr
))
{
char
*
key
,
*
val
;
mu_iterator_current
(
itr
,
(
void
**
)
&
elt
);
if
(
elt
->
type
!=
imap_eltype_string
)
break
;
key
=
elt
->
v
.
string
;
elt
->
v
.
string
=
NULL
;
mu_iterator_next
(
itr
);
if
(
mu_iterator_is_done
(
itr
))
break
;
mu_iterator_current
(
itr
,
(
void
**
)
&
elt
);
if
(
elt
->
type
!=
imap_eltype_string
)
break
;
val
=
elt
->
v
.
string
;
elt
->
v
.
string
=
NULL
;
mu_assoc_install
(
stp
->
assoc
,
key
,
&
val
);
}
}
}
return
1
;
}
static
int
parse_id_reply
(
mu_imap_t
imap
,
mu_assoc_t
*
passoc
)
{
mu_list_t
list
;
int
rc
;
const
char
*
response
;
struct
mu_wordsplit
ws
;
size_t
i
;
rc
=
mu_
list_create
(
&
list
);
struct
imap_list_element
const
*
response
;
struct
id_convert_state
st
;
mu_assoc_t
assoc
;
rc
=
mu_
assoc_create
(
&
assoc
,
sizeof
(
char
**
),
MU_ASSOC_ICASE
);
if
(
rc
)
return
rc
;
mu_list_set_comparator
(
list
,
id_comp
);
mu_list_set_destroy_item
(
list
,
mu_list_free_item
);
mu_assoc_set_free
(
assoc
,
_id_free
);
rc
=
mu_list_get
(
imap
->
untagged_resp
,
0
,
(
void
*
)
&
response
);
*
passoc
=
assoc
;
if
(
rc
==
MU_ERR_NOENT
)
{
*
plist
=
list
;
return
0
;
}
else
if
(
rc
)
{
mu_list_destroy
(
&
list
);
return
rc
;
}
ws
.
ws_delim
=
"()
\t
"
;
if
(
mu_wordsplit
(
response
,
&
ws
,
MU_WRDSF_NOVAR
|
MU_WRDSF_NOCMD
|
MU_WRDSF_QUOTE
|
MU_WRDSF_DELIM
|
MU_WRDSF_SQUEEZE_DELIMS
|
MU_WRDSF_WS
))
{
int
ec
=
errno
;
mu_error
(
"mu_imap_id: cannot split line: %s"
,
mu_wordsplit_strerror
(
&
ws
));
mu_list_destroy
(
&
list
);
return
ec
;
}
return
0
;
for
(
i
=
1
;
i
<
ws
.
ws_wordc
;
i
+=
2
)
{
size_t
len
,
l1
,
l2
;
char
*
elt
;
if
(
i
+
1
==
ws
.
ws_wordc
)
break
;
l1
=
strlen
(
ws
.
ws_wordv
[
i
]);
l2
=
strlen
(
ws
.
ws_wordv
[
i
+
1
]);
len
=
l1
+
l2
+
1
;
elt
=
malloc
(
len
+
1
);
if
(
!
elt
)
break
;
memcpy
(
elt
,
ws
.
ws_wordv
[
i
],
l1
);
elt
[
l1
]
=
0
;
memcpy
(
elt
+
l1
+
1
,
ws
.
ws_wordv
[
i
+
1
],
l2
);
elt
[
len
]
=
0
;
mu_list_append
(
list
,
elt
);
}
mu_wordsplit_free
(
&
ws
);
*
plist
=
list
;
return
0
;
st
.
item
=
0
;
st
.
assoc
=
assoc
;
st
.
ret
=
0
;
mu_list_do
(
response
->
v
.
list
,
_id_convert
,
&
st
);
return
st
.
ret
;
}
int
mu_imap_id
(
mu_imap_t
imap
,
char
**
idenv
,
mu_
list_t
*
plist
)
mu_imap_id
(
mu_imap_t
imap
,
char
**
idenv
,
mu_
assoc_t
*
passoc
)
{
int
status
;
if
(
imap
==
NULL
)
return
EINVAL
;
if
(
!
imap
->
carrier
)
if
(
!
imap
->
io
)
return
MU_ERR_NO_TRANSPORT
;
if
(
imap
->
state
!=
MU_IMAP_CONNECTED
)
return
MU_ERR_SEQ
;
...
...
@@ -118,11 +134,10 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
case
MU_IMAP_CONNECTED
:
status
=
_mu_imap_tag_next
(
imap
);
MU_IMAP_CHECK_EAGAIN
(
imap
,
status
);
status
=
mu_stream_printf
(
imap
->
carrier
,
"%s ID "
,
imap
->
tag_str
);
status
=
mu_imapio_printf
(
imap
->
io
,
"%s ID "
,
imap
->
tag_str
);
MU_IMAP_CHECK_ERROR
(
imap
,
status
);
if
(
!
idenv
)
status
=
mu_
stream_printf
(
imap
->
carrier
,
"NIL"
);
status
=
mu_
imapio_printf
(
imap
->
io
,
"NIL"
);
else
{
if
(
idenv
[
0
])
...
...
@@ -131,7 +146,7 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
char
*
delim
=
"("
;
for
(
i
=
0
;
idenv
[
i
];
i
++
)
{
status
=
mu_
stream_printf
(
imap
->
carrier
,
"%s
\"
%s
\"
"
,
status
=
mu_
imapio_printf
(
imap
->
io
,
"%s
\"
%s
\"
"
,
delim
,
idenv
[
i
]);
MU_IMAP_CHECK_ERROR
(
imap
,
status
);
...
...
@@ -139,13 +154,13 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
if
(
status
)
break
;
}
status
=
mu_
stream_printf
(
imap
->
carrier
,
")"
);
status
=
mu_
imapio_printf
(
imap
->
io
,
")"
);
}
else
status
=
mu_
stream_printf
(
imap
->
carrier
,
"()"
);
status
=
mu_
imapio_printf
(
imap
->
io
,
"()"
);
}
MU_IMAP_CHECK_ERROR
(
imap
,
status
);
status
=
mu_
stream_printf
(
imap
->
carrier
,
"
\r\n
"
);
status
=
mu_
imapio_printf
(
imap
->
io
,
"
\r\n
"
);
MU_IMAP_CHECK_ERROR
(
imap
,
status
);
MU_IMAP_FCLR
(
imap
,
MU_IMAP_RESP
);
imap
->
state
=
MU_IMAP_ID_RX
;
...
...
@@ -157,8 +172,8 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
{
case
MU_IMAP_OK
:
imap
->
imap_state
=
MU_IMAP_STATE_AUTH
;
if
(
p
list
)
status
=
parse_id_reply
(
imap
,
p
list
);
if
(
p
assoc
)
status
=
parse_id_reply
(
imap
,
p
assoc
);
break
;
case
MU_IMAP_NO
:
...
...
libproto/imap/login.c
View file @
f7942ce
...
...
@@ -30,7 +30,7 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
if
(
imap
==
NULL
)
return
EINVAL
;
if
(
!
imap
->
carrier
)
if
(
!
imap
->
io
)
return
MU_ERR_NO_TRANSPORT
;
if
(
imap
->
state
!=
MU_IMAP_CONNECTED
)
return
MU_ERR_SEQ
;
...
...
@@ -44,7 +44,7 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
_mu_imap_xscript_level
(
imap
,
MU_XSCRIPT_SECURE
);
status
=
_mu_imap_tag_next
(
imap
);
MU_IMAP_CHECK_EAGAIN
(
imap
,
status
);
status
=
mu_
stream_printf
(
imap
->
carrier
,
"%s LOGIN
\"
%s
\"
\"
%s
\"\r\n
"
,
status
=
mu_
imapio_printf
(
imap
->
io
,
"%s LOGIN
\"
%s
\"
\"
%s
\"\r\n
"
,
imap
->
tag_str
,
user
,
pass
);
_mu_imap_xscript_level
(
imap
,
MU_XSCRIPT_NORMAL
);
/* FIXME: how to obscure the passwd in the stream buffer? */
...
...
libproto/imap/logout.c
View file @
f7942ce
...
...
@@ -30,7 +30,7 @@ mu_imap_logout (mu_imap_t imap)
if
(
imap
==
NULL
)
return
EINVAL
;
if
(
!
imap
->
carrier
)
if
(
!
imap
->
io
)
return
MU_ERR_NO_TRANSPORT
;
if
(
imap
->
state
!=
MU_IMAP_CONNECTED
)
return
MU_ERR_SEQ
;
...
...
@@ -40,7 +40,7 @@ mu_imap_logout (mu_imap_t imap)
case
MU_IMAP_CONNECTED
:
status
=
_mu_imap_tag_next
(
imap
);
MU_IMAP_CHECK_EAGAIN
(
imap
,
status
);
status
=
mu_
stream_printf
(
imap
->
carrier
,
"%s LOGOUT
\r\n
"
,
status
=
mu_
imapio_printf
(
imap
->
io
,
"%s LOGOUT
\r\n
"
,
imap
->
tag_str
);
MU_IMAP_CHECK_EAGAIN
(
imap
,
status
);
MU_IMAP_FCLR
(
imap
,
MU_IMAP_RESP
);
...
...
libproto/imap/resplist.c
0 → 100644
View file @
f7942ce
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010, 2011 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
#include <mailutils/stream.h>
#include <mailutils/errno.h>
#include <mailutils/sys/imap.h>
static
void
_imap_list_free
(
void
*
ptr
)
{
struct
imap_list_element
*
elt
=
ptr
;
switch
(
elt
->
type
)
{
case
imap_eltype_string
:
free
(
elt
->
v
.
string
);
break
;
case
imap_eltype_list
:
mu_list_destroy
(
&
elt
->
v
.
list
);
}
free
(
ptr
);
}
static
int
_mu_imap_response_list_create
(
mu_imap_t
imap
,
mu_list_t
*
plist
)
{
mu_list_t
list
;
int
status
=
mu_list_create
(
&
list
);
MU_IMAP_CHECK_ERROR
(
imap
,
status
);
mu_list_set_destroy_item
(
list
,
_imap_list_free
);
*
plist
=
list
;
return
0
;
}
int
_mu_imap_untagged_response_clear
(
mu_imap_t
imap
)
{
if
(
imap
->
untagged_resp
)
mu_list_clear
(
imap
->
untagged_resp
);
else
return
_mu_imap_response_list_create
(
imap
,
&
imap
->
untagged_resp
);
return
0
;
}
#define IS_LBRACE(p) ((p)[0] == '(')
#define IS_RBRACE(p) ((p)[0] == ')')
static
struct
imap_list_element
*
_new_imap_list_element
(
mu_imap_t
imap
,
enum
imap_eltype
type
)
{
struct
imap_list_element
*
elt
=
calloc
(
1
,
sizeof
(
*
elt
));
if
(
!
elt
)
{
imap
->
state
=
MU_IMAP_ERROR
;
}
else
elt
->
type
=
type
;
return
elt
;
}
struct
parsebuf
{
mu_imap_t
pb_imap
;
size_t
pb_count
;
char
**
pb_arr
;
int
pb_err
;
int
pb_inlist
;
};
static
void
parsebuf_init
(
struct
parsebuf
*
pb
,
mu_imap_t
imap
)
{
memset
(
pb
,
0
,
sizeof
*
pb
);
pb
->
pb_imap
=
imap
;
}
static
int
parsebuf_advance
(
struct
parsebuf
*
pb
)
{
if
(
pb
->
pb_count
==
0
)
return
MU_ERR_NOENT
;
pb
->
pb_count
--
;
pb
->
pb_arr
++
;
return
0
;
}
static
char
*
parsebuf_gettok
(
struct
parsebuf
*
pb
)
{
char
*
p
;
if
(
pb
->
pb_count
==
0
)
return
NULL
;
p
=
*
pb
->
pb_arr
;
parsebuf_advance
(
pb
);
return
p
;
}
static
char
*
parsebuf_peek
(
struct
parsebuf
*
pb
)
{
if
(
pb
->
pb_count
==
0
)
return
NULL
;
return
*
pb
->
pb_arr
;
}
static
void
parsebuf_seterr
(
struct
parsebuf
*
pb
,
int
err
)
{
pb
->
pb_err
=
err
;
}
static
struct
imap_list_element
*
_parse_element
(
struct
parsebuf
*
pb
);
static
struct
imap_list_element
*
_parse_list
(
struct
parsebuf
*
pb
)
{
int
rc
;
struct
imap_list_element
*
elt
,
*
list_elt
;
elt
=
_new_imap_list_element
(
pb
->
pb_imap
,
imap_eltype_list
);
if
(
!
elt
)
{
parsebuf_seterr
(
pb
,
ENOMEM
);
return
NULL
;
}
rc
=
_mu_imap_response_list_create
(
pb
->
pb_imap
,
&
elt
->
v
.
list
);
if
(
rc
)
{
free
(
elt
);
parsebuf_seterr
(
pb
,
rc
);
return
NULL
;
}
while
((
list_elt
=
_parse_element
(
pb
)))
mu_list_append
(
elt
->
v
.
list
,
list_elt
);
return
elt
;
}
static
struct
imap_list_element
*
_parse_element
(
struct
parsebuf
*
pb
)
{
struct
imap_list_element
*
elt
;
char
*
tok
;
if
(
pb
->
pb_err
)
return
NULL
;
tok
=
parsebuf_gettok
(
pb
);
if
(
!
tok
)
{
if
(
pb
->
pb_inlist
)
parsebuf_seterr
(
pb
,
MU_ERR_PARSE
);
return
NULL
;
}
if
(
IS_LBRACE
(
tok
))
{
tok
=
parsebuf_peek
(
pb
);
if
(
!
tok
)
{
parsebuf_seterr
(
pb
,
MU_ERR_PARSE
);
return
NULL
;
}
if
(
IS_RBRACE
(
tok
))
{
elt
=
_new_imap_list_element
(
pb
->
pb_imap
,
imap_eltype_list
);
if
(
!
elt
)
{
parsebuf_seterr
(
pb
,
ENOMEM
);
return
NULL
;
}
elt
->
v
.
list
=
NULL
;
}
else
{
pb
->
pb_inlist
++
;
elt
=
_parse_list
(
pb
);
}
}
else
if
(
IS_RBRACE
(
tok
))
{
if
(
pb
->
pb_inlist
)
pb
->
pb_inlist
--
;
else
parsebuf_seterr
(
pb
,
MU_ERR_PARSE
);
return
NULL
;
}
else
{
char
*
s
;
elt
=
_new_imap_list_element
(
pb
->
pb_imap
,
imap_eltype_string
);
if
(
!
elt
)
{
parsebuf_seterr
(
pb
,
ENOMEM
);
return
NULL
;
}
s
=
strdup
(
tok
);
if
(
!
s
)
{
free
(
elt
);
parsebuf_seterr
(
pb
,
ENOMEM
);
return
NULL
;
}
elt
->
v
.
string
=
s
;
}
return
elt
;
}
int
_mu_imap_untagged_response_add
(
mu_imap_t
imap
)
{
struct
imap_list_element
*
elt
;
struct
parsebuf
pb
;
parsebuf_init
(
&
pb
,
imap
);
mu_imapio_get_words
(
imap
->
io
,
&
pb
.
pb_count
,
&
pb
.
pb_arr
);
parsebuf_advance
(
&
pb
);
/* Skip initial '*' */
elt
=
_parse_list
(
&
pb
);
if
(
pb
.
pb_err
)
{
if
(
elt
)
_imap_list_free
(
elt
);
imap
->
state
=
MU_IMAP_ERROR
;
return
pb
.
pb_err
;
}
mu_list_append
(
imap
->
untagged_resp
,
elt
);
return
0
;
}
libproto/imap/response.c
View file @
f7942ce
...
...
@@ -27,15 +27,9 @@
#include <mailutils/errno.h>
#include <mailutils/sys/imap.h>
#define IS_PREFIX(s, len, pfx) \
((len) >= sizeof (pfx) - 1 && \
memcmp ((s), (pfx), sizeof (pfx) - 1) == 0 && \
s[sizeof (pfx) - 1] == ' ')
int
_mu_imap_response
(
mu_imap_t
imap
)
{
size_t
n
=
0
;
int
status
=
0
;
if
(
imap
==
NULL
)
...
...
@@ -45,81 +39,74 @@ _mu_imap_response (mu_imap_t imap)
return
0
;
_mu_imap_clrerrstr
(
imap
);
if
(
imap
->
untagged_resp
)
mu_list_clear
(
imap
->
untagged_resp
);
else
{
status
=
mu_list_create
(
&
imap
->
untagged_resp
);
MU_IMAP_CHECK_ERROR
(
imap
,
status
);
mu_list_set_destroy_item
(
imap
->
untagged_resp
,
mu_list_free_item
);
}
status
=
_mu_imap_untagged_response_clear
(
imap
);
if
(
status
)
return
status
;
while
(
1
)
{
status
=
mu_stream_getline
(
imap
->
carrier
,
&
imap
->
rdbuf
,
&
imap
->
rdsize
,
NULL
);
status
=
mu_imapio_getline
(
imap
->
io
);
if
(
status
==
0
)
{
n
=
mu_rtrim_class
(
imap
->
rdbuf
,
MU_CTYPE_SPACE
);
if
(
imap
->
rdbuf
[
0
]
==
'*'
&&
imap
->
rdbuf
[
1
]
==
' '
)
char
**
wv
;
size_t
wc
;
char
*
p
;
mu_imapio_get_words
(
imap
->
io
,
&
wc
,
&
wv
);
if
(
strcmp
(
wv
[
0
],
"*"
)
==
0
)
{
char
*
p
=
mu_str_skip_cset
(
imap
->
rdbuf
+
2
,
" "
);
mu_list_append
(
imap
->
untagged_resp
,
strdup
(
p
))
;
_mu_imap_untagged_response_add
(
imap
);
/* FIXME: error checking */
continue
;
}
else
if
(
n
>
imap
->
tag_len
+
3
&&
memcmp
(
imap
->
rdbuf
,
imap
->
tag_str
,
imap
->
tag_len
)
==
0
&&
imap
->
rdbuf
[
imap
->
tag_len
]
==
' '
)
else
if
(
strlen
(
wv
[
0
])
==
imap
->
tag_len
&&
memcmp
(
wv
[
0
],
imap
->
tag_str
,
imap
->
tag_len
)
==
0
)
{
char
*
p
=
mu_str_skip_cset
(
imap
->
rdbuf
+
imap
->
tag_len
,
" "
);
size_t
len
=
strlen
(
p
);
if
(
len
>=
imap
->
tagsize
)
/* Handle the tagged response */
if
(
wc
<
2
)
{
char
*
np
=
realloc
(
imap
->
tagbuf
,
len
+
1
);
if
(
!
np
)
{
imap
->
state
=
MU_IMAP_ERROR
;
return
ENOMEM
;
}
imap
->
tagsize
=
len
+
1
;
imap
->
tagbuf
=
np
;
/*imap->state = MU_IMAP_ERROR;*/
status
=
MU_ERR_BADREPLY
;
}
strcpy
(
imap
->
tagbuf
,
p
);
if
(
IS_PREFIX
(
p
,
len
,
"OK"
))
else
if
(
strcmp
(
wv
[
1
],
"OK"
)
==
0
)
{
imap
->
resp_code
=
MU_IMAP_OK
;
p
=
mu_str_skip_cset
(
p
+
2
,
" "
);
_mu_imap_seterrstr
(
imap
,
p
,
strlen
(
p
));
if
(
mu_imapio_reply_string
(
imap
->
io
,
2
,
&
p
)
==
0
)
{
_mu_imap_seterrstr
(
imap
,
p
,
strlen
(
p
));
free
(
p
);
}
}
else
if
(
IS_PREFIX
(
p
,
len
,
"NO"
)
)
else
if
(
strcmp
(
wv
[
1
],
"NO"
)
==
0
)
{
imap
->
resp_code
=
MU_IMAP_NO
;
p
=
mu_str_skip_cset
(
p
+
2
,
" "
);
_mu_imap_seterrstr
(
imap
,
p
,
strlen
(
p
));
if
(
mu_imapio_reply_string
(
imap
->
io
,
2
,
&
p
)
==
0
)
{
_mu_imap_seterrstr
(
imap
,
p
,
strlen
(
p
));
free
(
p
);
}
}
else
if
(
IS_PREFIX
(
p
,
len
,
"BAD"
)
)
else
if
(
strcmp
(
wv
[
1
],
"BAD"
)
==
0
)
{
imap
->
resp_code
=
MU_IMAP_BAD
;
p
=
mu_str_skip_cset
(
p
+
2
,
" "
);
_mu_imap_seterrstr
(
imap
,
p
,
strlen
(
p
));
if
(
mu_imapio_reply_string
(
imap
->
io
,
2
,
&
p
)
==
0
)
{
_mu_imap_seterrstr
(
imap
,
p
,
strlen
(
p
));
free
(
p
);
}
}
else
status
=
MU_ERR_BADREPLY
;
MU_IMAP_FSET
(
imap
,
MU_IMAP_RESP
);
break
;
}
else
{
imap
->
state
=
MU_IMAP_ERROR
;
return
MU_ERR_BADREPLY
;
status
=
MU_ERR_BADREPLY
;
}
}
else
{
imap
->
state
=
MU_IMAP_ERROR
;
return
status
;
}
imap
->
state
=
MU_IMAP_ERROR
;
break
;
}
return
status
;
}
...
...
libproto/imap/trace.c
View file @
f7942ce
...
...
@@ -19,78 +19,50 @@
# include <config.h>
#endif
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
#include <mailutils/stream.h>
#include <mailutils/imapio.h>
#include <mailutils/sys/imap.h>
static
const
char
*
imap_prefix
[]
=
{
"S: "
,
"C: "
};
int
_mu_imap_trace_enable
(
mu_imap_t
imap
)
{
int
rc
=
0
;
mu_stream_t
dstr
,
xstr
;
if
(
!
imap
->
carrier
)
int
rc
;
if
(
!
imap
->
io
)
return
0
;
rc
=
mu_imapio_trace_enable
(
imap
->
io
);
switch
(
rc
)
{
case
0
:
case
MU_ERR_OPEN
:
MU_IMAP_FSET
(
imap
,
MU_IMAP_TRACE
);
return
0
;
}
rc
=
mu_dbgstream_create
(
&
dstr
,
MU_DIAG_DEBUG
);
if
(
rc
)
mu_error
(
_
(
"cannot create debug stream; transcript disabled: %s"
),
mu_strerror
(
rc
));
else
{
rc
=
mu_xscript_stream_create
(
&
xstr
,
imap
->
carrier
,
dstr
,
imap_prefix
);
if
(
rc
)
mu_error
(
_
(
"cannot create transcript stream: %s"
),
mu_strerror
(
rc
));
else
{
mu_stream_unref
(
imap
->
carrier
);
imap
->
carrier
=
xstr
;
MU_IMAP_FSET
(
imap
,
MU_IMAP_TRACE
);
}
break
;
}
return
rc
;
}
int
_mu_imap_trace_disable
(
mu_imap_t
imap
)
{
mu_stream_t
xstr
=
imap
->
carrier
;
mu_stream_t
stream
[
2
];
int
rc
;
if
(
!
xstr
)
if
(
!
imap
->
io
)
return
0
;
rc
=
mu_stream_ioctl
(
xstr
,
MU_IOCTL_TRANSPORT
,
MU_IOCTL_OP_GET
,
stream
);
if
(
rc
)
return
rc
;
rc
=
mu_imapio_trace_disable
(
imap
->
io
);
switch
(
rc
)
{
case
0
:
case
MU_ERR_NOT_OPEN
:
MU_IMAP_FCLR
(
imap
,
MU_IMAP_TRACE
);
break
;
}
return
rc
;
imap
->
carrier
=
stream
[
0
];
mu_stream_destroy
(
&
xstr
);
MU_IMAP_FCLR
(
imap
,
MU_IMAP_TRACE
);
return
0
;
}
int
mu_imap_trace
(
mu_imap_t
imap
,
int
op
)
{
int
trace_on
=
MU_IMAP_FISSET
(
imap
,
MU_IMAP_TRACE
);
int
trace_on
=
mu_imapio_get_trace
(
imap
->
io
);
switch
(
op
)
{
case
MU_IMAP_TRACE_SET
:
...
...
@@ -117,15 +89,15 @@ mu_imap_trace_mask (mu_imap_t imap, int op, int lev)
switch
(
op
)
{
case
MU_IMAP_TRACE_SET
:
imap
->
flags
|=
MU_IMAP_XSCRIPT_MASK
(
lev
);
imap
->
flags
|=
MU_IMAP_XSCRIPT_MASK
(
lev
);
break
;
case
MU_IMAP_TRACE_CLR
:
imap
->
flags
&=
~
MU_IMAP_XSCRIPT_MASK
(
lev
);
imap
->
flags
&=
~
MU_IMAP_XSCRIPT_MASK
(
lev
);
break
;
case
MU_IMAP_TRACE_QRY
:
if
(
imap
->
flags
&
MU_IMAP_XSCRIPT_MASK
(
lev
))
if
(
imap
->
flags
&
MU_IMAP_XSCRIPT_MASK
(
lev
))
break
;
return
MU_ERR_NOENT
;
...
...
@@ -138,8 +110,5 @@ mu_imap_trace_mask (mu_imap_t imap, int op, int lev)
int
_mu_imap_xscript_level
(
mu_imap_t
imap
,
int
xlev
)
{
if
(
mu_stream_ioctl
(
imap
->
carrier
,
MU_IOCTL_XSCRIPTSTREAM
,
MU_IOCTL_XSCRIPTSTREAM_LEVEL
,
&
xlev
)
==
0
)
return
xlev
;
return
MU_XSCRIPT_NORMAL
;
return
mu_imapio_set_xscript_level
(
imap
->
io
,
xlev
);
}
...
...
mu/imap.c
View file @
f7942ce
...
...
@@ -364,6 +364,12 @@ com_login (int argc, char **argv)
int
status
;
char
*
pwd
,
*
passbuf
=
NULL
;
if
(
!
imap
)
{
mu_error
(
_
(
"you need to connect first"
));
return
0
;
}
if
(
argc
==
2
)
{
if
(
!
mutool_shell_interactive
)
...
...
@@ -395,22 +401,13 @@ com_login (int argc, char **argv)
return
0
;
}
static
int
_print_id
(
void
*
item
,
void
*
data
)
{
const
char
*
id
=
item
;
mu_printf
(
"ID: %s %s
\n
"
,
id
,
id
+
strlen
(
id
)
+
1
);
return
0
;
}
static
int
com_id
(
int
argc
,
char
**
argv
)
{
mu_
list_t
list
;
mu_
assoc_t
assoc
;
char
*
test
=
NULL
;
int
status
;
argv
++
;
if
(
argv
[
0
]
&&
strcmp
(
argv
[
0
],
"-test"
)
==
0
)
{
...
...
@@ -424,31 +421,36 @@ com_id (int argc, char **argv)
argv
++
;
}
status
=
mu_imap_id
(
imap
,
argv
+
1
,
&
list
);
status
=
mu_imap_id
(
imap
,
argv
+
1
,
&
assoc
);
if
(
status
==
0
)
{
if
(
test
)
{
const
char
*
res
;
int
rc
=
mu_list_locate
(
list
,
test
,
(
void
*
)
&
res
);
switch
(
rc
)
void
*
res
=
mu_assoc_ref
(
assoc
,
test
);
if
(
res
)
{
case
0
:
mu_printf
(
"%s: %s
\n
"
,
test
,
res
+
strlen
(
res
)
+
1
);
break
;
case
MU_ERR_NOENT
:
mu_printf
(
"%s is not set
\n
"
,
test
);
break
;
default:
return
rc
;
mu_printf
(
"%s: %s
\n
"
,
test
,
*
(
char
**
)
res
);
}
else
mu_printf
(
"%s is not set
\n
"
,
test
);
}
else
mu_list_do
(
list
,
_print_id
,
NULL
);
mu_list_destroy
(
&
list
);
{
mu_iterator_t
itr
;
mu_assoc_get_iterator
(
assoc
,
&
itr
);
for
(
mu_iterator_first
(
itr
);
!
mu_iterator_is_done
(
itr
);
mu_iterator_next
(
itr
))
{
char
*
key
;
void
*
val
;
mu_iterator_current_kv
(
itr
,
(
const
void
**
)
&
key
,
&
val
);
mu_printf
(
"ID: %s %s
\n
"
,
key
,
*
(
char
**
)
val
);
}
mu_iterator_destroy
(
&
itr
);
}
mu_assoc_destroy
(
&
assoc
);
}
return
status
;
}
...
...
Please
register
or
sign in
to post a comment