/*

COGS Gamearena challenge algorithm 0.1.2
by Luigi Auriemma
e-mail: aluigi@autistici.org
web:    aluigi.org


INTRODUCTION
============
This algorithm is used by the COGS client (http://cogs.games.bigpond.com)
to calculate the challenge response to send back to the login server.
When you want to login you send your data (nickname and password) and the
server sends you a string of data to which you must answer with another
string calculated on it.

Note: this algorithm has been tested with Gcc and Lcc-win32 but on this
      last compiler something goes wrong and the result is not exact, so
      if you wanna use this algorithm try the following example and watch
      if your challenge result is the same:
      query:     abcdabcdabcdabcd
      challenge: vtzswpnoq


HOW TO USE
==========
 #include "cogs_chall.h"

  u_char data[] = "abcdabcdabcdabcd";
  datalen = cogs_chall(data, strlen(data));
  printf("The challenge is %s\n", data);


LICENSE
=======
    Copyright 2004,2005,2006 Luigi Auriemma

    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 Place, Suite 330, Boston, MA  02111-1307 USA

    http://www.gnu.org/licenses/gpl.txt

*/

#include <string.h>


int cogs_chall(unsigned char *buff, int size) {
    int             num,
                    i,
                    tmpsz;
    long double     fnum;
    unsigned char   *tmp,
                    *ptr,
                    *data;

    if(!*buff) return(0);

    num = buff[1] * buff[5];
    data = buff;
    for(i = 0; i < size; i++) {
        do {
            num = (num * 0x41a7) - ((num / 0x1f31d) * 0x7fffffff);
            if(num < 0) num += 0x7fffffff;
            fnum = (long double)num * 0.00000000046566128752457969;
        } while(fnum >= 1);
        *data = 219 - (((int)((fnum * 26) + 'a') + *data) >> 1);
        data++;
    }

    tmp = malloc(size + 1);
    if(!tmp) return(0);

    ptr = tmp;
    tmpsz = 0;
    data = buff + size - 1;
    while(size--) {
        num = *data--;
        for(i = 0; i < tmpsz; i++) {
            if(num == tmp[i]) break;
        }
        if(i != tmpsz) continue;
        *ptr++ = num;
        tmpsz++;
    }
    *ptr = 0;
    memcpy(buff, tmp, tmpsz + 1);
    free(tmp);
    return(tmpsz);
}

