[Evolution-hackers] camel debug log helper tools
- From: Jeffrey Stedfast <fejj novell com>
- To: evolution-hackers gnome org
- Subject: [Evolution-hackers] camel debug log helper tools
- Date: Fri, 28 Apr 2006 13:28:56 -0400
While sifting thru some camel debug logs yesterday, I wrote a couple
useful tools.
protocol-log.c: this program extracts imap and smtp protocol spew from
the camel debug log (doesn't handle pop, nntp, nor imap4 protocol
spewage because they each use different formats)
imap-state.c: meant for use debugging imap (not imap4, imapp, nor
imapx). adds inline state dumps to the log file stream (dumps message
sequence id -> uid mapping and message flags). also prints out warnings
in a few cases if it notices something fishy going on...
example usage:
./imap-state INBOX.Evolution -
runs 'imap-state', reading from stdin, and watches the INBOX.Evolution
folder and dumps state whenever it changes.
Jeff
--
Jeffrey Stedfast
Evolution Hacker - Novell, Inc.
fejj novell com - www.novell.com
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors: Jeffrey Stedfast <fejj novell com>
*
* Copyright 2006 Novell, Inc. (www.novell.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
int main (int argc, char **argv)
{
size_t inleft, insize, offset, n;
char *inbuf, *inptr, *str;
FILE *fp;
if (argc < 2 || !strcmp (argv[1], "-")) {
fp = stdin;
} else if (!(fp = fopen (argv[1], "rt"))) {
return 0;
}
insize = 128;
inbuf = malloc (insize);
while (!feof (fp)) {
inleft = insize;
inptr = inbuf;
while (fgets (inptr, inleft, fp)) {
n = strlen (inptr);
inleft -= n;
inptr += n;
if (n > 0 && inptr[-1] == '\n')
break;
if (inleft <= 2) {
insize += 128;
inleft += 128;
offset = inptr - inbuf;
inbuf = realloc (inbuf, insize);
inptr = inbuf + offset;
}
}
if (inleft == insize)
break;
if ((str = strstr (inbuf, "sending : "))) {
fputs (str, stdout);
continue;
}
if ((str = strstr (inbuf, "received: "))) {
fputs (str, stdout);
continue;
}
}
free (inbuf);
if (fp != stdin)
fclose (fp);
return 0;
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors: Jeffrey Stedfast <fejj novell com>
*
* Copyright 2006 Novell, Inc. (www.novell.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
enum {
ANSWERED = (1 << 0),
DELETED = (1 << 1),
DRAFT = (1 << 2),
FLAGGED = (1 << 3),
RECENT = (1 << 4),
SEEN = (1 << 5),
};
static struct {
const char *name;
size_t namelen;
unsigned int flag;
} imap_flags[] = {
{ "\\Answered", 9, ANSWERED },
{ "\\Deleted", 8, DELETED },
{ "\\Draft", 6, DRAFT },
{ "\\Flagged", 8, FLAGGED },
{ "\\Recent", 7, RECENT },
{ "\\Seen", 5, SEEN },
};
static unsigned int
parse_flags (const char *flags_list)
{
register const char *inptr = flags_list;
unsigned int flags = 0;
int i;
if (*inptr != '(')
return 0;
inptr++;
while (*inptr != ')') {
while (*inptr == ' ')
inptr++;
if (*inptr == '\\') {
for (i = 0; i < (sizeof (imap_flags) / sizeof (imap_flags[0])); i++) {
if (!strncmp (imap_flags[i].name, inptr, imap_flags[i].namelen)) {
inptr += imap_flags[i].namelen;
flags |= imap_flags[i].flag;
break;
}
}
}
while (*inptr != ' ' && *inptr != ')')
inptr++;
}
return flags;
}
static void
write_flags (unsigned int flags)
{
int space = 0;
size_t i;
for (i = 0; i < (sizeof (imap_flags) / sizeof (imap_flags[0])); i++) {
if (flags & imap_flags[i].flag) {
if (space)
fputs (" ", stdout);
fputs (imap_flags[i].name, stdout);
space = 1;
}
}
}
struct msg {
int known;
unsigned int uid;
unsigned int flags;
};
struct folder {
const char *name;
short selecting;
short selected;
struct msg **msgs; /* message array */
size_t mmsgs; /* max number of messages our array can hold */
size_t nmsgs; /* number of messages in array */
};
static void
folder_free (struct folder *folder)
{
size_t i;
for (i = 0; i < folder->mmsgs; i++)
free (folder->msgs[i]);
free (folder->msgs);
}
static void
folder_reset (struct folder *folder)
{
size_t i;
for (i = 0; i < folder->nmsgs; i++) {
folder->msgs[i]->known = 0;
folder->msgs[i]->flags = 0;
folder->msgs[i]->uid = 0;
}
folder->nmsgs = 0;
}
enum {
FLAGS,
PLUS_FLAGS,
MINUS_FLAGS
};
static void
set_flags (struct msg *msg, int mode, unsigned int flags)
{
switch (mode) {
case FLAGS:
msg->flags = flags;
break;
case PLUS_FLAGS:
msg->flags |= flags;
break;
case MINUS_FLAGS:
msg->flags &= ~flags;
break;
}
}
static void
store_flags (struct folder *folder, int uids, const char *set, int mode, unsigned int flags)
{
size_t min, max, cur, i;
char *end;
while (1) {
cur = strtoul (set, &end, 10);
if (*end == ',' || *end == ' ') {
/* singleton message */
if (uids) {
i = 0;
while (i < folder->nmsgs && cur != folder->msgs[i]->uid)
i++;
if (i < folder->nmsgs)
set_flags (folder->msgs[i], mode, flags);
} else {
if (cur > 0 && cur < folder->nmsgs)
set_flags (folder->msgs[cur - 1], mode, flags);
}
} else if (*end == ':') {
/* message range */
set = end + 1;
max = strtoul (set, &end, 10);
if (cur < max) {
min = cur;
} else {
min = max;
max = cur;
}
if (uids) {
i = 0;
while (i < folder->nmsgs && folder->msgs[i]->uid < min)
i++;
while (i < folder->nmsgs && folder->msgs[i]->uid <= max)
set_flags (folder->msgs[i++], mode, flags);
} else {
for (i = min - 1; i < max && i < folder->nmsgs; i++)
set_flags (folder->msgs[i], mode, flags);
}
} else {
break;
}
if (*end != ',')
break;
set = end + 1;
}
}
static void
untagged_expunge (struct folder *folder, size_t index)
{
size_t i, j;
if (index > folder->nmsgs) {
fprintf (stdout, "\n\tWARNING: expunging message %u; out of range\n\n", index);
return;
}
if (!(folder->msgs[index - 1]->flags & DELETED))
fprintf (stdout, "\n\tWARNING: expunging undeleted message %u!?!?!?\n\n", index);
else if (!folder->msgs[index - 1]->known)
fprintf (stdout, "\n\tWARNING: expunging unknown message %u\n\n", index);
if (folder->nmsgs > index) {
for (i = index - 1, j = index; j < folder->nmsgs; i++, j++)
memcpy (folder->msgs[i], folder->msgs[j], sizeof (struct msg));
}
folder->nmsgs--;
}
static void
untagged_fetch_flags (struct folder *folder, size_t index, unsigned int uid, unsigned int flags)
{
struct msg *msg;
size_t i;
if (index > folder->mmsgs) {
if (folder->msgs)
folder->msgs = realloc (folder->msgs, (index + 100) * sizeof (struct msg *));
else
folder->msgs = malloc ((index + 100) * sizeof (struct msg *));
folder->mmsgs = index + 100;
for (i = folder->nmsgs; i < folder->mmsgs; i++) {
msg = folder->msgs[i] = malloc (sizeof (struct msg));
msg->known = 0;
msg->flags = 0;
msg->uid = 0;
}
}
if (folder->nmsgs < index)
folder->nmsgs = index;
msg = folder->msgs[index - 1];
if (uid != 0) {
msg->known = 1;
msg->uid = uid;
msg->flags = flags;
} else {
if (!msg->known)
fprintf (stdout, "\n\tWARNING: getting flag updates for unknown msg %u\n\n", index);
msg->flags = flags;
}
}
static void
write_folder_state (struct folder *folder)
{
size_t i;
for (i = 0; i < folder->nmsgs; i++) {
if (folder->msgs[i]->known) {
printf ("\t* %u UID %u FLAGS (", i + 1, folder->msgs[i]->uid);
write_flags (folder->msgs[i]->flags);
fputs (")\n", stdout);
} else {
printf ("\t* %u UID ??? FLAGS (", i + 1);
write_flags (folder->msgs[i]->flags);
fputs (")\n", stdout);
}
}
}
int main (int argc, char **argv)
{
size_t inleft, insize, offset, n, index;
const char *progname;
struct folder folder;
char *inbuf, *inptr;
int mode, uids, log;
unsigned int flags;
unsigned int uid;
const char *set;
char tag = 'A';
FILE *fp;
if (!(progname = strrchr (argv[0], '/')))
progname = argv[0];
else
progname++;
if (argc < 2 || argc > 4 || (argc == 4 && !(argv[1][0] >= 'A' && argv[1][0] <= 'Z') && argv[1][1] != '\0')) {
printf ("Usage: %s [[TAG] Folder] filename\n", progname);
return 0;
}
if (argc == 4) {
folder.name = argv[2];
tag = argv[1][0];
} else if (argc == 3) {
folder.name = argv[1];
} else {
folder.name = "INBOX";
}
folder.selecting = 0;
folder.selected = 0;
folder.msgs = NULL;
folder.mmsgs = 0;
folder.nmsgs = 0;
if (!strcmp (argv[argc - 1], "-")) {
fp = stdin;
} else {
if (!(fp = fopen (argv[argc - 1], "rt"))) {
fprintf (stderr, "%s: fopen: `%s': %s\n", progname, argv[argc - 1], strerror (errno));
return 0;
}
}
insize = 128;
inbuf = malloc (insize);
while (!feof (fp)) {
inleft = insize;
inptr = inbuf;
log = 0;
while (fgets (inptr, inleft, fp)) {
n = strlen (inptr);
inleft -= n;
inptr += n;
if (n > 0 && inptr[-1] == '\n') {
if (strncmp (inbuf, "received: ", 10) != 0 || (inptr[-2] != '}' && inptr[-3] != '}'))
break;
}
if (inleft <= 2) {
insize += 128;
inleft += 128;
offset = inptr - inbuf;
inbuf = realloc (inbuf, insize);
inptr = inbuf + offset;
}
}
if (inleft == insize)
break;
fputs (inbuf, stdout);
if (!strncmp (inbuf, "sending : ", 10) && inbuf[10] == tag) {
inptr = inbuf + 10;
while (*inptr == ' ')
inptr++;
/* skip past tag */
while (*inptr && *inptr != ' ')
inptr++;
while (*inptr == ' ')
inptr++;
if (!strncmp (inptr, "SELECT", 6)) {
inptr += 6;
while (*inptr == ' ')
inptr++;
if (!strncmp (inptr, folder.name, strlen (folder.name)))
folder.selecting = 1;
else
folder.selecting = 0;
goto loop;
}
if (!folder.selected)
goto loop;
if (!strncmp (inptr, "UID", 3)) {
inptr += 3;
while (*inptr == ' ')
inptr++;
uids = 1;
} else
uids = 0;
if (!strncmp (inptr, "STORE", 5)) {
inptr += 5;
while (*inptr == ' ')
inptr++;
set = inptr;
while (*inptr && *inptr != ' ')
inptr++;
while (*inptr == ' ')
inptr++;
if (!strncmp (inptr, "+FLAGS", 6)) {
mode = PLUS_FLAGS;
inptr += 6;
} else if (!strncmp (inptr, "-FLAGS", 6)) {
mode = MINUS_FLAGS;
inptr += 6;
} else if (!strncmp (inptr, "FLAGS", 5)) {
mode = FLAGS;
inptr += 5;
} else {
goto loop;
}
if (strncmp (inptr, ".SILENT", 7) != 0) {
/* we'll get untagged responses to update our state */
goto loop;
}
inptr += 7;
while (*inptr == ' ')
inptr++;
if (*inptr != '(')
goto loop;
flags = parse_flags (inptr);
store_flags (&folder, uids, set, mode, flags);
log = 1;
}
} else if (!strncmp (inbuf, "received: ", 10)) {
inptr = inbuf + 10;
while (*inptr == ' ')
inptr++;
if (*inptr == '*' && folder.selected) {
inptr++;
while (*inptr == ' ')
inptr++;
if ((index = strtoul (inptr, &inptr, 10)) == 0) {
/* "* 0 RECENT" or "* 0 EXISTS" perhaps? */
goto loop;
}
while (*inptr == ' ')
inptr++;
if (!strncmp (inptr, "FETCH", 5)) {
inptr += 5;
while (*inptr == ' ')
inptr++;
offset = inptr - inbuf;
if ((inptr = strstr (inptr, "UID ")))
uid = strtoul (inptr + 4, NULL, 10);
else
uid = 0;
inptr = inbuf + offset;
if ((inptr = strstr (inptr, "FLAGS ("))) {
flags = parse_flags (inptr + 6);
untagged_fetch_flags (&folder, index, uid, flags);
log = 1;
}
} else if (!strncmp (inptr, "EXPUNGE", 7)) {
untagged_expunge (&folder, index);
log = 1;
}
} else if (*inptr == tag) {
/* tagged response */
while (*inptr && *inptr != ' ')
inptr++;
while (*inptr == ' ')
inptr++;
if (!strncmp (inptr, "OK ", 3)) {
inptr += 3;
while (*inptr == ' ')
inptr++;
/* skip over [READ-WRITE] or [READ-ONLY] RESP-CODE */
if (*inptr == '[') {
while (*inptr && *inptr != ' ')
inptr++;
while (*inptr == ' ')
inptr++;
}
if (!strncmp (inptr, "SELECT", 6)) {
if (folder.selecting) {
folder.selecting = 0;
folder.selected = 1;
folder_reset (&folder);
} else {
/* another folder got selected */
folder.selected = 0;
}
}
} else if (!strncmp (inptr, "NO ", 3)) {
if (folder.selecting && strstr (inptr, "SELECT"))
folder.selecting = 0;
} else if (!strncmp (inptr, "BAD ", 4)) {
if (folder.selecting && strstr (inptr, "SELECT"))
folder.selecting = 0;
}
}
}
loop:
if (log) {
inptr = inbuf + 10;
while (*inptr == ' ')
inptr++;
while (*inptr && *inptr != ' ')
inptr++;
*inptr = '\0';
inptr = inbuf + 10;
while (*inptr == ' ')
inptr++;
printf ("\n\tCurrent state of %s:\n", folder.name);
write_folder_state (&folder);
fputs ("\n\n", stdout);
fflush (stdout);
}
}
folder_free (&folder);
free (inbuf);
if (fp != stdin)
fclose (fp);
return 0;
}
[
Date Prev][Date Next] [
Thread Prev][Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]