📄 pgparmor.c
字号:
context->inlen);
/* Apply padding so that we can overshoot */
if (context->inlen < sizeof (context->input))
context->input[context->inlen] = 0;
/* Refill the output buffer from the input buffer */
context->outlen = armorLine (context->input, context->inlen,
context->output);
context->output [context->outlen++] = '\n';
context->outptr = context->output;
context->inlen = 0;
}
static PGPError
Flush (PGPPipeline *myself)
{
ArmorContext *context;
PGPError error;
size_t retlen;
pgpAssert (myself);
pgpAssert (myself->magic == ARMORMAGIC);
context = (ArmorContext *)myself->priv;
pgpAssert (context);
pgpAssert (context->tail);
/* Try to flush anything that we have buffered. */
while (context->outlen) {
retlen = context->tail->write (context->tail,
(PGPByte *)context->outptr,
context->outlen,
&error);
context->outlen -= retlen;
context->outptr += retlen;
if (!context->outlen)
context->lineno++;
if (error)
return error;
}
return kPGPError_NoErr;
}
/*
* First, try to flush out the output buffer. Once that is empty,
* refill the output buffer from the input buffer, append a newline,
* and set the input buffer to 0 input. Then try to write that out,
* too.
*/
static PGPError
DoFlush (PGPPipeline *myself)
{
ArmorContext *context = (ArmorContext *)myself->priv;
PGPError error = kPGPError_NoErr;
/*
* Try to flush anything that we have buffered. I know that
* the first time Flush is called, outlen WILL be zero!
*/
error = Flush (myself);
if (error)
return error;
/* Next, try to output anything in the header fifo */
error = armorFlushHeader (context);
if (error)
return error;
/* Finally, process the input buffer and flush it out again */
if (context->inlen) {
armorProcessLine (context);
error = DoFlush (myself);
}
return error;
}
/*
* Write a single line.
*/
static size_t
armorWriteBytes (PGPPipeline *myself, PGPByte const *buf, size_t size,
PGPError *error)
{
ArmorContext *context = (ArmorContext *)myself->priv;
size_t size0 = size;
unsigned t;
/*
* Try to flush anything that we have buffered. I know that
* the first time Flush is called, outlen WILL be zero!
*/
*error = Flush (myself);
if (*error)
return 0;
/* try to fill up the input buffer */
t = pgpMin ((sizeof (context->input) - context->inlen), size);
memcpy (context->input + context->inlen, buf, t);
buf += t;
size -= t;
context->inlen += t;
if( context->inlen ) {
armorWriteClassify (context, context->input);
/*
* check if we need a new file. This is called if we
* exceed armorlines, or when we do have multiparts and we do
* not have a current part.
*/
if (context->armorlines && (context->lineno >=
context->armorlines ||
!context->thispart)) {
/*
* Set maxparts to -1 if this _is_ multipart armor
* using one-pass processing.
*/
if (context->version > PGPVERSION_3 &&
!context->maxparts && !context->sizevalid)
context->maxparts = -1;
*error = armorNewFile (myself);
if (*error)
return size0-size;
}
}
/* If we've filled a line, then flush it out */
if (context->inlen == sizeof (context->input)) {
if (!context->didheader)
armorMakeHeader (context);
*error = DoFlush (myself);
if (*error)
return size0-size;
}
return size0-size;
}
/*
* Minimally perform a DoFlush(), but try to flush the fifo, too!
*
* If context->version > PGPVERSION_3 then we only start writing
* things out context->armorlines == 0 or when we have a full block
* worth of data (48 * (context->armorlines - context->lineno)). If
* context->sizevalid == 2, we have an EOF and should flush the rest
* of the fifo regardless.
*/
static PGPError
armorFlushFifo (PGPPipeline *myself)
{
ArmorContext *context = (ArmorContext *)myself->priv;
PGPByte const *ptr;
PGPSize len;
size_t retlen;
PGPError error;
ptr = pgpFifoPeek (context->fd, context->fifo, &len);
while (len) {
if (context->version > PGPVERSION_3 &&
context->sizevalid < 2 &&
context->armorlines &&
pgpFifoSize (context->fd, context->fifo) < 48 *
(context->lineno == context->armorlines ?
context->armorlines :
(context->armorlines - context->lineno)))
return kPGPError_NoErr;
retlen = armorWriteBytes (myself, ptr, len, &error);
pgpFifoSeek (context->fd, context->fifo, retlen);
if (error)
return error;
ptr = pgpFifoPeek (context->fd, context->fifo, &len);
}
return kPGPError_NoErr;
}
/*
* This is the function that processes a clearsigned message. It uses
* context->state to tell it what it is doing:
* 0) at the beginning -- check it
* 1) middle of line, pass it through
* 2) end of line with \r -- check next character for \n */
static size_t
armorDoClearsign (PGPPipeline *myself, PGPByte const *buf, size_t size,
PGPError *error)
{
ArmorContext *context = (ArmorContext *)myself->priv;
size_t written, size0 = size;
PGPByte const *ptr;
static PGPByte const from[] = "From ";
int i, t, flag;
while (size) {
if (context->state == 2) {
context->state = 0;
if (*buf == '\n') {
ptr = buf+1;
goto do_write;
}
}
/*
* Here, we check the beginning of the line. We use the
* flag to denote what we've found/buffered:
* 0) no match
* 1) full match
* 2) partial match (and we buffered data)
*/
if (!context->state) {
flag = 0;
if (!context->linebuf) {
/* nothing is buffered */
if (*buf == '-')
flag = 1;
}
if (!flag) {
t = pgpMin (5, size - context->linebuf);
for (i = 0; i < t; i++)
if (buf[i] != from[context->linebuf +
i]) {
pgpFifoWrite
(context->fd,
context->header,
context->input,
context->linebuf);
context->linebuf = 0;
break;
}
if (i == t) {
/* We matched the whole input buffer */
if (i + context->linebuf == 5)
flag = 1;
else {
memcpy (context->input +
context->linebuf, buf,
t);
context->linebuf += t;
size -= t;
buf += t;
flag = 2;
}
}
}
if (flag == 1) {
pgpFifoWrite (context->fd, context->header,
(PGPByte const *)"- ", 2);
if (context->linebuf) {
pgpFifoWrite (context->fd,
context->header,
context->input,
context->linebuf);
context->linebuf = 0;
}
}
if (flag != 2)
context->state = 1;
}
*error = armorFlushHeader (context);
if (*error)
return size0 - size;
for (ptr = buf; ptr < buf+size; ptr++) {
if (*ptr == '\r' || *ptr == '\n') {
context->state = (*ptr++ == '\r') ?
2 : 0;
break;
}
}
do_write:
written = context->tail->write (context->tail, buf,
ptr-buf, error);
buf += written;
size -= written;
if (*error)
return size0 - size;
}
return size0 - size;
}
/*
* This function creates a pgp-mime multipart/signed (clearsigned) message.
* We are now assuming that caller is responsible for giving us a good,
* MIME formatted body part. So we just pass it through.
*/
static size_t
armorDoMimesign (PGPPipeline *myself, PGPByte const *buf, size_t size,
PGPError *error)
{
ArmorContext *context = (ArmorContext *)myself->priv;
size_t written, size0 = size;
while (size) {
written = context->tail->write (context->tail, buf, size, error);
buf += written;
size -= written;
if (*error)
return size0 - size;
}
return size0 - size;
}
static size_t
Write (PGPPipeline *myself, PGPByte const *buf, size_t size, PGPError *error)
{
ArmorContext *context;
size_t retval, written = 0;
pgpAssert (myself);
pgpAssert (myself->magic == ARMORMAGIC);
pgpAssert (error);
context = (ArmorContext *)myself->priv;
pgpAssert (context);
pgpAssert (context->tail);
if (context->outlen) {
*error = DoFlush (myself);
if (*error)
return 0;
}
if (context->clearsign) {
if (context->pgpmime)
return armorDoMimesign (myself, buf, size, error);
else
return armorDoClearsign (myself, buf, size, error);
}
if (!context->sizevalid || context->version > PGPVERSION_3) {
written = pgpFifoWrite (context->fd, context->fifo, buf, size);
if (context->version <= PGPVERSION_3)
return written;
}
*error = armorFlushFifo (myself);
if (*error || context->version > PGPVERSION_3)
return written;
/* Try to write all the data we were given */
do {
retval = armorWriteBytes (myself, buf, size, error);
written += retval;
buf += retval;
size -= retval;
if (*error)
return written;
} while (size);
return written;
}
static PGPError
Annotate (PGPPipeline *myself, PGPPipeline *origin, int type,
PGPByte const *string, size_t size)
{
ArmorContext *context;
PGPError error = kPGPError_NoErr;
pgpAssert (myself);
pgpAssert (myself->magic == ARMORMAGIC);
context = (ArmorContext *)myself->priv;
pgpAssert (context);
switch( type ) {
case PGPANN_PGPMIME_HEADER_SIZE:
pgpAssert( size == sizeof(PGPSize) );
*(PGPSize *)string = context->mimebodyoff;
break;
case PGPANN_PGPMIME_HEADER_LINES:
pgpAssert( size == sizeof(PGPUInt32) );
*(PGPUInt32 *)string = context->mimeheaderlines;
break;
case PGPANN_PGPMIME_SEPARATOR:
if (context->pgpmime == PGPMIMEENC) {
strncpy((char *)string, MIMEENCSEP,
pgpMin(size, strlen(MIMEENCSEP)+1));
} else {
strncpy((char *)string, context->mimesigsep,
pgpMin(size, NSEPCHARS+1));
}
break;
default:
if (context->tail)
error = context->tail->annotate (context->tail, origin, type,
string, size);
break;
}
if (!error)
PGP_SCOPE_DEPTH_UPDATE(context->scope_depth, type);
pgpAssert(context->scope_depth != -1);
return error;
}
static PGPError
SizeAdvise (PGPPipeline *myself, unsigned long bytes)
{
ArmorContext *context;
PGPError error = kPGPError_NoErr;
unsigned long total;
pgpAssert (myself);
pgpAssert (myself->magic == ARMORMAGIC);
context = (ArmorContext *)myself->priv;
pgpAssert (context);
pgpAssert (context->tail);
/* Only handle bytes until EOF */
if (context->scope_depth)
return kPGPError_NoErr;
/* Then compute maxparts */
if (!context->sizevalid) {
if (context->armorlines) {
total = bytes + pgpFifoSize (context->fd,
context->fifo);
if (context->version > PGPVERSION_3 &&
context->thispart) {
total += 48 * context->armorlines *
(context->thispart - 1);
total += 48 * context->lineno;
}
/* 48 bytes / line */
context->maxparts = total / (context->armorlines * 48);
if (context->maxparts)
context->maxparts++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -