/* $Cambridge: hermes/src/prayer/session/checksum.c,v 1.3 2008/09/16 09:59:58 dpc22 Exp $ */
/************************************************
 *    Prayer - a Webmail Interface              *
 ************************************************/

/* Copyright (c) University of Cambridge 2000 - 2008 */
/* See the file NOTICE for conditions of use and distribution. */

/* Little snippet of code to calculate file checksum and compare with
 * current value. Rather strange little checksum routine: just happens
 * to be compatible with what we are using at the moment... */

#include "prayer_session.h"

/* checksum_hash_line() **************************************************
 *
 * Convert single line of input into checksum value
 *   line:   Line to checksum
 *   maxlen: Maximum length to checksum
 *           [shouldn't be an 
 ************************************************************************/

static int checksum_hash_line(char *line)
{
    unsigned int total = 0;
    unsigned int i;
    char *p;

    for (i = 0, p = line; *p != '\0' && *p != '\n'; p++, i++) {
        total += (((unsigned int) *p) * (i + 1));
    }

    return (total % 65536);
}

/* checksum_test() ********************************************************
 *
 * Calculate checksum value for a string.
 *   string: String to checksum
 *     pool: Scratch pool
 * existing: Existing checksum
 *  current: Calculated checksum
 *
 * Returns: T => Found existing checksum line
 *************************************************************************/

BOOL
checksum_test(char *string, struct pool *pool)
{
    char *checkstring = CHECKSUM_PREFIX;
    unsigned long checklen = strlen(checkstring);
    unsigned long file_checksum = 0;
    unsigned long checksum = 0;
    int rc = NIL;
    char *line, *p;

    string = pool_strdup(pool, string);

    while ((line=string_get_line(&string))) {
        if (line[0] != '#') {
            checksum += checksum_hash_line(line);
            checksum %= (1024 * 1024);     /* Cap values to < 10^6 */
            continue;
        }

        if (strncmp(line, checkstring, checklen) != 0)
            continue;

        p = line + strlen(checkstring);

        while (*p != '\0' && !Uisdigit(*p))
            p++;
        
        file_checksum = atoi(p);
        rc = T;
    }

    return((rc && (checksum == file_checksum)) ? T : NIL);
}

/* checksum_calculate() ****************************************************
 *
 * Input:
 *   string: string to checksum
 *     pool: scratch pool
 *
 * Returns:
 *   Checksum value.
 *************************************************************************/

unsigned long
checksum_calculate(char *string, struct pool *pool)
{
    char *line;
    unsigned long checksum = 0;

    string = pool_strdup(pool, string);

    while ((line=string_get_line(&string))) {
        if (line[0] == '#')
            continue;

        checksum += checksum_hash_line(line);
        checksum %= (1024 * 1024); /* Cap values to < 10^6 */
    }

    return (checksum);
}
