Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117886085
imapd.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
51 KB
Referenced Files
None
Subscribers
None
imapd.c
View Options
/*
* IMAP server protocol parsing
*/
#include
<stdio.h>
#include
<string.h>
#include
<time.h>
#include
<sysexits.h>
#include
<signal.h>
#include
<sys/types.h>
#include
<sys/param.h>
#include
<sys/stat.h>
#include
<syslog.h>
#include
<com_err.h>
#include
<netdb.h>
#include
<sys/socket.h>
#include
<netinet/in.h>
#include
"acl.h"
#include
"util.h"
#include
"auth.h"
#include
"imap_err.h"
#include
"mailbox.h"
#include
"imapd.h"
#include
"xmalloc.h"
extern
int
optind
;
extern
char
*
optarg
;
extern
int
errno
;
struct
buf
{
char
*
s
;
int
alloc
;
};
char
*
imapd_userid
;
int
imapd_userisadmin
;
struct
mailbox
*
imapd_mailbox
;
int
imapd_exists
;
char
imapd_clienthost
[
250
]
=
"[local]"
;
static
struct
mailbox
mboxstruct
;
static
struct
fetchargs
zerofetchargs
;
static
char
*
monthname
[]
=
{
"jan"
,
"feb"
,
"mar"
,
"apr"
,
"may"
,
"jun"
,
"jul"
,
"aug"
,
"sep"
,
"oct"
,
"nov"
,
"dec"
};
main
(
argc
,
argv
)
{
char
hostname
[
MAXHOSTNAMELEN
+
1
];
struct
sockaddr_in
sa
;
int
salen
=
sizeof
(
sa
);
struct
hostent
*
hp
;
config_init
(
"imapd"
);
signal
(
SIGPIPE
,
SIG_IGN
);
gethostname
(
hostname
,
sizeof
(
hostname
));
/* Find out name of client host */
if
(
getpeername
(
0
,
&
sa
,
&
salen
)
==
0
&&
sa
.
sin_family
==
AF_INET
)
{
if
(
hp
=
gethostbyaddr
((
char
*
)
&
sa
.
sin_addr
,
sizeof
(
sa
.
sin_addr
),
AF_INET
))
{
if
(
strlen
(
hp
->
h_name
)
+
30
>
sizeof
(
imapd_clienthost
))
{
hp
->
h_name
[
sizeof
(
imapd_clienthost
)
-30
]
=
'\0'
;
}
strcpy
(
imapd_clienthost
,
hp
->
h_name
);
}
else
{
imapd_clienthost
[
0
]
=
'\0'
;
}
strcat
(
imapd_clienthost
,
"["
);
strcat
(
imapd_clienthost
,
inet_ntoa
(
sa
.
sin_addr
));
strcat
(
imapd_clienthost
,
"]"
);
}
printf
(
"* OK %s Cyrus IMAP2bis v0.2-ALPHA server ready
\r\n
"
,
hostname
);
cmdloop
();
}
usage
()
{
printf
(
"* BYE usage: imapd
\r\n
"
);
exit
(
EX_USAGE
);
}
/*
* Cleanly shut down and exit
*/
shutdown
(
code
)
int
code
;
{
if
(
imapd_mailbox
)
{
index_checkseen
(
imapd_mailbox
,
1
,
0
,
imapd_exists
);
mailbox_close
(
imapd_mailbox
);
}
exit
(
code
);
}
fatal
(
s
,
code
)
char
*
s
;
int
code
;
{
static
int
recurse_code
=
0
;
if
(
recurse_code
)
{
/* We were called recursively. Just give up */
exit
(
recurse_code
);
}
recurse_code
=
code
;
printf
(
"* BYE Fatal error: %s
\r\n
"
,
s
);
shutdown
(
code
);
}
/*
* Top-level command loop parsing
*/
cmdloop
()
{
int
c
;
int
usinguid
,
havepartition
;
static
struct
buf
tag
,
cmd
,
arg1
,
arg2
,
arg3
,
arg4
;
char
*
p
;
for
(;;)
{
fflush
(
stdout
);
/* Parse tag */
c
=
getword
(
&
tag
);
if
(
c
==
EOF
)
{
shutdown
(
0
);
}
if
(
c
!=
' '
||
!
isatom
(
tag
.
s
)
||
(
tag
.
s
[
0
]
==
'*'
&&
!
tag
.
s
[
1
]))
{
printf
(
"* BAD Invalid tag
\r\n
"
);
if
(
c
!=
'\n'
)
eatline
();
continue
;
}
/* Parse command name */
c
=
getword
(
&
cmd
);
if
(
!
cmd
.
s
[
0
])
{
printf
(
"%s BAD Null command
\r\n
"
,
tag
.
s
);
if
(
c
!=
'\n'
)
eatline
();
continue
;
}
if
(
islower
(
cmd
.
s
[
0
]))
cmd
.
s
[
0
]
=
toupper
(
cmd
.
s
[
0
]);
for
(
p
=
&
cmd
.
s
[
1
];
*
p
;
p
++
)
{
if
(
isupper
(
*
p
))
*
p
=
tolower
(
*
p
);
}
/* Only Login/Logout/Noop allowed when not logged in */
if
(
!
imapd_userid
&&
cmd
.
s
[
0
]
!=
'L'
&&
cmd
.
s
[
0
]
!=
'N'
)
goto
nologin
;
switch
(
cmd
.
s
[
0
])
{
case
'A'
:
if
(
!
strcmp
(
cmd
.
s
,
"Append"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
cmd_append
(
tag
.
s
,
arg1
.
s
);
}
else
goto
badcmd
;
break
;
case
'B'
:
if
(
!
strcmp
(
cmd
.
s
,
"Bboard"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg1
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_select
(
tag
.
s
,
cmd
.
s
,
arg1
.
s
);
}
else
goto
badcmd
;
break
;
case
'C'
:
if
(
!
strcmp
(
cmd
.
s
,
"Check"
))
{
if
(
!
imapd_mailbox
)
goto
nomailbox
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_noop
(
tag
.
s
,
cmd
.
s
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Copy"
))
{
if
(
!
imapd_mailbox
)
goto
nomailbox
;
usinguid
=
0
;
if
(
c
!=
' '
)
goto
missingargs
;
copy
:
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
||
!
issequence
(
arg1
.
s
))
goto
badsequence
;
c
=
getastring
(
&
arg2
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_copy
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
,
usinguid
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Create"
))
{
havepartition
=
0
;
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg1
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
' '
)
{
havepartition
=
1
;
c
=
getword
(
&
arg2
);
if
(
!
isatom
(
arg2
.
s
))
goto
badpartition
;
}
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_create
(
tag
.
s
,
arg1
.
s
,
havepartition
?
arg2
.
s
:
0
);
}
else
goto
badcmd
;
break
;
case
'D'
:
if
(
!
strcmp
(
cmd
.
s
,
"Deleteacl"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg2
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg3
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_setacl
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
,
arg3
.
s
,
(
char
*
)
0
);
}
else
goto
badcmd
;
break
;
case
'E'
:
if
(
!
strcmp
(
cmd
.
s
,
"Expunge"
))
{
if
(
!
imapd_mailbox
)
goto
nomailbox
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_expunge
(
tag
.
s
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Examine"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg1
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_select
(
tag
.
s
,
cmd
.
s
,
arg1
.
s
);
}
else
goto
badcmd
;
break
;
case
'F'
:
if
(
!
strcmp
(
cmd
.
s
,
"Fetch"
))
{
if
(
!
imapd_mailbox
)
goto
nomailbox
;
usinguid
=
0
;
if
(
c
!=
' '
)
goto
missingargs
;
fetch
:
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
||
!
issequence
(
arg1
.
s
))
goto
badsequence
;
cmd_fetch
(
tag
.
s
,
arg1
.
s
,
usinguid
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Find"
))
{
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg2
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_find
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
);
}
else
goto
badcmd
;
break
;
case
'G'
:
if
(
!
strcmp
(
cmd
.
s
,
"Getacl"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg2
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_getacl
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
);
}
else
goto
badcmd
;
break
;
case
'L'
:
if
(
!
strcmp
(
cmd
.
s
,
"Login"
))
{
if
(
c
!=
' '
||
(
c
=
getastring
(
&
arg1
))
!=
' '
)
{
goto
missingargs
;
}
c
=
getastring
(
&
arg2
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
if
(
imapd_userid
)
{
printf
(
"%s NO Already logged in
\r\n
"
,
tag
.
s
);
continue
;
}
cmd_login
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Logout"
))
{
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
printf
(
"* BYE Server terminating connection
\r\n
"
);
printf
(
"%s OK Logout completed
\r\n
"
,
tag
.
s
);
shutdown
(
0
);
}
else
if
(
!
imapd_userid
)
goto
nologin
;
else
goto
badcmd
;
break
;
case
'M'
:
if
(
!
strcmp
(
cmd
.
s
,
"Myrights"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg2
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_myrights
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
);
}
else
goto
badcmd
;
break
;
case
'N'
:
if
(
!
strcmp
(
cmd
.
s
,
"Noop"
))
{
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_noop
(
tag
.
s
,
cmd
.
s
);
}
else
if
(
!
imapd_userid
)
goto
nologin
;
else
goto
badcmd
;
break
;
case
'P'
:
if
(
!
strcmp
(
cmd
.
s
,
"Partial"
))
{
if
(
!
imapd_mailbox
)
goto
nomailbox
;
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg2
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg3
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg4
);
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_partial
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
,
arg3
.
s
,
arg4
.
s
);
}
else
goto
badcmd
;
break
;
case
'S'
:
if
(
!
strcmp
(
cmd
.
s
,
"Store"
))
{
if
(
!
imapd_mailbox
)
goto
nomailbox
;
usinguid
=
0
;
if
(
c
!=
' '
)
goto
missingargs
;
store
:
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
||
!
issequence
(
arg1
.
s
))
goto
badsequence
;
c
=
getword
(
&
arg2
);
if
(
c
!=
' '
)
goto
badsequence
;
cmd_store
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
,
usinguid
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Select"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg1
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_select
(
tag
.
s
,
cmd
.
s
,
arg1
.
s
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Search"
))
{
if
(
!
imapd_mailbox
)
goto
nomailbox
;
usinguid
=
0
;
if
(
c
!=
' '
)
goto
missingargs
;
search
:
cmd_search
(
tag
.
s
,
usinguid
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Subscribe"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg2
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_changesub
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
,
1
);
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Setacl"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg2
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg3
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg4
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_setacl
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
,
arg3
.
s
,
arg4
.
s
);
}
else
goto
badcmd
;
break
;
case
'U'
:
if
(
!
strcmp
(
cmd
.
s
,
"Uid"
))
{
if
(
!
imapd_mailbox
)
goto
nomailbox
;
usinguid
=
1
;
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
lcase
(
arg1
.
s
);
if
(
!
strcmp
(
arg1
.
s
,
"fetch"
))
{
goto
fetch
;
}
else
if
(
!
strcmp
(
arg1
.
s
,
"store"
))
{
goto
store
;
}
else
if
(
!
strcmp
(
arg1
.
s
,
"search"
))
{
goto
search
;
}
else
if
(
!
strcmp
(
arg1
.
s
,
"copy"
))
{
goto
copy
;
}
else
{
printf
(
"%s BAD Unrecognized UID subcommand
\r\n
"
,
tag
.
s
);
if
(
c
!=
'\n'
)
eatline
();
}
}
else
if
(
!
strcmp
(
cmd
.
s
,
"Unsubscribe"
))
{
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getword
(
&
arg1
);
if
(
c
!=
' '
)
goto
missingargs
;
c
=
getastring
(
&
arg2
);
if
(
c
==
EOF
)
goto
missingargs
;
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
goto
extraargs
;
cmd_changesub
(
tag
.
s
,
arg1
.
s
,
arg2
.
s
,
0
);
}
else
goto
badcmd
;
break
;
default
:
badcmd
:
printf
(
"%s BAD Unrecognized command
\r\n
"
,
tag
.
s
);
if
(
c
!=
'\n'
)
eatline
();
}
continue
;
nologin
:
printf
(
"%s BAD Please login first
\r\n
"
,
tag
.
s
);
if
(
c
!=
'\n'
)
eatline
();
continue
;
nomailbox
:
printf
(
"%s BAD Please select a mailbox first
\r\n
"
,
tag
.
s
);
if
(
c
!=
'\n'
)
eatline
();
continue
;
missingargs
:
printf
(
"%s BAD Missing required argument to %s
\r\n
"
,
tag
.
s
,
cmd
.
s
);
if
(
c
!=
'\n'
)
eatline
();
continue
;
extraargs
:
printf
(
"%s BAD Unexpected extra arguments to %s
\r\n
"
,
tag
.
s
,
cmd
.
s
);
if
(
c
!=
'\n'
)
eatline
();
continue
;
badsequence
:
printf
(
"%s BAD Invalid sequence in %s
\r\n
"
,
tag
.
s
,
cmd
.
s
);
if
(
c
!=
'\n'
)
eatline
();
continue
;
badpartition
:
printf
(
"%s BAD Invalid partition name in %s
\r\n
"
,
tag
.
s
,
cmd
.
s
);
if
(
c
!=
'\n'
)
eatline
();
continue
;
}
}
/*
* Perform a LOGIN command
*/
cmd_login
(
tag
,
user
,
passwd
)
char
*
tag
;
char
*
user
;
char
*
passwd
;
{
char
*
canon_user
;
char
*
reply
=
0
;
canon_user
=
auth_canonifyid
(
user
);
if
(
!
canon_user
)
{
syslog
(
LOG_NOTICE
,
"badlogin: %s bad userid %s"
,
imapd_clienthost
,
beautify_string
(
user
));
printf
(
"%s NO Invalid user %s
\r\n
"
,
tag
,
beautify_string
(
user
));
return
;
}
if
(
!
strcmp
(
canon_user
,
"anonymous"
))
{
if
(
config_getswitch
(
"allowanonymouslogin"
,
0
))
{
passwd
=
beautify_string
(
passwd
);
if
(
strlen
(
passwd
)
>
500
)
passwd
[
500
]
=
'\0'
;
syslog
(
LOG_NOTICE
,
"login: %s anonymous %s"
,
imapd_clienthost
,
passwd
);
reply
=
"Anonymous access granted"
;
}
else
{
syslog
(
LOG_NOTICE
,
"badlogin: %s anonymous login refused"
,
imapd_clienthost
);
printf
(
"%s NO Anonymous login not permitted
\r\n
"
,
tag
);
return
;
}
}
else
if
(
login_authenticate
(
canon_user
,
passwd
,
&
reply
)
!=
0
)
{
if
(
!
reply
)
reply
=
"Login incorrect"
;
printf
(
"%s NO %s
\r\n
"
,
tag
,
reply
);
return
;
}
auth_setid
(
canon_user
);
imapd_userid
=
strsave
(
canon_user
);
if
(
!
reply
)
reply
=
"User logged in"
;
printf
(
"%s OK %s
\r\n
"
,
tag
,
reply
);
return
;
};
/*
* Perform a NOOP command
*/
cmd_noop
(
tag
,
cmd
)
char
*
tag
;
char
*
cmd
;
{
if
(
imapd_mailbox
)
{
index_check
(
imapd_mailbox
,
0
,
1
);
}
printf
(
"%s OK %s completed
\r\n
"
,
tag
,
cmd
);
};
/*
* Parse and perform an APPEND command.
* The command has been parsed up to and including
* the mailbox name.
*/
#define FLAGGROW 10
cmd_append
(
tag
,
name
)
char
*
tag
;
char
*
name
;
{
int
c
;
char
**
flag
=
0
;
int
nflags
=
0
,
flagalloc
=
0
;
static
struct
buf
arg
;
char
*
p
;
time_t
internaldate
=
time
(
0
);
unsigned
size
=
0
;
int
r
;
char
inboxname
[
MAX_MAILBOX_PATH
];
struct
mailbox
mailbox
;
/* Parse flags */
for
(
c
=
getword
(
&
arg
);
c
==
' '
&&
arg
.
s
[
0
]
!=
'{'
;
c
=
getword
(
&
arg
))
{
if
(
arg
.
s
[
0
]
==
'\\'
)
{
lcase
(
arg
.
s
);
if
(
!
strcmp
(
arg
.
s
,
"
\\
seen"
)
&&
!
strcmp
(
arg
.
s
,
"
\\
answered"
)
&&
!
strcmp
(
arg
.
s
,
"
\\
flagged"
)
&&
!
strcmp
(
arg
.
s
,
"
\\
deleted"
))
{
printf
(
"%s BAD Invalid system flag in Append command
\r\n
"
,
tag
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeflags
;
}
}
else
if
(
!
isatom
(
arg
.
s
))
{
printf
(
"%s BAD Invalid flag name %s in Append command
\r\n
"
,
tag
,
arg
.
s
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeflags
;
}
if
(
nflags
==
flagalloc
)
{
flagalloc
+=
FLAGGROW
;
flag
=
(
char
**
)
xrealloc
((
char
*
)
flag
,
flagalloc
*
sizeof
(
char
*
));
}
flag
[
nflags
++
]
=
strsave
(
arg
.
s
);
}
/* Parse internaldate */
if
(
c
==
'\"'
)
{
ungetc
(
c
,
stdin
);
c
=
getdatetime
(
&
internaldate
);
if
(
c
!=
' '
)
{
printf
(
"%s BAD Invalid date-time in Append command
\r\n
"
,
tag
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeflags
;
}
c
=
getword
(
&
arg
);
if
(
arg
.
s
[
0
]
!=
'{'
)
{
printf
(
"%s BAD Missing required argument to Append command
\r\n
"
,
tag
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeflags
;
}
}
else
if
(
c
!=
' '
)
{
printf
(
"%s BAD Missing required argument to Append command
\r\n
"
,
tag
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeflags
;
}
/* Read size from literal */
for
(
p
=
arg
.
s
+
1
;
*
p
&&
isdigit
(
*
p
);
p
++
)
{
size
=
size
*
10
+
*
p
-
'0'
;
}
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
*
p
!=
'}'
||
p
[
1
]
||
c
!=
'\n'
||
size
<
2
)
{
printf
(
"%s BAD Invalid literal in Append command
\r\n
"
,
tag
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeflags
;
}
/* Set up the append */
if
(
strcasecmp
(
name
,
"inbox"
)
==
0
&&
!
strchr
(
imapd_userid
,
'.'
)
&&
strlen
(
imapd_userid
)
+
6
<=
MAX_MAILBOX_PATH
)
{
strcpy
(
inboxname
,
"user."
);
strcat
(
inboxname
,
imapd_userid
);
r
=
append_setup
(
&
mailbox
,
inboxname
,
MAILBOX_FORMAT_NORMAL
,
ACL_INSERT
,
size
);
}
else
{
r
=
append_setup
(
&
mailbox
,
name
,
MAILBOX_FORMAT_NORMAL
,
ACL_INSERT
,
size
);
}
if
(
r
)
{
printf
(
"%s NO %sAppend to %s failed: %s
\r\n
"
,
tag
,
r
==
IMAP_MAILBOX_NONEXISTENT
?
"[TRYCREATE] "
:
""
,
beautify_string
(
name
),
error_message
(
r
));
/* XXX check create permissions for [TRYCREATE] */
goto
freeflags
;
}
/* Tell client to send the message */
printf
(
"+ go ahead
\r\n
"
);
fflush
(
stdout
);
/* Perform the rest of the append */
r
=
append_fromstream
(
&
mailbox
,
stdin
,
size
,
internaldate
,
flag
,
nflags
,
imapd_userid
);
mailbox_close
(
&
mailbox
);
if
(
imapd_mailbox
)
{
/*
* We do a full check, to pick up any \Seen flag we might have
* set on the appended message.
* XXX full check isn't necessary--test removing it
*/
index_check
(
imapd_mailbox
,
0
,
1
);
}
if
(
r
)
{
printf
(
"%s NO Append to %s failed: %s
\r\n
"
,
tag
,
beautify_string
(
name
),
error_message
(
r
));
}
else
{
printf
(
"%s OK Append completed
\r\n
"
,
tag
);
}
freeflags
:
while
(
nflags
--
)
{
free
(
flag
[
nflags
]);
}
if
(
flag
)
free
((
char
*
)
flag
);
}
/*
* Perform a SELECT/EXAMINE/BBOARD command
*/
cmd_select
(
tag
,
cmd
,
name
)
char
*
tag
;
char
*
cmd
;
char
*
name
;
{
struct
mailbox
mailbox
;
char
inboxname
[
MAX_MAILBOX_PATH
];
int
r
=
0
;
int
i
;
int
usage
;
int
doclose
=
0
;
if
(
cmd
[
0
]
==
'B'
)
{
/* BBoard namespace is empty */
r
=
IMAP_MAILBOX_NONEXISTENT
;
}
else
if
(
strcasecmp
(
name
,
"inbox"
)
==
0
&&
!
strchr
(
imapd_userid
,
'.'
)
&&
strlen
(
imapd_userid
)
+
6
<=
MAX_MAILBOX_PATH
)
{
strcpy
(
inboxname
,
"user."
);
strcat
(
inboxname
,
imapd_userid
);
r
=
mailbox_open_header
(
inboxname
,
&
mailbox
);
}
else
{
r
=
mailbox_open_header
(
name
,
&
mailbox
);
}
if
(
!
r
)
{
doclose
=
1
;
r
=
mailbox_open_index
(
&
mailbox
);
}
if
(
!
r
&&
!
(
mailbox
.
myrights
&
ACL_READ
))
{
r
=
(
mailbox
.
myrights
&
ACL_LOOKUP
)
?
IMAP_PERMISSION_DENIED
:
IMAP_MAILBOX_NONEXISTENT
;
}
if
(
!
r
&&
chdir
(
mailbox
.
path
))
{
r
=
IMAP_IOERROR
;
}
if
(
r
)
{
printf
(
"%s NO %s of %s failed: %s
\r\n
"
,
tag
,
cmd
,
beautify_string
(
name
),
error_message
(
r
));
if
(
doclose
)
mailbox_close
(
&
mailbox
);
return
;
}
if
(
imapd_mailbox
)
{
/* Save \Seen state and close previously open mailbox */
index_checkseen
(
imapd_mailbox
,
1
,
0
,
imapd_exists
);
mailbox_close
(
imapd_mailbox
);
}
mboxstruct
=
mailbox
;
imapd_mailbox
=
&
mboxstruct
;
index_newmailbox
(
imapd_mailbox
);
/* Examine command puts mailbox in read-only mode */
if
(
cmd
[
0
]
==
'E'
)
{
imapd_mailbox
->
myrights
&=
~
(
ACL_SEEN
|
ACL_WRITE
|
ACL_DELETE
);
}
if
(
imapd_mailbox
->
myrights
&
ACL_DELETE
)
{
/* Warn if mailbox is close to or over quota */
mailbox_read_quota
(
imapd_mailbox
);
if
(
imapd_mailbox
->
quota_limit
>
0
)
{
usage
=
imapd_mailbox
->
quota_used
*
100
/
(
imapd_mailbox
->
quota_limit
*
QUOTA_UNITS
);
if
(
usage
>=
100
)
{
printf
(
"* NO Mailbox %s is over quota
\r\n
"
,
name
);
}
else
if
(
usage
>
config_getint
(
"quotawarn"
,
90
))
{
printf
(
"* NO Mailbox %s is at %d%% of quota
\r\n
"
,
name
,
usage
);
}
}
}
printf
(
"%s OK [READ-%s] %s completed
\r\n
"
,
tag
,
imapd_mailbox
->
myrights
&
ACL_WRITE
?
"WRITE"
:
"ONLY"
,
cmd
);
syslog
(
LOG_INFO
,
"open: user %s opened %s"
,
imapd_userid
,
name
);
}
/*
* Parse and perform a FETCH/UID FETCH command
* The command has been parsed up to and including
* the sequence
*/
cmd_fetch
(
tag
,
sequence
,
usinguid
)
char
*
tag
;
char
*
sequence
;
int
usinguid
;
{
char
*
cmd
=
usinguid
?
"UID Fetch"
:
"Fetch"
;
static
struct
buf
fetchatt
,
fieldname
;
int
c
;
int
inlist
=
0
;
int
fetchitems
=
0
;
struct
fetchargs
fetchargs
;
char
*
p
,
*
section
;
fetchargs
=
zerofetchargs
;
c
=
getword
(
&
fetchatt
);
if
(
c
==
'('
&&
!
fetchatt
.
s
[
0
])
{
inlist
=
1
;
c
=
getword
(
&
fetchatt
);
}
for
(;;)
{
lcase
(
fetchatt
.
s
);
switch
(
fetchatt
.
s
[
0
])
{
case
'a'
:
if
(
!
inlist
&&
!
strcmp
(
fetchatt
.
s
,
"all"
))
{
fetchitems
|=
FETCH_ALL
;
}
else
goto
badatt
;
break
;
case
'b'
:
if
(
!
strcmp
(
fetchatt
.
s
,
"body"
))
{
fetchitems
|=
FETCH_BODY
;
}
else
if
(
!
strcmp
(
fetchatt
.
s
,
"bodystructure"
))
{
fetchitems
|=
FETCH_BODYSTRUCTURE
;
}
else
if
(
!
strncmp
(
fetchatt
.
s
,
"body["
,
5
)
||
!
strncmp
(
fetchatt
.
s
,
"body.peek["
,
10
))
{
p
=
section
=
fetchatt
.
s
+
5
;
if
(
*
p
==
'p'
)
{
p
=
section
+=
5
;
}
else
{
fetchitems
|=
FETCH_SETSEEN
;
}
while
(
isdigit
(
*
p
)
||
*
p
==
'.'
)
{
if
(
*
p
==
'.'
&&
(
p
==
section
||
!
isdigit
(
p
[
1
])))
break
;
p
++
;
}
if
(
p
==
section
||
*
p
!=
']'
||
p
[
1
])
{
printf
(
"%s BAD Invalid body section
\r\n
"
,
tag
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
*
p
=
'\0'
;
appendstrlist
(
&
fetchargs
.
bodysections
,
section
);
}
else
goto
badatt
;
break
;
case
'e'
:
if
(
!
strcmp
(
fetchatt
.
s
,
"envelope"
))
{
fetchitems
|=
FETCH_ENVELOPE
;
}
else
goto
badatt
;
break
;
case
'f'
:
if
(
!
inlist
&&
!
strcmp
(
fetchatt
.
s
,
"fast"
))
{
fetchitems
|=
FETCH_FAST
;
}
else
if
(
!
inlist
&&
!
strcmp
(
fetchatt
.
s
,
"full"
))
{
fetchitems
|=
FETCH_FULL
;
}
else
if
(
!
strcmp
(
fetchatt
.
s
,
"flags"
))
{
fetchitems
|=
FETCH_FLAGS
;
}
else
goto
badatt
;
break
;
case
'i'
:
if
(
!
strcmp
(
fetchatt
.
s
,
"internaldate"
))
{
fetchitems
|=
FETCH_INTERNALDATE
;
}
else
goto
badatt
;
break
;
case
'r'
:
if
(
!
strcmp
(
fetchatt
.
s
,
"rfc822"
))
{
fetchitems
|=
FETCH_RFC822
|
FETCH_SETSEEN
;
}
else
if
(
!
strcmp
(
fetchatt
.
s
,
"rfc822.header"
))
{
fetchitems
|=
FETCH_HEADER
;
}
else
if
(
!
strcmp
(
fetchatt
.
s
,
"rfc822.peek"
))
{
fetchitems
|=
FETCH_RFC822
;
}
else
if
(
!
strcmp
(
fetchatt
.
s
,
"rfc822.size"
))
{
fetchitems
|=
FETCH_SIZE
;
}
else
if
(
!
strcmp
(
fetchatt
.
s
,
"rfc822.text"
))
{
fetchitems
|=
FETCH_TEXT
|
FETCH_SETSEEN
;
}
else
if
(
!
strcmp
(
fetchatt
.
s
,
"rfc822.text.peek"
))
{
fetchitems
|=
FETCH_TEXT
;
}
else
if
(
!
strcmp
(
fetchatt
.
s
,
"rfc822.header.lines"
)
||
!
strcmp
(
fetchatt
.
s
,
"rfc822.header.lines.not"
))
{
if
(
c
!=
' '
)
{
printf
(
"%s BAD Missing required argument to %s %s
\r\n
"
,
tag
,
cmd
,
fetchatt
.
s
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
c
=
getc
(
stdin
);
if
(
c
!=
'('
)
{
printf
(
"%s BAD Missing required open parenthesis in %s %s
\r\n
"
,
tag
,
cmd
,
fetchatt
.
s
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
do
{
c
=
getastring
(
&
fieldname
);
for
(
p
=
fieldname
.
s
;
*
p
;
p
++
)
{
if
(
*
p
<=
' '
||
*
p
&
0x80
||
*
p
==
':'
)
break
;
}
if
(
*
p
||
!*
fieldname
.
s
)
{
printf
(
"%s BAD Invalid field-name in %s %s
\r\n
"
,
tag
,
cmd
,
fetchatt
.
s
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
appendstrlist
(
strlen
(
fetchatt
.
s
)
==
19
?
&
fetchargs
.
headers
:
&
fetchargs
.
headers_not
,
fieldname
.
s
);
}
while
(
c
==
' '
);
if
(
c
!=
')'
)
{
printf
(
"%s BAD Missing required close parenthesis in %s %s
\r\n
"
,
tag
,
cmd
,
fetchatt
.
s
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
c
=
getc
(
stdin
);
}
else
goto
badatt
;
break
;
case
'u'
:
if
(
!
strcmp
(
fetchatt
.
s
,
"uid"
))
{
fetchitems
|=
FETCH_UID
;
}
else
goto
badatt
;
break
;
default
:
badatt
:
printf
(
"%s BAD Invalid %s attribute %s
\r\n
"
,
tag
,
cmd
,
fetchatt
.
s
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
if
(
inlist
&&
c
==
' '
)
c
=
getword
(
&
fetchatt
);
else
break
;
}
if
(
inlist
&&
c
==
')'
)
{
inlist
=
0
;
c
=
getc
(
stdin
);
}
if
(
inlist
)
{
printf
(
"%s BAD Missing close parenthesis in %s
\r\n
"
,
tag
,
cmd
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
{
printf
(
"%s BAD Unexpected extra arguments to %s
\r\n
"
,
tag
,
cmd
);
eatline
();
goto
freeargs
;
}
if
(
!
fetchitems
&&
!
fetchargs
.
bodysections
&&
!
fetchargs
.
headers
&&
!
fetchargs
.
headers_not
)
{
printf
(
"%s BAD Missing required argument to %s
\r\n
"
,
tag
,
cmd
);
goto
freeargs
;
}
if
(
usinguid
)
{
fetchitems
|=
FETCH_UID
;
index_check
(
imapd_mailbox
,
1
,
0
);
}
fetchargs
.
fetchitems
=
fetchitems
;
index_fetch
(
imapd_mailbox
,
sequence
,
usinguid
,
&
fetchargs
);
printf
(
"%s OK %s completed
\r\n
"
,
tag
,
cmd
);
freeargs
:
freestrlist
(
fetchargs
.
bodysections
);
freestrlist
(
fetchargs
.
headers
);
freestrlist
(
fetchargs
.
headers_not
);
}
/*
* Perform a PARTIAL command
*/
cmd_partial
(
tag
,
msgno
,
data
,
start
,
count
)
char
*
tag
;
char
*
msgno
;
char
*
data
;
char
*
start
;
char
*
count
;
{
char
*
p
;
struct
fetchargs
fetchargs
;
int
r
;
char
*
section
;
fetchargs
=
zerofetchargs
;
for
(
p
=
msgno
;
*
p
;
p
++
)
{
if
(
!
isdigit
(
*
p
))
break
;
}
if
(
*
p
||
!*
msgno
)
{
printf
(
"%s BAD Invalid message number
\r\n
"
,
tag
);
return
;
}
lcase
(
data
);
if
(
!
strcmp
(
data
,
"rfc822"
))
{
fetchargs
.
fetchitems
=
FETCH_RFC822
|
FETCH_SETSEEN
;
}
else
if
(
!
strcmp
(
data
,
"rfc822.header"
))
{
fetchargs
.
fetchitems
=
FETCH_HEADER
;
}
else
if
(
!
strcmp
(
data
,
"rfc822.peek"
))
{
fetchargs
.
fetchitems
=
FETCH_RFC822
;
}
else
if
(
!
strcmp
(
data
,
"rfc822.text"
))
{
fetchargs
.
fetchitems
=
FETCH_TEXT
|
FETCH_SETSEEN
;
}
else
if
(
!
strcmp
(
data
,
"rfc822.text.peek"
))
{
fetchargs
.
fetchitems
=
FETCH_TEXT
;
}
else
if
(
!
strncmp
(
data
,
"body["
,
5
)
||
!
strncmp
(
data
,
"body.peek["
,
10
))
{
p
=
section
=
data
+
5
;
if
(
*
p
==
'p'
)
{
p
=
section
+=
5
;
}
else
{
fetchargs
.
fetchitems
=
FETCH_SETSEEN
;
}
while
(
isdigit
(
*
p
)
||
*
p
==
'.'
)
{
if
(
*
p
==
'.'
&&
(
p
==
section
||
!
isdigit
(
p
[
1
])))
break
;
p
++
;
}
if
(
p
==
section
||
*
p
!=
']'
||
p
[
1
])
{
printf
(
"%s BAD Invalid body section
\r\n
"
,
tag
);
freestrlist
(
fetchargs
.
bodysections
);
return
;
}
*
p
=
'\0'
;
appendstrlist
(
&
fetchargs
.
bodysections
,
section
);
}
else
{
printf
(
"%s BAD Invalid Partial item
\r\n
"
,
tag
);
freestrlist
(
fetchargs
.
bodysections
);
return
;
}
for
(
p
=
start
;
*
p
;
p
++
)
{
if
(
!
isdigit
(
*
p
))
break
;
fetchargs
.
start_octet
=
fetchargs
.
start_octet
*
10
+
*
p
-
'0'
;
}
if
(
*
p
||
!
fetchargs
.
start_octet
)
{
printf
(
"%s BAD Invalid starting octet
\r\n
"
,
tag
);
freestrlist
(
fetchargs
.
bodysections
);
return
;
}
for
(
p
=
count
;
*
p
;
p
++
)
{
if
(
!
isdigit
(
*
p
))
break
;
fetchargs
.
octet_count
=
fetchargs
.
octet_count
*
10
+
*
p
-
'0'
;
}
if
(
*
p
||
!*
count
)
{
printf
(
"%s BAD Invalid octet count
\r\n
"
,
tag
);
freestrlist
(
fetchargs
.
bodysections
);
return
;
}
index_fetch
(
imapd_mailbox
,
msgno
,
0
,
&
fetchargs
);
index_check
(
imapd_mailbox
,
0
,
0
);
printf
(
"%s OK Partial completed
\r\n
"
,
tag
);
freestrlist
(
fetchargs
.
bodysections
);
}
/*
* Parse and perform a STORE/UID STORE command
* The command has been parsed up to and including
* the FLAGS/+FLAGS/-FLAGS
*/
cmd_store
(
tag
,
sequence
,
operation
,
usinguid
)
char
*
tag
;
char
*
sequence
;
char
*
operation
;
int
usinguid
;
{
char
*
cmd
=
usinguid
?
"UID Store"
:
"Store"
;
struct
storeargs
storeargs
;
static
struct
storeargs
zerostoreargs
;
static
struct
buf
flagname
;
int
c
;
char
**
flag
=
0
;
int
nflags
=
0
,
flagalloc
=
0
;
int
flagsparsed
=
0
,
inlist
=
0
;
int
r
;
storeargs
=
zerostoreargs
;
lcase
(
operation
);
if
(
!
strcmp
(
operation
,
"+flags"
))
{
storeargs
.
operation
=
STORE_ADD
;
}
else
if
(
!
strcmp
(
operation
,
"-flags"
))
{
storeargs
.
operation
=
STORE_REMOVE
;
}
else
if
(
!
strcmp
(
operation
,
"flags"
))
{
storeargs
.
operation
=
STORE_REPLACE
;
}
else
{
printf
(
"%s BAD Invalid %s attribute
\r\n
"
,
tag
,
cmd
);
eatline
();
return
;
}
for
(;;)
{
c
=
getword
(
&
flagname
);
if
(
c
==
'('
&&
!
flagname
.
s
[
0
]
&&
!
flagsparsed
&&
!
inlist
)
{
inlist
=
1
;
continue
;
}
if
(
flagname
.
s
[
0
]
==
'\\'
)
{
lcase
(
flagname
.
s
);
if
(
!
strcmp
(
flagname
.
s
,
"
\\
seen"
))
{
storeargs
.
seen
=
1
;
}
else
if
(
!
strcmp
(
flagname
.
s
,
"
\\
answered"
))
{
storeargs
.
system_flags
|=
FLAG_ANSWERED
;
}
else
if
(
!
strcmp
(
flagname
.
s
,
"
\\
flagged"
))
{
storeargs
.
system_flags
|=
FLAG_FLAGGED
;
}
else
if
(
!
strcmp
(
flagname
.
s
,
"
\\
deleted"
))
{
storeargs
.
system_flags
|=
FLAG_DELETED
;
}
else
{
printf
(
"%s BAD Invalid system flag in %s command
\r\n
"
,
tag
,
cmd
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeflags
;
}
}
else
if
(
!
isatom
(
flagname
.
s
))
{
printf
(
"%s BAD Invalid flag name %s in %s command
\r\n
"
,
tag
,
flagname
.
s
,
cmd
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeflags
;
}
else
{
if
(
nflags
==
flagalloc
)
{
flagalloc
+=
FLAGGROW
;
flag
=
(
char
**
)
xrealloc
((
char
*
)
flag
,
flagalloc
*
sizeof
(
char
*
));
}
flag
[
nflags
++
]
=
strsave
(
flagname
.
s
);
}
flagsparsed
++
;
if
(
c
!=
' '
)
break
;
}
if
(
inlist
&&
c
==
')'
)
{
inlist
=
0
;
c
=
getc
(
stdin
);
}
if
(
inlist
)
{
printf
(
"%s BAD Missing close parenthesis in %s
\r\n
"
,
tag
,
cmd
);
if
(
c
!=
'\n'
)
eatline
();
return
;
}
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
{
printf
(
"%s BAD Unexpected extra arguments to %s
\r\n
"
,
tag
,
cmd
);
eatline
();
return
;
}
if
(
!
flagsparsed
)
{
printf
(
"%s BAD Missing required argument to %s
\r\n
"
,
tag
,
cmd
);
return
;
}
r
=
index_store
(
imapd_mailbox
,
sequence
,
usinguid
,
&
storeargs
,
flag
,
nflags
);
if
(
usinguid
)
{
index_check
(
imapd_mailbox
,
1
,
0
);
}
if
(
r
)
{
printf
(
"%s NO %s failed: %s
\r\n
"
,
tag
,
cmd
,
error_message
(
r
));
}
else
{
printf
(
"%s OK %s completed
\r\n
"
,
tag
,
cmd
);
}
freeflags
:
while
(
nflags
--
)
{
free
(
flag
[
nflags
]);
}
if
(
flag
)
free
((
char
*
)
flag
);
}
cmd_search
(
tag
,
usinguid
)
char
*
tag
;
int
usinguid
;
{
int
c
=
' '
;
static
struct
buf
criteria
,
arg
;
struct
searchargs
searchargs
;
static
struct
searchargs
zerosearchargs
;
int
nothing_found
=
0
;
int
flag
;
time_t
start
,
end
;
searchargs
=
zerosearchargs
;
while
(
c
==
' '
)
{
c
=
getword
(
&
criteria
);
lcase
(
criteria
.
s
);
switch
(
criteria
.
s
[
0
])
{
case
'a'
:
if
(
!
strcmp
(
criteria
.
s
,
"answered"
))
{
searchargs
.
system_flags_set
|=
FLAG_ANSWERED
;
}
else
if
(
!
strcmp
(
criteria
.
s
,
"all"
))
{
break
;
}
else
goto
badcri
;
break
;
case
'b'
:
if
(
!
strcmp
(
criteria
.
s
,
"before"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getdate
(
&
start
,
&
end
);
if
(
c
==
EOF
)
goto
baddate
;
if
(
!
searchargs
.
before
||
searchargs
.
before
>
start
)
{
searchargs
.
before
=
start
;
}
}
else
if
(
!
strcmp
(
criteria
.
s
,
"bcc"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getastring
(
&
arg
);
if
(
c
==
EOF
)
goto
missingarg
;
appendstrlist
(
&
searchargs
.
bcc
,
arg
.
s
);
}
else
if
(
!
strcmp
(
criteria
.
s
,
"body"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getastring
(
&
arg
);
if
(
c
==
EOF
)
goto
missingarg
;
appendstrlist
(
&
searchargs
.
body
,
arg
.
s
);
}
else
goto
badcri
;
break
;
case
'c'
:
if
(
!
strcmp
(
criteria
.
s
,
"cc"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getastring
(
&
arg
);
if
(
c
==
EOF
)
goto
missingarg
;
appendstrlist
(
&
searchargs
.
cc
,
arg
.
s
);
}
else
goto
badcri
;
break
;
case
'd'
:
if
(
!
strcmp
(
criteria
.
s
,
"deleted"
))
{
searchargs
.
system_flags_set
|=
FLAG_DELETED
;
}
else
goto
badcri
;
break
;
case
'f'
:
if
(
!
strcmp
(
criteria
.
s
,
"flagged"
))
{
searchargs
.
system_flags_set
|=
FLAG_FLAGGED
;
}
else
if
(
!
strcmp
(
criteria
.
s
,
"from"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getastring
(
&
arg
);
if
(
c
==
EOF
)
goto
missingarg
;
appendstrlist
(
&
searchargs
.
from
,
arg
.
s
);
}
else
goto
badcri
;
break
;
case
'k'
:
if
(
!
strcmp
(
criteria
.
s
,
"keyword"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getword
(
&
arg
);
if
(
!
isatom
(
arg
.
s
))
goto
badflag
;
lcase
(
arg
.
s
);
for
(
flag
=
0
;
flag
<
MAX_USER_FLAGS
;
flag
++
)
{
if
(
imapd_mailbox
->
flagname
[
flag
]
&&
!
strcmp
(
imapd_mailbox
->
flagname
[
flag
],
arg
.
s
))
break
;
}
if
(
flag
==
MAX_USER_FLAGS
)
{
nothing_found
++
;
break
;
}
searchargs
.
user_flags_set
[
flag
/
32
]
|=
1
<<
(
flag
&
31
);
}
else
goto
badcri
;
break
;
case
'n'
:
if
(
!
strcmp
(
criteria
.
s
,
"new"
))
{
if
(
searchargs
.
seen_state
==
SEARCH_SET
||
searchargs
.
recent_state
==
SEARCH_UNSET
)
nothing_found
++
;
searchargs
.
seen_state
=
SEARCH_UNSET
;
searchargs
.
recent_state
=
SEARCH_SET
;
}
else
goto
badcri
;
break
;
case
'o'
:
if
(
!
strcmp
(
criteria
.
s
,
"old"
))
{
if
(
searchargs
.
recent_state
==
SEARCH_SET
)
nothing_found
++
;
searchargs
.
recent_state
=
SEARCH_UNSET
;
}
else
if
(
!
strcmp
(
criteria
.
s
,
"on"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getdate
(
&
start
,
&
end
);
if
(
c
==
EOF
)
goto
baddate
;
if
(
!
searchargs
.
before
||
searchargs
.
before
>
end
)
{
searchargs
.
before
=
end
;
}
if
(
!
searchargs
.
after
||
searchargs
.
after
<
start
)
{
searchargs
.
after
=
start
;
}
}
else
goto
badcri
;
break
;
case
'r'
:
if
(
!
strcmp
(
criteria
.
s
,
"recent"
))
{
if
(
searchargs
.
recent_state
==
SEARCH_UNSET
)
nothing_found
++
;
searchargs
.
recent_state
=
SEARCH_SET
;
}
else
goto
badcri
;
break
;
case
's'
:
if
(
!
strcmp
(
criteria
.
s
,
"seen"
))
{
if
(
searchargs
.
seen_state
==
SEARCH_UNSET
)
nothing_found
++
;
searchargs
.
seen_state
=
SEARCH_SET
;
}
else
if
(
!
strcmp
(
criteria
.
s
,
"since"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getdate
(
&
start
,
&
end
);
if
(
c
==
EOF
)
goto
baddate
;
if
(
!
searchargs
.
after
||
searchargs
.
after
<
start
)
{
searchargs
.
after
=
start
;
}
}
else
if
(
!
strcmp
(
criteria
.
s
,
"subject"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getastring
(
&
arg
);
if
(
c
==
EOF
)
goto
missingarg
;
appendstrlist
(
&
searchargs
.
subject
,
arg
.
s
);
}
else
goto
badcri
;
break
;
case
't'
:
if
(
!
strcmp
(
criteria
.
s
,
"to"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getastring
(
&
arg
);
if
(
c
==
EOF
)
goto
missingarg
;
appendstrlist
(
&
searchargs
.
to
,
arg
.
s
);
}
else
if
(
!
strcmp
(
criteria
.
s
,
"text"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getastring
(
&
arg
);
if
(
c
==
EOF
)
goto
missingarg
;
appendstrlist
(
&
searchargs
.
text
,
arg
.
s
);
}
else
goto
badcri
;
break
;
case
'u'
:
if
(
!
strcmp
(
criteria
.
s
,
"unseen"
))
{
if
(
searchargs
.
seen_state
==
SEARCH_SET
)
nothing_found
++
;
searchargs
.
seen_state
=
SEARCH_UNSET
;
}
else
if
(
!
strcmp
(
criteria
.
s
,
"unanswered"
))
{
searchargs
.
system_flags_unset
|=
FLAG_ANSWERED
;
}
else
if
(
!
strcmp
(
criteria
.
s
,
"undeleted"
))
{
searchargs
.
system_flags_unset
|=
FLAG_DELETED
;
}
else
if
(
!
strcmp
(
criteria
.
s
,
"unflagged"
))
{
searchargs
.
system_flags_unset
|=
FLAG_FLAGGED
;
}
else
if
(
!
strcmp
(
criteria
.
s
,
"unkeyword"
))
{
if
(
c
!=
' '
)
goto
missingarg
;
c
=
getword
(
&
arg
);
if
(
!
isatom
(
arg
.
s
))
goto
badflag
;
lcase
(
arg
.
s
);
for
(
flag
=
0
;
flag
<
MAX_USER_FLAGS
;
flag
++
)
{
if
(
imapd_mailbox
->
flagname
[
flag
]
&&
!
strcmp
(
imapd_mailbox
->
flagname
[
flag
],
arg
.
s
))
break
;
}
if
(
flag
!=
MAX_USER_FLAGS
)
{
searchargs
.
user_flags_unset
[
flag
/
32
]
|=
1
<<
(
flag
&
31
);
}
}
else
goto
badcri
;
break
;
default
:
badcri
:
printf
(
"%s BAD Invalid Search criteria
\r\n
"
,
tag
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
}
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
{
printf
(
"%s BAD Unexpected extra arguments to Search
\r\n
"
,
tag
);
eatline
();
goto
freeargs
;
}
if
(
nothing_found
)
{
printf
(
"* SEARCH
\r\n
"
);
}
else
{
index_search
(
imapd_mailbox
,
&
searchargs
,
usinguid
);
}
printf
(
"%s OK Search completed
\r\n
"
,
tag
);
freeargs
:
freestrlist
(
searchargs
.
from
);
freestrlist
(
searchargs
.
to
);
freestrlist
(
searchargs
.
cc
);
freestrlist
(
searchargs
.
bcc
);
freestrlist
(
searchargs
.
subject
);
freestrlist
(
searchargs
.
body
);
freestrlist
(
searchargs
.
text
);
return
;
missingarg
:
printf
(
"%s BAD Missing required argument to Search %s
\r\n
"
,
tag
,
criteria
.
s
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
badflag
:
printf
(
"%s BAD Invalid flag name %s in Search command
\r\n
"
,
tag
,
arg
.
s
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
baddate
:
printf
(
"%s BAD Invalid date in Search command
\r\n
"
,
tag
);
if
(
c
!=
'\n'
)
eatline
();
goto
freeargs
;
}
/*
* Perform a COPY/UID COPY command
*/
cmd_copy
(
tag
,
sequence
,
name
,
usinguid
)
char
*
tag
;
char
*
sequence
;
char
*
name
;
int
usinguid
;
{
char
*
cmd
=
usinguid
?
"UID Copy"
:
"Copy"
;
int
r
;
char
inboxname
[
MAX_MAILBOX_PATH
];
if
(
strcasecmp
(
name
,
"inbox"
)
==
0
&&
!
strchr
(
imapd_userid
,
'.'
)
&&
strlen
(
imapd_userid
)
+
6
<=
MAX_MAILBOX_PATH
)
{
strcpy
(
inboxname
,
"user."
);
strcat
(
inboxname
,
imapd_userid
);
r
=
index_copy
(
imapd_mailbox
,
sequence
,
usinguid
,
inboxname
);
}
else
{
r
=
index_copy
(
imapd_mailbox
,
sequence
,
usinguid
,
name
);
}
index_check
(
imapd_mailbox
,
usinguid
,
0
);
if
(
r
)
{
printf
(
"%s NO %s failed: %s
\r\n
"
,
tag
,
cmd
,
error_message
(
r
));
}
else
{
printf
(
"%s OK %s completed
\r\n
"
,
tag
,
cmd
);
}
}
/*
* Perform an EXPUNGE command
*/
cmd_expunge
(
tag
)
char
*
tag
;
{
int
r
;
if
(
!
(
imapd_mailbox
->
myrights
&
ACL_DELETE
))
r
=
IMAP_PERMISSION_DENIED
;
else
{
r
=
mailbox_expunge
(
imapd_mailbox
,
(
int
(
*
)())
0
,
(
char
*
)
0
);
}
index_check
(
imapd_mailbox
,
0
,
0
);
if
(
r
)
{
printf
(
"%s NO Expunge failed: %s
\r\n
"
,
tag
,
error_message
(
r
));
}
else
{
printf
(
"%s OK Expunge completed
\r\n
"
,
tag
);
}
}
/*
* Perform a CREATE command
*/
cmd_create
(
tag
,
name
,
partition
)
char
*
tag
;
char
*
name
;
char
*
partition
;
{
int
r
;
if
(
partition
&&
!
imapd_userisadmin
)
{
printf
(
"%s NO Only administrators may specify partition
\r\n
"
,
tag
);
return
;
}
r
=
mboxlist_createmailbox
(
name
,
MAILBOX_FORMAT_NORMAL
,
partition
,
imapd_userisadmin
,
imapd_userid
);
if
(
r
)
{
printf
(
"%s NO Create failed: %s
\r\n
"
,
tag
,
error_message
(
r
));
}
else
{
printf
(
"%s OK Create completed
\r\n
"
,
tag
);
}
}
/*
* Perform a FIND command
*/
cmd_find
(
tag
,
namespace
,
pattern
)
char
*
tag
;
char
*
namespace
;
char
*
pattern
;
{
lcase
(
namespace
);
if
(
!
strcmp
(
namespace
,
"mailboxes"
))
{
mboxlist_find
(
pattern
,
imapd_userisadmin
,
imapd_userid
);
}
else
if
(
!
strcmp
(
namespace
,
"all.mailboxes"
))
{
mboxlist_findall
(
pattern
,
imapd_userisadmin
,
imapd_userid
);
}
else
if
(
!
strcmp
(
namespace
,
"bboards"
)
||
!
strcmp
(
namespace
,
"all.bboards"
))
{
;
}
else
{
printf
(
"%s BAD Invalid FIND subcommand
\r\n
"
,
tag
);
return
;
}
printf
(
"%s OK Find completed
\r\n
"
,
tag
);
}
/*
* Perform a SUBSCRIBE (add is nonzero) or
* UNSUBSCRIBE (add is zero) command
*/
cmd_changesub
(
tag
,
namespace
,
name
,
add
)
char
*
tag
;
char
*
namespace
;
char
*
name
;
int
add
;
{
int
r
;
lcase
(
namespace
);
if
(
!
strcmp
(
namespace
,
"mailbox"
))
{
r
=
mboxlist_changesub
(
name
,
imapd_userid
,
add
);
}
else
if
(
!
strcmp
(
namespace
,
"bboard"
))
{
r
=
add
?
IMAP_MAILBOX_NONEXISTENT
:
IMAP_MAILBOX_UNSUBSCRIBED
;
}
else
{
printf
(
"%s BAD Invalid %s subcommand
\r\n
"
,
tag
,
add
?
"Subscribe"
:
"Unsubscribe"
);
return
;
}
if
(
r
)
{
printf
(
"%s NO %s failed: %s
\r\n
"
,
tag
,
add
?
"Subscribe"
:
"Unsubscribe"
,
error_message
(
r
));
}
else
{
printf
(
"%s OK %s completed
\r\n
"
,
tag
,
add
?
"Subscribe"
:
"Unsubscribe"
);
}
}
/*
* Perform a GETACL command
*/
cmd_getacl
(
tag
,
namespace
,
name
)
char
*
tag
;
char
*
namespace
;
char
*
name
;
{
char
inboxname
[
MAX_MAILBOX_PATH
];
int
r
,
access
;
char
*
acl
;
char
*
rights
,
*
nextid
;
lcase
(
namespace
);
if
(
!
strcmp
(
namespace
,
"bboard"
))
{
r
=
IMAP_MAILBOX_NONEXISTENT
;
}
else
if
(
!
strcmp
(
namespace
,
"mailbox"
))
{
if
(
strcasecmp
(
name
,
"inbox"
)
==
0
&&
!
strchr
(
imapd_userid
,
'.'
)
&&
strlen
(
imapd_userid
)
+
6
<=
MAX_MAILBOX_PATH
)
{
strcpy
(
inboxname
,
"user."
);
strcat
(
inboxname
,
imapd_userid
);
r
=
mboxlist_lookup
(
inboxname
,
(
char
**
)
0
,
&
acl
);
}
else
{
r
=
mboxlist_lookup
(
name
,
(
char
**
)
0
,
&
acl
);
}
}
else
{
printf
(
"%s BAD Invalid Getacl subcommand
\r\n
"
,
tag
);
return
;
}
if
(
!
r
)
{
access
=
acl_myrights
(
acl
);
if
(
!
(
access
&
(
ACL_READ
|
ACL_ADMIN
)))
{
r
=
(
access
&
ACL_LOOKUP
)
?
IMAP_PERMISSION_DENIED
:
IMAP_MAILBOX_NONEXISTENT
;
}
}
if
(
r
)
{
printf
(
"%s NO Getacl failed: %s
\r\n
"
,
tag
,
error_message
(
r
));
return
;
}
while
(
acl
)
{
rights
=
strchr
(
acl
,
'\t'
);
if
(
!
rights
)
break
;
*
rights
++
=
'\0'
;
nextid
=
strchr
(
rights
,
'\t'
);
if
(
!
nextid
)
break
;
*
nextid
++
=
'\0'
;
printf
(
"* ACL MAILBOX "
);
printastring
(
name
);
printf
(
" "
);
printastring
(
acl
);
printf
(
" "
);
printastring
(
rights
);
printf
(
"
\r\n
"
);
acl
=
nextid
;
}
printf
(
"%s OK Getacl completed
\r\n
"
,
tag
);
}
/*
* Perform a MYRIGHTS command
*/
cmd_myrights
(
tag
,
namespace
,
name
)
char
*
tag
;
char
*
namespace
;
char
*
name
;
{
char
inboxname
[
MAX_MAILBOX_PATH
];
int
r
,
rights
;
char
*
acl
;
char
str
[
ACL_MAXSTR
];
lcase
(
namespace
);
if
(
!
strcmp
(
namespace
,
"bboard"
))
{
r
=
IMAP_MAILBOX_NONEXISTENT
;
}
else
if
(
!
strcmp
(
namespace
,
"mailbox"
))
{
if
(
strcasecmp
(
name
,
"inbox"
)
==
0
&&
!
strchr
(
imapd_userid
,
'.'
)
&&
strlen
(
imapd_userid
)
+
6
<=
MAX_MAILBOX_PATH
)
{
strcpy
(
inboxname
,
"user."
);
strcat
(
inboxname
,
imapd_userid
);
r
=
mboxlist_lookup
(
inboxname
,
(
char
**
)
0
,
&
acl
);
}
else
{
r
=
mboxlist_lookup
(
name
,
(
char
**
)
0
,
&
acl
);
}
}
else
{
printf
(
"%s BAD Invalid Myrights subcommand
\r\n
"
,
tag
);
return
;
}
if
(
!
r
)
{
rights
=
acl_myrights
(
acl
);
/* Add in implicit rights */
if
(
imapd_userisadmin
||
strcasecmp
(
name
,
"inbox"
))
{
rights
|=
ACL_LOOKUP
|
ACL_ADMIN
;
}
if
(
!
strchr
(
imapd_userid
,
'.'
)
&&
!
strncasecmp
(
name
,
"user."
,
5
)
&&
!
strncasecmp
(
name
+
5
,
imapd_userid
,
strlen
(
imapd_userid
))
&&
name
[
5
+
strlen
(
imapd_userid
)]
==
'.'
)
{
rights
|=
ACL_LOOKUP
|
ACL_ADMIN
;
}
if
(
!
rights
)
{
r
=
IMAP_MAILBOX_NONEXISTENT
;
}
}
if
(
r
)
{
printf
(
"%s NO Myrights failed: %s
\r\n
"
,
tag
,
error_message
(
r
));
return
;
}
printf
(
"* MYRIGHTS MAILBOX "
);
printastring
(
name
);
printf
(
" "
);
printastring
(
acl_masktostr
(
rights
,
str
));
printf
(
"
\r\n
%s OK Myrights completed
\r\n
"
,
tag
);
}
/*
* Perform a SETACL command
*/
cmd_setacl
(
tag
,
namespace
,
name
,
identifier
,
rights
)
char
*
tag
;
char
*
namespace
;
char
*
name
;
char
*
identifier
;
char
*
rights
;
{
int
r
;
char
*
cmd
=
rights
?
"Setacl"
:
"Deleteacl"
;
lcase
(
namespace
);
if
(
!
strcmp
(
namespace
,
"bboard"
))
{
r
=
IMAP_MAILBOX_NONEXISTENT
;
}
else
if
(
!
strcmp
(
namespace
,
"mailbox"
))
{
r
=
mboxlist_setacl
(
name
,
identifier
,
rights
,
imapd_userisadmin
,
imapd_userid
);
}
else
{
printf
(
"%s BAD Invalid %s subcommand
\r\n
"
,
tag
,
cmd
);
return
;
}
if
(
r
)
{
printf
(
"%s NO %s failed: %s
\r\n
"
,
tag
,
cmd
,
error_message
(
r
));
return
;
}
printf
(
"%s OK %s completed
\r\n
"
,
tag
,
cmd
);
}
/*
* Parse a word
* (token not containing whitespace, parens, or double quotes)
*/
#define BUFGROWSIZE 100
int
getword
(
buf
)
struct
buf
*
buf
;
{
int
c
;
int
len
=
0
;
if
(
buf
->
alloc
==
0
)
{
buf
->
alloc
=
BUFGROWSIZE
;
buf
->
s
=
xmalloc
(
buf
->
alloc
+
1
);
}
for
(;;)
{
c
=
getc
(
stdin
);
if
(
c
==
EOF
||
isspace
(
c
)
||
c
==
'('
||
c
==
')'
||
c
==
'\"'
)
{
buf
->
s
[
len
]
=
'\0'
;
return
c
;
}
if
(
len
==
buf
->
alloc
)
{
buf
->
alloc
+=
BUFGROWSIZE
;
buf
->
s
=
xrealloc
(
buf
->
s
,
buf
->
alloc
+
1
);
}
buf
->
s
[
len
++
]
=
c
;
}
}
/*
* Parse an astring
* (atom, quoted-string, or literal)
*/
int
getastring
(
buf
)
struct
buf
*
buf
;
{
int
c
;
int
i
,
len
=
0
;
if
(
buf
->
alloc
==
0
)
{
buf
->
alloc
=
BUFGROWSIZE
;
buf
->
s
=
xmalloc
(
buf
->
alloc
+
1
);
}
c
=
getc
(
stdin
);
switch
(
c
)
{
case
EOF
:
case
' '
:
case
'('
:
case
')'
:
case
'\r'
:
case
'\n'
:
/* Invalid starting character */
buf
->
s
[
0
]
=
'\0'
;
if
(
c
!=
EOF
)
ungetc
(
c
,
stdin
);
return
EOF
;
default
:
/*
* Atom -- server is liberal in accepting specials other
* than whitespace, parens, or double quotes
*/
for
(;;)
{
if
(
c
==
EOF
||
isspace
(
c
)
||
c
==
'('
||
c
==
')'
||
c
==
'\"'
)
{
buf
->
s
[
len
]
=
'\0'
;
return
c
;
}
if
(
len
==
buf
->
alloc
)
{
buf
->
alloc
+=
BUFGROWSIZE
;
buf
->
s
=
xrealloc
(
buf
->
s
,
buf
->
alloc
+
1
);
}
buf
->
s
[
len
++
]
=
c
;
c
=
getc
(
stdin
);
}
case
'\"'
:
/*
* Quoted-string. Server is liberal in accepting qspecials
* other than double-quote, CR, and LF.
*/
for
(;;)
{
c
=
getc
(
stdin
);
if
(
c
==
'\"'
)
{
buf
->
s
[
len
]
=
'\0'
;
return
getc
(
stdin
);
}
if
(
c
==
EOF
||
c
==
'\r'
||
c
==
'\n'
)
{
buf
->
s
[
len
]
=
'\0'
;
if
(
c
!=
EOF
)
ungetc
(
c
,
stdin
);
return
EOF
;
}
if
(
len
==
buf
->
alloc
)
{
buf
->
alloc
+=
BUFGROWSIZE
;
buf
->
s
=
xrealloc
(
buf
->
s
,
buf
->
alloc
+
1
);
}
buf
->
s
[
len
++
]
=
c
;
}
case
'{'
:
/* Literal */
buf
->
s
[
0
]
=
'\0'
;
while
((
c
=
getc
(
stdin
))
!=
EOF
&&
isdigit
(
c
))
{
len
=
len
*
10
+
c
-
'0'
;
}
if
(
c
!=
'}'
)
{
if
(
c
!=
EOF
)
ungetc
(
c
,
stdin
);
return
EOF
;
}
if
(
len
==
0
)
return
EOF
;
c
=
getc
(
stdin
);
if
(
c
==
'\r'
)
c
=
getc
(
stdin
);
if
(
c
!=
'\n'
)
{
if
(
c
!=
EOF
)
ungetc
(
c
,
stdin
);
return
EOF
;
}
if
(
len
>=
buf
->
alloc
)
{
buf
->
alloc
=
len
+
1
;
buf
->
s
=
xrealloc
(
buf
->
s
,
buf
->
alloc
+
1
);
}
printf
(
"+ go ahead
\r\n
"
);
fflush
(
stdout
);
for
(
i
=
0
;
i
<
len
;
i
++
)
{
c
=
getc
(
stdin
);
if
(
c
==
EOF
)
{
buf
->
s
[
len
]
=
'\0'
;
return
EOF
;
}
buf
->
s
[
i
]
=
c
;
}
buf
->
s
[
len
]
=
'\0'
;
if
(
strlen
(
buf
->
s
)
!=
len
)
return
EOF
;
/* Disallow imbedded NUL */
return
getc
(
stdin
);
}
}
/*
* Parse a "date", for SEARCH criteria
* The time_t's pointed to by 'start' and 'end' are set to the
* times of the start and end of the parsed date.
*/
int
getdate
(
start
,
end
)
time_t
*
start
,
*
end
;
{
int
c
;
struct
tm
tm
;
static
struct
tm
zerotm
;
int
quoted
=
0
;
char
month
[
4
];
tm
=
zerotm
;
c
=
getc
(
stdin
);
if
(
c
==
'\"'
)
{
quoted
++
;
c
=
getc
(
stdin
);
}
/* Day of month */
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_mday
=
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
isdigit
(
c
))
{
tm
.
tm_mday
=
tm
.
tm_mday
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
}
if
(
c
!=
'-'
)
goto
baddate
;
c
=
getc
(
stdin
);
/* Month name */
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
0
]
=
c
;
c
=
getc
(
stdin
);
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
1
]
=
c
;
c
=
getc
(
stdin
);
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
2
]
=
c
;
c
=
getc
(
stdin
);
month
[
3
]
=
'\0'
;
lcase
(
month
);
for
(
tm
.
tm_mon
=
0
;
tm
.
tm_mon
<
12
;
tm
.
tm_mon
++
)
{
if
(
!
strcmp
(
month
,
monthname
[
tm
.
tm_mon
]))
break
;
}
if
(
tm
.
tm_mon
==
12
)
goto
baddate
;
if
(
c
!=
'-'
)
goto
baddate
;
c
=
getc
(
stdin
);
/* Year */
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
isdigit
(
c
))
{
if
(
tm
.
tm_year
<
19
)
goto
baddate
;
tm
.
tm_year
-=
19
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
}
if
(
quoted
)
{
if
(
c
!=
'\"'
)
goto
baddate
;
c
=
getc
(
stdin
);
}
tm
.
tm_isdst
=
-1
;
*
start
=
mktime
(
&
tm
);
tm
.
tm_sec
=
tm
.
tm_min
=
59
;
tm
.
tm_hour
=
23
;
*
end
=
mktime
(
&
tm
);
return
c
;
baddate
:
ungetc
(
c
,
stdin
);
return
EOF
;
}
/*
* Parse a date_time, for the APPEND command
*/
int
getdatetime
(
date
)
time_t
*
date
;
{
int
c
;
struct
tm
tm
,
*
ltm
;
int
old_format
=
0
;
static
struct
tm
zerotm
;
char
month
[
4
],
zone
[
4
],
*
p
;
int
zone_off
;
tm
=
zerotm
;
c
=
getc
(
stdin
);
if
(
c
!=
'\"'
)
goto
baddate
;
/* Day of month */
c
=
getc
(
stdin
);
if
(
c
==
' '
)
c
=
'0'
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_mday
=
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
isdigit
(
c
))
{
tm
.
tm_mday
=
tm
.
tm_mday
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
}
if
(
c
!=
'-'
)
goto
baddate
;
c
=
getc
(
stdin
);
/* Month name */
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
0
]
=
c
;
c
=
getc
(
stdin
);
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
1
]
=
c
;
c
=
getc
(
stdin
);
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
2
]
=
c
;
c
=
getc
(
stdin
);
month
[
3
]
=
'\0'
;
lcase
(
month
);
for
(
tm
.
tm_mon
=
0
;
tm
.
tm_mon
<
12
;
tm
.
tm_mon
++
)
{
if
(
!
strcmp
(
month
,
monthname
[
tm
.
tm_mon
]))
break
;
}
if
(
tm
.
tm_mon
==
12
)
goto
baddate
;
if
(
c
!=
'-'
)
goto
baddate
;
c
=
getc
(
stdin
);
/* Year */
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
isdigit
(
c
))
{
if
(
tm
.
tm_year
<
19
)
goto
baddate
;
tm
.
tm_year
-=
19
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
}
else
old_format
++
;
/* Hour */
if
(
c
!=
' '
)
goto
baddate
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_hour
=
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_hour
=
tm
.
tm_hour
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
tm
.
tm_hour
>
23
)
goto
baddate
;
/* Minute */
if
(
c
!=
':'
)
goto
baddate
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_min
=
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_min
=
tm
.
tm_min
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
tm
.
tm_min
>
59
)
goto
baddate
;
/* Second */
if
(
c
!=
':'
)
goto
baddate
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_sec
=
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_sec
=
tm
.
tm_sec
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
tm
.
tm_min
>
60
)
goto
baddate
;
/* Time zone */
if
(
old_format
)
{
if
(
c
!=
'-'
)
goto
baddate
;
c
=
getc
(
stdin
);
if
(
!
isalpha
(
c
))
goto
baddate
;
zone
[
0
]
=
c
;
c
=
getc
(
stdin
);
if
(
c
==
'\"'
)
{
/* Military (single-char) zones */
zone
[
1
]
=
'\0'
;
lcase
(
zone
);
if
(
zone
[
0
]
<=
'm'
)
{
zone_off
=
(
zone
[
0
]
-
'a'
+
1
)
*
60
;
}
else
if
(
zone
[
0
]
<
'z'
)
{
zone_off
=
(
'm'
-
zone
[
0
])
*
60
;
}
else
zone_off
=
0
;
}
else
{
/* UT (universal time) */
zone
[
1
]
=
c
;
c
=
getc
(
stdin
);
if
(
c
==
'\"'
)
{
zone
[
2
]
=
'\0'
;
lcase
(
zone
);
if
(
!
strcmp
(
zone
,
"ut"
))
goto
baddate
;
zone_off
=
0
;
}
else
{
/* 3-char time zone */
zone
[
2
]
=
c
;
c
=
getc
(
stdin
);
if
(
c
!=
'\"'
)
goto
baddate
;
zone
[
3
]
=
'\0'
;
lcase
(
zone
);
p
=
strchr
(
"aecmpyhb"
,
zone
[
0
]);
if
(
c
!=
'\"'
||
zone
[
2
]
!=
't'
||
!
p
)
goto
baddate
;
zone_off
=
(
strlen
(
p
)
-
12
)
*
60
;
if
(
zone
[
1
]
==
'd'
)
zone_off
-=
60
;
else
if
(
zone
[
1
]
!=
's'
)
goto
baddate
;
}
}
}
else
{
if
(
c
!=
' '
)
goto
baddate
;
c
=
getc
(
stdin
);
if
(
c
!=
'+'
&&
c
!=
'-'
)
goto
baddate
;
zone
[
0
]
=
c
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
zone_off
=
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
zone_off
=
zone_off
*
10
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
zone_off
=
zone_off
*
6
+
c
-
'0'
;
c
=
getc
(
stdin
);
if
(
!
isdigit
(
c
))
goto
baddate
;
zone_off
=
zone_off
*
10
+
c
-
'0'
;
if
(
zone
[
0
]
==
'-'
)
zone_off
=
-
zone_off
;
c
=
getc
(
stdin
);
if
(
c
!=
'\"'
)
goto
baddate
;
}
c
=
getc
(
stdin
);
tm
.
tm_isdst
=
-1
;
*
date
=
mktime
(
&
tm
);
ltm
=
localtime
(
date
);
*
date
+=
ltm
->
tm_gmtoff
-
zone_off
*
60
;
return
c
;
baddate
:
ungetc
(
c
,
stdin
);
return
EOF
;
}
/*
* Return nonzero if 's' matches the grammar for an atom
*/
int
isatom
(
s
)
char
*
s
;
{
if
(
!*
s
)
return
0
;
for
(;
*
s
;
s
++
)
{
if
(
*
s
&
0x80
||
*
s
<
0x1f
||
*
s
==
0x7f
||
*
s
==
' '
||
*
s
==
'{'
||
*
s
==
'('
||
*
s
==
')'
||
*
s
==
'\"'
||
*
s
==
'%'
||
*
s
==
'\\'
)
return
0
;
}
return
1
;
}
/*
* Return nonzero if 's' matches the grammar for a sequence
*/
int
issequence
(
s
)
char
*
s
;
{
int
c
;
int
len
=
0
;
int
sawcolon
=
0
;
while
(
c
=
*
s
)
{
if
(
c
==
','
)
{
if
(
!
len
)
return
0
;
if
(
!
isdigit
(
s
[
-1
])
&&
s
[
-1
]
!=
'*'
)
return
0
;
sawcolon
=
0
;
}
else
if
(
c
==
':'
)
{
if
(
sawcolon
||
!
len
)
return
0
;
if
(
!
isdigit
(
s
[
-1
])
&&
s
[
-1
]
!=
'*'
)
return
0
;
sawcolon
=
1
;
}
else
if
(
c
==
'*'
)
{
if
(
len
&&
s
[
-1
]
!=
','
&&
s
[
-1
]
!=
':'
)
return
0
;
if
(
isdigit
(
s
[
1
]))
return
0
;
}
else
if
(
!
isdigit
(
c
))
{
return
0
;
}
s
++
;
len
++
;
}
if
(
len
==
0
)
return
0
;
if
(
!
isdigit
(
s
[
-1
])
&&
s
[
-1
]
!=
'*'
)
return
0
;
return
1
;
}
/*
* Eat characters up to and including the next newline
*/
eatline
()
{
char
c
;
while
((
c
=
getc
(
stdin
))
!=
EOF
&&
c
!=
'\n'
);
}
/*
* Print 's' as an atom, quoted-string, or literal
*/
printastring
(
s
)
char
*
s
;
{
char
*
p
;
if
(
isatom
(
s
))
{
printf
(
"%s"
,
s
);
return
;
}
/* Look for any non-QCHAR characters */
for
(
p
=
s
;
*
p
;
p
++
)
{
if
(
*
p
&
0x80
||
*
p
==
'\r'
||
*
p
==
'\n'
||
*
p
==
'\"'
||
*
p
==
'%'
||
*
p
==
'\\'
)
break
;
}
if
(
*
p
)
{
printf
(
"{%d}
\r\n
%s"
,
strlen
(
s
),
s
);
}
else
{
printf
(
"
\"
%s
\"
"
,
s
);
}
}
/*
* Append 's' to the strlist 'l'.
*/
appendstrlist
(
l
,
s
)
struct
strlist
**
l
;
char
*
s
;
{
struct
strlist
**
tail
=
l
;
while
(
*
tail
)
tail
=
&
(
*
tail
)
->
next
;
*
tail
=
(
struct
strlist
*
)
xmalloc
(
sizeof
(
struct
strlist
));
(
*
tail
)
->
s
=
strsave
(
s
);
(
*
tail
)
->
next
=
0
;
}
/*
* Free the strlist 'l'
*/
freestrlist
(
l
)
struct
strlist
*
l
;
{
struct
strlist
*
n
;
while
(
l
)
{
n
=
l
->
next
;
free
(
l
->
s
);
free
((
char
*
)
l
);
l
=
n
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Mon, Apr 6, 2:23 AM (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831993
Default Alt Text
imapd.c (51 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline