262 lines
7.8 KiB
C
262 lines
7.8 KiB
C
/****************************************************************************
|
|
* <Novell-copyright>
|
|
* Copyright (c) 2001 Novell, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, contact Novell, Inc.
|
|
*
|
|
* To contact Novell about this file by physical or electronic mail, you
|
|
* may find current contact information at www.novell.com.
|
|
* </Novell-copyright>
|
|
****************************************************************************/
|
|
|
|
#include "protocol.h"
|
|
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
|
|
static const char *
|
|
SkipSpace(const char *cursor)
|
|
{
|
|
while (*cursor == ' ' || *cursor == '\t') cursor++;
|
|
return cursor;
|
|
}
|
|
|
|
static int
|
|
ParseUnsigned(const char **cursor, uint32_t *value)
|
|
{
|
|
uint32_t parsed = 0;
|
|
const char *current = *cursor;
|
|
|
|
if (!isdigit((unsigned char)*current)) return 0;
|
|
do {
|
|
unsigned int digit = (unsigned int)(*current - '0');
|
|
if (parsed > (UINT32_MAX - digit) / 10) return 0;
|
|
parsed = parsed * 10 + digit;
|
|
current++;
|
|
} while (isdigit((unsigned char)*current));
|
|
|
|
*cursor = current;
|
|
*value = parsed;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
POP3ArgumentsEmpty(const char *arguments)
|
|
{
|
|
return arguments && *arguments == '\0';
|
|
}
|
|
|
|
POP3STLSStatus
|
|
POP3STLSCheck(int authorization_state, int tls_active, int utf8_active,
|
|
int tls_available)
|
|
{
|
|
if (!authorization_state || tls_active || utf8_active)
|
|
return POP3_STLS_INVALID_STATE;
|
|
if (!tls_available) return POP3_STLS_UNAVAILABLE;
|
|
return POP3_STLS_READY;
|
|
}
|
|
|
|
int
|
|
POP3ParseMessageNumber(const char *arguments, uint32_t *message_number)
|
|
{
|
|
const char *cursor;
|
|
uint32_t parsed;
|
|
|
|
if (!arguments || !message_number ||
|
|
(*arguments != ' ' && *arguments != '\t')) return 0;
|
|
cursor = SkipSpace(arguments);
|
|
if (!ParseUnsigned(&cursor, &parsed) || parsed == 0 || *cursor != '\0')
|
|
return 0;
|
|
*message_number = parsed;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
POP3ParseTopArguments(const char *arguments, uint32_t *message_number,
|
|
uint32_t *line_count)
|
|
{
|
|
const char *cursor;
|
|
uint32_t parsed_message;
|
|
uint32_t parsed_lines;
|
|
|
|
if (!arguments || !message_number || !line_count ||
|
|
(*arguments != ' ' && *arguments != '\t')) return 0;
|
|
cursor = SkipSpace(arguments);
|
|
if (!ParseUnsigned(&cursor, &parsed_message) || parsed_message == 0 ||
|
|
(*cursor != ' ' && *cursor != '\t')) return 0;
|
|
cursor = SkipSpace(cursor);
|
|
if (!ParseUnsigned(&cursor, &parsed_lines) || *cursor != '\0') return 0;
|
|
*message_number = parsed_message;
|
|
*line_count = parsed_lines;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
POP3UserNameValid(const char *user, size_t user_size, int allow_utf8)
|
|
{
|
|
const unsigned char *cursor = (const unsigned char *)user;
|
|
size_t length = 0;
|
|
|
|
if (!user || user_size == 0 || !*cursor) return 0;
|
|
while (*cursor) {
|
|
if (*cursor <= 0x20 || *cursor == 0x7f ||
|
|
(!allow_utf8 && *cursor >= 0x80) || length + 1 >= user_size) {
|
|
return 0;
|
|
}
|
|
length++;
|
|
cursor++;
|
|
}
|
|
return !allow_utf8 || POP3UTF8Valid(user, length);
|
|
}
|
|
|
|
int
|
|
POP3ParseUserArgument(const char *arguments, char *user, size_t user_size,
|
|
int allow_utf8)
|
|
{
|
|
const char *cursor;
|
|
size_t length;
|
|
|
|
if (!arguments || !user || user_size == 0 ||
|
|
(*arguments != ' ' && *arguments != '\t')) return 0;
|
|
cursor = SkipSpace(arguments);
|
|
length = strlen(cursor);
|
|
if (length >= user_size ||
|
|
!POP3UserNameValid(cursor, user_size, allow_utf8)) {
|
|
user[0] = '\0';
|
|
return 0;
|
|
}
|
|
memcpy(user, cursor, length + 1);
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
POP3MultilineWriterInit(POP3MultilineWriter *writer)
|
|
{
|
|
if (!writer) return;
|
|
writer->at_line_start = 1;
|
|
writer->has_data = 0;
|
|
writer->ends_in_lf = 0;
|
|
writer->ends_in_cr = 0;
|
|
}
|
|
|
|
int
|
|
POP3Contains8Bit(const void *data, size_t length)
|
|
{
|
|
const unsigned char *cursor = data;
|
|
size_t i;
|
|
|
|
if (!data && length) return 0;
|
|
for (i = 0; i < length; i++) {
|
|
if (cursor[i] >= 0x80) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
POP3UTF8Valid(const void *data, size_t length)
|
|
{
|
|
const unsigned char *cursor = data;
|
|
size_t i = 0;
|
|
|
|
if (!data && length) return 0;
|
|
while (i < length) {
|
|
unsigned char first = cursor[i++];
|
|
|
|
if (first <= 0x7f) continue;
|
|
if (first >= 0xc2 && first <= 0xdf) {
|
|
if (i >= length || cursor[i] < 0x80 || cursor[i] > 0xbf)
|
|
return 0;
|
|
i++;
|
|
} else if (first >= 0xe0 && first <= 0xef) {
|
|
unsigned char second;
|
|
if (length - i < 2) return 0;
|
|
second = cursor[i++];
|
|
if ((first == 0xe0 && (second < 0xa0 || second > 0xbf)) ||
|
|
(first == 0xed && (second < 0x80 || second > 0x9f)) ||
|
|
((first != 0xe0 && first != 0xed) &&
|
|
(second < 0x80 || second > 0xbf)) ||
|
|
cursor[i] < 0x80 || cursor[i] > 0xbf) return 0;
|
|
i++;
|
|
} else if (first >= 0xf0 && first <= 0xf4) {
|
|
unsigned char second;
|
|
if (length - i < 3) return 0;
|
|
second = cursor[i++];
|
|
if ((first == 0xf0 && (second < 0x90 || second > 0xbf)) ||
|
|
(first == 0xf4 && (second < 0x80 || second > 0x8f)) ||
|
|
((first != 0xf0 && first != 0xf4) &&
|
|
(second < 0x80 || second > 0xbf)) ||
|
|
cursor[i] < 0x80 || cursor[i] > 0xbf ||
|
|
cursor[i + 1] < 0x80 || cursor[i + 1] > 0xbf) return 0;
|
|
i += 2;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
POP3MultilineWriterWrite(POP3MultilineWriter *writer, const void *data,
|
|
size_t length, POP3WriteFunction write_function,
|
|
void *context)
|
|
{
|
|
const unsigned char *cursor = data;
|
|
size_t start = 0;
|
|
size_t i;
|
|
|
|
if (!writer || (!data && length) || !write_function) return 0;
|
|
for (i = 0; i < length; i++) {
|
|
if (writer->at_line_start && cursor[i] == '.') {
|
|
if (i > start && !write_function(context, cursor + start, i - start))
|
|
return 0;
|
|
if (!write_function(context, ".", 1)) return 0;
|
|
start = i;
|
|
}
|
|
if (cursor[i] == '\n' && !writer->ends_in_cr) {
|
|
if (i > start && !write_function(context, cursor + start, i - start))
|
|
return 0;
|
|
if (!write_function(context, "\r", 1)) return 0;
|
|
start = i;
|
|
}
|
|
writer->at_line_start = cursor[i] == '\n';
|
|
writer->has_data = 1;
|
|
writer->ends_in_lf = writer->at_line_start;
|
|
writer->ends_in_cr = cursor[i] == '\r';
|
|
}
|
|
return start == length ||
|
|
write_function(context, cursor + start, length - start);
|
|
}
|
|
|
|
int
|
|
POP3MultilineWriterFinish(POP3MultilineWriter *writer,
|
|
POP3WriteFunction write_function, void *context)
|
|
{
|
|
if (!writer || !write_function) return 0;
|
|
if (!writer->has_data) {
|
|
if (!write_function(context, "\r\n", 2)) return 0;
|
|
} else if (!writer->ends_in_lf) {
|
|
if (writer->ends_in_cr) {
|
|
if (!write_function(context, "\n", 1)) return 0;
|
|
} else if (!write_function(context, "\r\n", 2)) {
|
|
return 0;
|
|
}
|
|
}
|
|
if (!write_function(context, ".\r\n", 3)) return 0;
|
|
writer->at_line_start = 1;
|
|
writer->has_data = 0;
|
|
writer->ends_in_lf = 0;
|
|
writer->ends_in_cr = 0;
|
|
return 1;
|
|
}
|