#include "..\inc\swilib.h"

#include "objects.h"
#include "zipstruct.h"

#define wslen(ws) ws->wsbody[0]
extern void InitConfig();
extern const char WORKFOLDER[];
extern const char DER_FILE[];
extern const char KEY_FILE[];
extern const char folder[];

extern const char FOLDER_ICON[];
extern const char JAR_ICON[];

extern const int FREAD;
extern const int FWRITE;
extern const int INTERNET;
extern const int COMM;
extern const int BLUETOOTH;
extern const int SMS;
extern const int MMS;
extern const int MEDIA;

typedef struct
{
  CSM_RAM csm;
  int gui_id;
}MAIN_CSM;

typedef struct
{
  void *next;
  WSHDR *fullname;
  WSHDR *filename;
  int is_dir;
}FLIST;

#pragma pack(1)
typedef struct
{
#ifdef NEWSGOLD
  char signature[0x3C];
#else
  char signature[0x23];
#endif
  char cert_num;
}SBP_FILE_SIG;
#pragma pack()

typedef struct
{
  void *next;
  char *issuer;
  char *hash;
}SBP_LIST;

int filelist_menu_id;
volatile int request_remake_filelist;
volatile int request_close_filelist;
int is_manufacturer_patched();
volatile FLIST *fltop;
WSHDR* jar_file;
int S_ICONS[3];


const char manufacturer_sbp[]="2:\\Policy\\manufacturer.sbp";
const char certificate_store[]="2:\\Certificate store\\";

const char delimeter[]={2};
  
const int minus11=-11;
unsigned short maincsm_name_body[20];
extern void kill_data(void *p, void (*func_p)(void *));
extern char * base64_encode(const void *data, int *size);

const char midlet_cert[]="MIDlet-Certificate-1-1:";
const char midlet_jar_rsa[]="MIDlet-Jar-RSA-SHA1:";
const char midlet_permissions[]="MIDlet-Permissions:";
const char eol[]="\r\n";

//===============================================================================================
// ELKA Compatibility
#pragma inline
void patch_header(HEADER_DESC* head)
{
  head->rc.x=0;
  head->rc.y=YDISP;
  head->rc.x2=ScreenW()-1;
  head->rc.y2=HeaderH()+YDISP;
}
#pragma inline
void patch_input(INPUTDIA_DESC* inp)
{
  inp->rc.x=0;
  inp->rc.y=HeaderH()+1+YDISP;
  inp->rc.x2=ScreenW()-1;
  inp->rc.y2=ScreenH()-SoftkeyH()-1;
}
//===============================================================================================

void ed1_locret(void){}

void* zcalloc(int unk,size_t nelem, size_t elsize)
{
  return (malloc(nelem*elsize));
}

void zcfree(int unk, void* ptr)
{
  mfree(ptr);
}


#pragma inline=forced
int toupper(int c)
{
  if ((c>='a')&&(c<='z')) c+='A'-'a';
  return(c);
}

int strcmp_nocase(const char *s1,const char *s2)
{
  int i;
  int c;
  while(!(i=(c=toupper(*s1++))-toupper(*s2++))) if (!c) break;
  return(i);
}

int strncmp_nocase(const char *s1,const char *s2,unsigned int n)
{
  int i;
  int c;
  while(!(i=(c=toupper(*s1++))-toupper(*s2++))&&(--n)) if (!c) break;
  return(i);
}

#define DONE 0
#define CANT_OPEN_JAD 1
#define BAD_JAR 2
#define FILE_ALREADY_SIGNED 3
#define CANT_READ_CERT 4
#define CANT_CREATE_HASH 5
#define CANT_SIGN_HASH 6
#define CANT_APPEND 7
#define JAD_ALREDY_EXISTS 8
#define CANT_OPEN_JAR 9
#define CANT_FIND_MANIFEST 10
#define CANT_CREATE_JAD 11
#define BAD_KEY_FILE 12
#define SIZE_OF_JAD_NULL 13
#define FILE_WAS_NOT_SIGNED 14
#define CANT_OPEN_SFILE 15
#define CANT_OPEN_DFILE 16
#define CANT_OPEN_MANUFACTURER 17
#define CANT_WRITE_MANUFACTURER 18
#define MANUF_ALR_PATCHED 19
#define MANUF_PATCHED_UNCORR 20
#define MANUF_NOT_PATCHED 21

const char* errors[22]=
{  
  "成功!",
  "不能打开*.jad!",
  "错误的*.jar!",
  "*.jad已经被授权!",
  "不能读取证书!",
  "Can't create SHA1 hash!",
  "Can't sign hash!",
  "Can't open *.jad for append!",
  "*.jad文件已经存在!",
  "不能打开*.jar!",
  "不能找到MANIFEST.MF!",
  "不能创建*.jad!",
  "错误的*.key文件!",
  "jad文件大小是 NULL!",
  "文件没有被授权!",
  "不能打开证书!",
  "不能写入证书!",
  "不能打开manufacturer.sbp!",
  "不能写入manufacturer.sbp!",
  "Manufacturer已经修改!",
  "Manufacturer内容错误!",
  "Manufacturer需要修改!"
};

int split_lines(char *dest,const char *str1,const char *str2)
{
  strcpy(dest,str1);
  strcat(dest,str2);
  return (strlen(dest));
}

void ErrMsg(int num)
{
  ShowMSG(1,(int)errors[num]);
}

void ElfKiller(void)
{
  extern void *ELF_BEGIN;
  kill_data(&ELF_BEGIN,(void (*)(void *))mfree_adr());
}

int get_file_size(char* fname)
{
  int f;
  unsigned int err;
  FSTATS fs;
  if ((f=GetFileStats(fname,&fs,&err))==-1)
    return f;
  return (fs.size);
} 

char *ReadCertificate(int* size)
{
  char fname[256];
  int f;
  unsigned int err;
  unsigned int fsize;
  char* cert;
  split_lines(fname,certificate_store,DER_FILE);
  if ((f=fopen(fname,A_ReadOnly+A_BIN,P_READ,&err))==-1)
  {
    split_lines(fname,WORKFOLDER,DER_FILE);
    if ((f=fopen(fname,A_ReadOnly+A_BIN,P_READ,&err))==-1)
      return 0;
  }
  *size=fsize=lseek(f,0,S_END,&err,&err);
  if (!fsize)
    return 0;
  lseek(f,0,S_SET,&err,&err);
  cert=malloc(fsize);
  fread(f,cert,fsize,&err);
  fclose(f,&err);
  return (cert); 
}

void CreateSHA1Hash(char *hash, char *data, unsigned int n)
{
  SHA_CTX ctx;
  SHA1_Init(&ctx);
  SHA1_Update(&ctx, data, n);
  SHA1_Final(hash,&ctx);
}  

int CreateSHA1HashFile(const char* file,char * hash)
{
  int f;
  unsigned int err;
  unsigned int fsize;
  char* jar_data;
  if ((f=fopen(file,A_ReadOnly+A_BIN,P_READ,&err))==-1)
    return (f);
  fsize=lseek(f,0,S_END,&err,&err);
  if (!fsize)
    return (-2);
  lseek(f,0,S_SET,&err,&err);
  jar_data=malloc(fsize);
  fread(f,jar_data,fsize,&err);
  fclose(f,&err);
  CreateSHA1Hash(hash,jar_data,fsize);
  mfree(jar_data);
  return (0);
}
  
    
#pragma optimize=z 9
BIGNUM *BN_bin2bn_mod(int f,unsigned int len,BIGNUM *ret)
{
  BIGNUM *ret2;
  char *s=malloc(len);
  unsigned int err;
  fread(f,s,len,&err);
  unsigned int ch;
  unsigned int k=len/2;
  for (unsigned int i=0; i<k; i++)
  {
    ch=s[i];
    s[i]=s[len-i-1];
    s[len-i-1]=ch;
  }
  ret2=BN_bin2bn(s,len,ret);
  mfree(s);
  return (ret2);
}

int SignHash(char * hash,char*sign)
{
  int n;
  int f;
  unsigned int err;
  unsigned int rsa_sha1_len=1024;
  char buf[128];
  split_lines(buf,WORKFOLDER,KEY_FILE);
  if (get_file_size(buf)!=596)
    return(-1);

  if ((f=fopen(buf,A_ReadOnly+A_BIN,P_READ,&err))==-1)
    return(-1);
  
  RSA *rsa;
  
  if ((rsa=RSA_new_method(0))==NULL)
    return (-2);
  
  lseek(f,0x10,S_SET,&err,&err);
  
  if (!(rsa->e=BN_bin2bn_mod(f,4,rsa->e)))
    goto L_BN_ERROR;

  if (!(rsa->n=BN_bin2bn_mod(f,1024/8,rsa->n)))
    goto L_BN_ERROR;
  
  if (!(rsa->p=BN_bin2bn_mod(f,1024/16,rsa->p)))
    goto L_BN_ERROR;
  
  if (!(rsa->q=BN_bin2bn_mod(f,1024/16,rsa->q)))
    goto L_BN_ERROR;
  
  if (!(rsa->dmp1=BN_bin2bn_mod(f,1024/16,rsa->dmp1)))
    goto L_BN_ERROR;
  
  if (!(rsa->dmq1=BN_bin2bn_mod(f,1024/16,rsa->dmq1)))
    goto L_BN_ERROR;
  
  if (!(rsa->iqmp=BN_bin2bn_mod(f,1024/16,rsa->iqmp)))
    goto L_BN_ERROR;
  
  if (!(rsa->d=BN_bin2bn_mod(f,1024/8,rsa->d)))
    goto L_BN_ERROR;
       
 
  fclose(f,&err);
  zeromem(sign,128);
  rsa->meth->flags=RSA_FLAG_SIGN_VER;
  rsa->flags=RSA_FLAG_CACHE_PRIVATE;
  n=RSA_sign(NID_sha1, hash, 20, sign, &rsa_sha1_len, rsa);
  RSA_free(rsa);
  
  if (n<=0)
    return (-4);
  return (0);
  
L_BN_ERROR:
  RSA_free(rsa);
  return(-3);
}
  

  
int is_file_signed(char*jad, int size)
{
  int f;
  unsigned int err;
  char* buf;
  
  if ((f=fopen(jad,A_ReadOnly+A_BIN,P_READ,&err))==-1)
    return 1;
  buf=malloc(size+1);
  buf[size]=0;
  fread(f,buf,size,&err);
  fclose(f,&err);
  
  if (strstr(buf,midlet_cert))
    goto L_SIGNED;
  
  if (strstr(buf,midlet_jar_rsa))
    goto L_SIGNED;
  
  if (strstr(buf,midlet_permissions))
    goto L_SIGNED;
  
  mfree(buf);
  return (0);
  
L_SIGNED:
  mfree(buf);
  return (1);
}
  
void sign_jad(GUI *data)
{
  char jar[256];
  char * base64cert;
  char * base64hash;
  char *cert;
  char sha1jar[20];
  char rsa_sha1[128];
  char jad_name[256];
  char* signature;
  char*p;
  int size;
  int err_n;
  
  err_n=is_manufacturer_patched();
  if (err_n!=MANUF_ALR_PATCHED)
  {
    GeneralFuncF1(1);
    ErrMsg(err_n);
    return;
  }

  
  ws_2str(jar_file,jar,255);
  if (!(p=strstr(jar,".jar")))
  {
    err_n=BAD_JAR;
    GeneralFuncF1(1);
    ErrMsg(err_n);
    return;
  }
  strcpy(jad_name,jar);
  strcpy(jad_name+(p-jar),".jad");
  
  if ((size=get_file_size(jad_name))<=0)
  {
    err_n=CANT_OPEN_JAD;
    GeneralFuncF1(1);
    ErrMsg(err_n);
    return;
  }
  
  if (is_file_signed(jad_name,size))
  {
    err_n=FILE_ALREADY_SIGNED;
    GeneralFuncF1(1);
    ErrMsg(err_n);
    return;
  }
  
  if (!(cert=ReadCertificate(&size)))
  {
    err_n=CANT_READ_CERT;
    GeneralFuncF1(1);
    ErrMsg(err_n);
    return;
  }
  
  base64cert=base64_encode(cert,&size);
  mfree(cert);
  if(!base64cert)
  {
    err_n=CANT_READ_CERT;
    mfree(base64cert);
    GeneralFuncF1(1);
    ErrMsg(err_n);
    return;
  }
  
  if (CreateSHA1HashFile(jar,sha1jar))
  {
    err_n=CANT_CREATE_HASH;
    mfree(base64cert);
    GeneralFuncF1(1);
    ErrMsg(err_n);
    return;
  }
  
  if (SignHash(sha1jar,rsa_sha1))
  {
    err_n=CANT_SIGN_HASH;
    mfree(base64cert);
    GeneralFuncF1(1);
    ErrMsg(err_n);
    return;
  }
    
  size=128;
  base64hash=base64_encode(rsa_sha1,&size);
  
  signature=malloc(0x2000);
  sprintf(signature,"%s %s\r\n%s %s\r\n%s %s",midlet_cert,base64cert,midlet_jar_rsa,base64hash,midlet_permissions,"javax.microedition.midlet.MIDlet.platformRequest");
  mfree(base64cert);
  mfree(base64hash);
  
  if (FREAD>0)
  {
    strcat(signature,",javax.microedition.io.Connector.file.read");
    if (FREAD==1)
      strcat(signature,",com.siemens.mp.io.File.read");
  }
  
  if (FWRITE>0)
  {
    strcat(signature,",javax.microedition.io.Connector.file.write");
    if (FWRITE==1)
      strcat(signature,",com.siemens.mp.io.File.readwrite");
  }
  
  if (INTERNET==1)
  {
    strcat(signature,",javax.microedition.io.Connector.http");
    strcat(signature,",javax.microedition.io.Connector.https");
    strcat(signature,",javax.microedition.io.Connector.ssl");
    strcat(signature,",javax.microedition.io.Connector.socket");   
    strcat(signature,",javax.microedition.io.Connector.datagram");
    strcat(signature,",javax.microedition.io.Connector.serversocket");
    strcat(signature,",javax.microedition.io.Connector.datagramreceiver");
  }
  if (COMM==1)
    strcat(signature,",javax.microedition.io.Connector.comm");
  
  if (BLUETOOTH==1)
  {
    strcat(signature,",javax.microedition.io.Connector.bluetooth.client");
    strcat(signature,",javax.microedition.io.Connector.bluetooth.server");    
  }
  
  if (SMS==1)
  {
    strcat(signature,",javax.microedition.io.Connector.sms");
    strcat(signature,",javax.microedition.io.Connector.sms.send");   
    strcat(signature,",javax.microedition.io.Connector.sms.receive");
    strcat(signature,",javax.wireless.messaging.sms.receive");
    strcat(signature,",javax.wireless.messaging.sms.send");
  }
  
  if (MMS==1)
  {
    strcat(signature,",javax.microedition.io.Connector.mms");   
    strcat(signature,",javax.microedition.io.Connector.mms");
    strcat(signature,",javax.wireless.messaging.mms.receive");
    strcat(signature,",javax.wireless.messaging.mms.send"); 
  }
  
  if (MEDIA==1)
    strcat(signature,",javax.microedition.media.RecordControl.startRecord");  
  else if (MEDIA==2)
  {
    strcat(signature,",javax.microedition.media.control.RecordControl");  
    strcat(signature,",javax.microedition.media.control.VideoControl.getSnapshot");  
  }
  strcat(signature,eol);
  
  int f;
  unsigned int err;
  
  if ((f=fopen(jad_name,A_WriteOnly+A_BIN+A_Append,P_WRITE,&err))<0)
  {
    err_n=CANT_APPEND;
    goto L_ERR_FREE;
  }
  fwrite(f,signature,strlen(signature),&err);
  fclose(f,&err);
  err_n=DONE;
L_ERR_FREE:  
  mfree(signature);
  GeneralFuncF1(1);
  ErrMsg(err_n);
}

int unzip(char *compr, unsigned int comprLen, char *uncompr, unsigned int uncomprLen)
{
  int err;
  z_stream d_stream;
  d_stream.zalloc = (alloc_func)zcalloc;
  d_stream.zfree = (free_func)zcfree;
  d_stream.opaque = (voidpf)0;
  d_stream.next_in  = (Byte*)compr;
  d_stream.avail_in = (uInt)comprLen;
  err = inflateInit2(&d_stream,-MAX_WBITS);
  if(err!=Z_OK)
  {
    unerr:
      return err;
  }
  d_stream.next_out = (Byte*)uncompr;
  d_stream.avail_out = (uInt)uncomprLen;
  err = inflate(&d_stream, 2);
  if(err<0) goto unerr;
  err = inflateEnd(&d_stream);
  if(err<0) goto unerr;
  return 0;
}

char* find_manifest_mf(const char* jar, unsigned int fsize)
{
  int f;
  unsigned int err;
  char* buf;
  CENTRAL_ZIP* c_zip;
  LOCAL_ZIP* l_zip;
  EXTRA_FIELD* ex_field;
  char* fname;
  
  unsigned int compr_size,uncompr_size,offset;
  char* compr_data;
  char* uncompr_data;
  
  if((f=fopen(jar,A_ReadOnly+A_BIN,P_READ,&err))<0)
    return (0);
  buf=malloc(fsize+1);
  fread(f,buf,fsize,&err);
  fclose(f,&err);
  for(int n=0; n<fsize-3;n++)
  {
    if (buf[n]==0x50 && buf[n+1]==0x4b && buf[n+2]==0x01 && buf[n+3]==0x02)
    {
      c_zip=(CENTRAL_ZIP*)(buf+n);
      int len=c_zip->fname_len;
      fname=malloc(len+1);
      strncpy(fname,buf+n+sizeof(CENTRAL_ZIP),len);
      fname[len]=0;
      compr_data=strstr(fname,"MANIFEST.MF");
      mfree(fname);
      if (compr_data)
      {
        compr_size=c_zip->compr_size;
        uncompr_size=c_zip->uncompr_size;
        offset=c_zip->relative_offset;
        l_zip=(LOCAL_ZIP*)(buf+offset);
        offset+=sizeof(LOCAL_ZIP)+l_zip->fname_len;
        int ex_len=l_zip->extra_field_len;
        if(ex_len)
        {
          ex_field=(EXTRA_FIELD*)(buf+offset);
          offset+=ex_field->data_size+ex_len+2;
        }
        compr_data=malloc(compr_size);
        memcpy(compr_data,buf+offset,compr_size);
        mfree(buf);
        uncompr_data=malloc(uncompr_size+1);
        uncompr_data[uncompr_size]=0;
        unzip(compr_data,compr_size,uncompr_data,uncompr_size);
        mfree(compr_data);
        return (uncompr_data);
      }     
    }
  }
  mfree(buf);
  return (0);
}

void generate_jad(GUI *data)
{
  char jar_f[256];
  char jad_f[256];
  int f; 
  int fsize;
  char* p;
  char* manifest;
  char* jad;
  
  unsigned int err;
  ws_2str(jar_file,jar_f,255);
  
  if ((p=strstr(jar_f,".jar"))==NULL)
  {
    GeneralFuncF1(1);
    ErrMsg(BAD_JAR);
    return;
  }
  strcpy(jad_f,jar_f);
  strcpy(jad_f+(p-jar_f),".jad");
  
  if ((f=fopen(jad_f,A_ReadOnly+A_BIN,P_READ,&err))>=0)
  {
    fclose(f,&err);
    GeneralFuncF1(1);
    ErrMsg(JAD_ALREDY_EXISTS);
    return;
  }
  
  if ((fsize=get_file_size(jar_f))==-1)
  {
    GeneralFuncF1(1);
    ErrMsg(CANT_OPEN_JAR);
    return;
  }  
    
  if (!(manifest=find_manifest_mf(jar_f,fsize)))
  {
    GeneralFuncF1(1);
    ErrMsg(CANT_FIND_MANIFEST);
    return;
  }
  
  jad=malloc(strlen(manifest)+512);
  sprintf(jad,"MIDlet-Jar-Size: %u\r\nMIDlet-Jar-URL: %s\r\n",fsize,jar_f);
  strcat(jad,manifest);
  mfree(manifest);
  
  if ((f=fopen(jad_f,A_ReadWrite+A_Create+A_Truncate+A_BIN,P_READ+P_WRITE,&err))<0)
  {
    mfree(jad);
    GeneralFuncF1(1);
    ErrMsg(CANT_CREATE_JAD);
    return;
  }
  
  fwrite(f,jad,strlen(jad),&err);
  fclose(f,&err);
  mfree(jad);
  GeneralFuncF1(1);
  ErrMsg(DONE);
}

void remove_sign_from_jad(GUI *data)
{
  int f;
  unsigned int err;
  char* p;
  char* first;
  char* end;
  char fname[256];
  unsigned int fsize,fs;
  char* buf;
  ws_2str(jar_file,fname,255);
  int err_n;
  
  if ((p=strstr(fname,".jar"))==NULL)
  {
    err_n=BAD_JAR;
    goto L_ERR;
  }
  strcpy(p,".jad");
  if ((f=fopen(fname,A_ReadWrite+A_BIN,P_READ,&err))<0)
  {
    err_n=CANT_OPEN_JAD;
    goto L_ERR;
  }
  fs=fsize=lseek(f,0,S_END,&err,&err);
  if (!fsize)
  {
    err_n=SIZE_OF_JAD_NULL;
    goto L_ERR;
  }
  lseek(f,0,S_SET,&err,&err);
  buf=malloc(fsize+1);
  buf[fsize]=0;
  fread(f,buf,fsize,&err);
  
  if ((first=strstr(buf,midlet_cert)))
  {
    end=strstr(first,eol)+2;
    memcpy(first,end,buf+fsize-end+1);
    fsize-=end-first;
  }
  
  if ((first=strstr(buf,midlet_jar_rsa)))
  {
    end=strstr(first,eol)+2;
    memcpy(first,end,buf+fsize-end+1);
    fsize-=end-first;
  }
    
  if ((first=strstr(buf,midlet_permissions)))
  {
    end=strstr(first,eol)+2;
    memcpy(first,end,buf+fsize-end+1);
    fsize-=end-first;
  } 
  fclose(f,&err);
  
  if(fs==fsize)
  {
    mfree(buf);
    err_n=FILE_WAS_NOT_SIGNED;
    goto L_ERR;
  }
  
  f=fopen(fname,A_ReadWrite+A_Truncate+A_BIN,P_READ+P_WRITE,&err);
  fwrite(f,buf,fsize,&err);
  fclose(f,&err); 
  mfree(buf);
  err_n=DONE;
L_ERR:
  GeneralFuncF1(1);
  ErrMsg(err_n);
}

#define BUF_SIZE 128
void copy_certificate(GUI *data)
{
  char sname[128];
  char dname[128];
  char buf[BUF_SIZE];
  int rlen;
  unsigned int fsize;
  int sh,dh;
  unsigned int serr,derr;
  split_lines(sname,WORKFOLDER,DER_FILE);
  if((sh=fopen(sname,A_ReadOnly+A_BIN,P_READ,&serr))<0)
  {
    GeneralFuncF1(1);
    ErrMsg(CANT_OPEN_SFILE);
    return;
  }
  fsize=lseek(sh,0,S_END,&serr,&serr);
  lseek(sh,0,S_SET,&serr,&serr);
  split_lines(dname,certificate_store,DER_FILE);
  if ((dh=fopen(dname,A_WriteOnly+A_Create+A_Truncate+A_BIN,P_WRITE,&derr))<0)
  {
    fclose(sh,&serr);
    GeneralFuncF1(1);
    ErrMsg(CANT_OPEN_DFILE);
    return;
  }
  while (fsize)
  {
    rlen=fsize<BUF_SIZE?fsize:BUF_SIZE;
    fread(sh,buf,rlen,&serr);
    fwrite(dh,buf,rlen,&derr);
    fsize-=rlen;
  }
  fclose(sh,&serr);
  fclose(dh,&derr);
  GeneralFuncF1(1);
  ErrMsg(DONE);  
}

void free_sbp_list(SBP_LIST *sbp_top)
{
  SBP_LIST *prev;
  while (sbp_top)
  {
    prev=sbp_top;
    mfree(sbp_top->issuer);
    mfree(sbp_top->hash);
    sbp_top=sbp_top->next;
    mfree(prev);
  }
}


void create_sha1_cert(char *hash)
{
  int f;
  unsigned int err;
  char der_file[128];  
  int size;
  char buf[8];
  char *new_data;
  split_lines(der_file,certificate_store,DER_FILE);
  if ((f=fopen(der_file,A_ReadOnly+A_BIN,P_READ,&err))<0)
  {
    return;
  }
  fread(f,buf,8,&err);
  size=buf[6]*256+buf[7]+4;
  new_data=malloc(size);
  lseek(f,4,S_SET,&err,&err);
  fread(f,new_data,size,&err);
  fclose(f,&err);
  CreateSHA1Hash(hash,new_data,size);
  mfree(new_data);  
}
  
  
int verify_hash(char *hash)
{
  char new_hash[20];
  create_sha1_cert(new_hash);
  return ((memcmp(hash,new_hash,20))?MANUF_PATCHED_UNCORR:MANUF_ALR_PATCHED);  
}

int is_manufacturer_patched()
{
  int f;
  unsigned int err;
  int num;
  int len;
  SBP_FILE_SIG sbp_sig;
  char *issuer;
  char hash[20];
  int ret=0;
  if ((f=fopen(manufacturer_sbp,A_ReadOnly+A_BIN,P_READ,&err))<0)
  {
    return (CANT_OPEN_MANUFACTURER);  
  }
  fread(f,&sbp_sig,sizeof(SBP_FILE_SIG),&err);
  num=sbp_sig.cert_num;
  
  while(num)
  {
    fread(f,&len,sizeof(int),&err);
    issuer=malloc(len+1);
    issuer[len]=0;
    fread(f,issuer,len,&err);
    lseek(f,1,S_CUR,&err,&err);
    char *s=issuer;
    while((s=strchr(s,'=')))
    {
      s++;
      ret=strncmp_nocase(s,DER_FILE,strlen(DER_FILE)-4);
      if (!ret)
      {
        mfree(issuer);
        fread(f,hash,20,&err);
        fclose(f,&err);
        return (verify_hash(hash));
      }
    }
    mfree(issuer);
    lseek(f,20,S_CUR,&err,&err);
    num--;
  }
  fclose(f,&err);
  return (MANUF_NOT_PATCHED);
}

void remove_record_sbp(GUI *data)
{
  SBP_LIST *sbp_top=0; 
  SBP_LIST *sbp_list; 
  SBP_LIST *sbp_prev; 
  SBP_FILE_SIG sbp_sig;
  int fsize;
  int curpos;
  char *oldbuf;
  int oldsize;
  int num;
  int len;
  int f;
  unsigned int err;
  char *issuer;
  char *hash;
  num=is_manufacturer_patched();
  if (num!=MANUF_ALR_PATCHED&&num!=MANUF_PATCHED_UNCORR)
  {
    GeneralFuncF1(1);
    ErrMsg(num);
    return;
  }
  if ((f=fopen(manufacturer_sbp,A_ReadOnly+A_BIN,P_READ,&err))<0)
  {
    GeneralFuncF1(1);
    ErrMsg(CANT_OPEN_MANUFACTURER);
    return;  
  }
  fsize=lseek(f,0,S_END,&err,&err);
  lseek(f,0,S_SET,&err,&err);
  fread(f,&sbp_sig,sizeof(SBP_FILE_SIG),&err);
  num=sbp_sig.cert_num;
  while(num)
  {
    fread(f,&len,sizeof(int),&err);
    issuer=malloc(len+1);
    issuer[len]=0;
    fread(f,issuer,len,&err);
    lseek(f,1,S_CUR,&err,&err);
    hash=malloc(20);
    fread(f,hash,20,&err);
    char *s=issuer;
    while((s=strchr(s,'=')))
    {
      s++;
      if (!strncmp_nocase(s,DER_FILE,strlen(DER_FILE)-4))
        break;
    }
    if (!s)  
    {
      sbp_prev=malloc(sizeof(SBP_LIST));
      sbp_list=sbp_top?(sbp_list->next=sbp_prev):(sbp_top=sbp_prev);
      sbp_list->issuer=issuer;
      sbp_list->hash=hash;   
      sbp_list->next=0;
    }
    else  
    {
      mfree(issuer);
      mfree(hash);
    }
    num--;
  }
  curpos=lseek(f,0,S_CUR,&err,&err);  
  oldsize=fsize-curpos;               
  if(oldsize)                   
  {
    oldbuf=malloc(oldsize);
    fread(f,oldbuf,oldsize,&err);
  }
  fclose(f,&err);
  
  if ((f=fopen(manufacturer_sbp,A_WriteOnly+A_Truncate+A_BIN,P_WRITE,&err))==-1)
  {
    free_sbp_list(sbp_top);
    GeneralFuncF1(1);
    ErrMsg(CANT_WRITE_MANUFACTURER);
    return;  
  } 
  num=0;
  sbp_list=sbp_top;
  while(sbp_list)
  {
    num++;
    sbp_list=sbp_list->next;
  }
  sbp_list=sbp_top;
  sbp_sig.cert_num=num;
  fwrite(f,&sbp_sig,sizeof(SBP_FILE_SIG),&err);
  while(sbp_list)
  {
    len=strlen(sbp_list->issuer);
    fwrite(f,&len,sizeof(int),&err);
    fwrite(f,sbp_list->issuer,len,&err);
    fwrite(f,delimeter,1,&err);
    fwrite(f,sbp_list->hash,20,&err);
    mfree(sbp_list->issuer);
    mfree(sbp_list->hash);
    sbp_prev=sbp_list;
    sbp_list=sbp_list->next;
    mfree(sbp_prev);
  }
  if (oldsize)
  {
    fwrite(f,oldbuf,oldsize,&err);
    mfree(oldbuf);
  }
  fclose(f,&err);
  GeneralFuncF1(1);
  ErrMsg(DONE);  
}

void store_record_sbp(GUI *data)
{
  int ret;
  int f;
  unsigned int err;
  SBP_LIST *sbp_top=0; 
  SBP_LIST *sbp_list; 
  SBP_LIST *sbp_prev; 
  SBP_FILE_SIG sbp_sig;
  int fsize;
  int curpos;
  char *oldbuf;
  int oldsize;
  int len;
  int num;
  int clen;
  char *issuer;
  char *hash;
  char my_issuer[64];
  char der_file[32];
  char my_hash[20];
  if ((ret=is_manufacturer_patched())!=MANUF_NOT_PATCHED)
  {
    GeneralFuncF1(1);
    ErrMsg(ret);
    return;   
  }
  if ((f=fopen(manufacturer_sbp,A_ReadOnly+A_BIN,P_READ,&err))<0)
  {
    GeneralFuncF1(1);
    ErrMsg(CANT_OPEN_MANUFACTURER);
    return;  
  } 
  fsize=lseek(f,0,S_END,&err,&err);
  lseek(f,0,S_SET,&err,&err);
  fread(f,&sbp_sig,sizeof(SBP_FILE_SIG),&err);
  clen=num=sbp_sig.cert_num;
  while(clen)
  {
    fread(f,&len,sizeof(int),&err);
    issuer=malloc(len+1);
    fread(f,issuer,len,&err);
    issuer[len]=0;
    lseek(f,1,S_CUR,&err,&err);
    hash=malloc(20);
    fread(f,hash,20,&err);
    sbp_prev=malloc(sizeof(SBP_LIST));
    sbp_list=sbp_top?(sbp_list->next=sbp_prev):(sbp_top=sbp_prev);
    sbp_list->issuer=issuer;
    sbp_list->hash=hash;   
    sbp_list->next=0;    
    clen--;
  }
  curpos=lseek(f,0,S_CUR,&err,&err);  
  oldsize=fsize-curpos;               
  if(oldsize)                   
  {
    oldbuf=malloc(oldsize);
    fread(f,oldbuf,oldsize,&err);
  }
  fclose(f,&err);

  if ((f=fopen(manufacturer_sbp,A_WriteOnly+A_Truncate+A_BIN,P_WRITE,&err))<0)
  {
    free_sbp_list(sbp_top);
    GeneralFuncF1(1);
    ErrMsg(CANT_WRITE_MANUFACTURER);
    return;  
  } 
  sbp_list=sbp_top;
  sbp_sig.cert_num=num+1;
  fwrite(f,&sbp_sig,sizeof(SBP_FILE_SIG),&err);
  while(sbp_list)
  {
    len=strlen(sbp_list->issuer);
    fwrite(f,&len,sizeof(int),&err);
    fwrite(f,sbp_list->issuer,len,&err);
    fwrite(f,delimeter,1,&err);
    fwrite(f,sbp_list->hash,20,&err);
    mfree(sbp_list->issuer);
    mfree(sbp_list->hash);
    sbp_prev=sbp_list;
    sbp_list=sbp_list->next;
    mfree(sbp_prev);
  }
  len=strlen(DER_FILE);
  strncpy(der_file,DER_FILE,len-4);
  der_file[len-4]=0;
  len=snprintf(my_issuer,63,"CN=%s,O=www.Siemens-Club.org,C=SU",der_file);
  fwrite(f,&len,sizeof(int),&err);
  fwrite(f,my_issuer,len,&err);
  fwrite(f,delimeter,1,&err);
  create_sha1_cert(my_hash);
  fwrite(f,my_hash,20,&err);
  if (oldsize)
  {
    fwrite(f,oldbuf,oldsize,&err);
    mfree(oldbuf);
  }
  fclose(f,&err);
  GeneralFuncF1(1);
  ErrMsg(DONE);
}

void options_back(GUI *data)
{
  GeneralFuncF1(1);
}

int options_softkeys[]={0,1,2};
SOFTKEY_DESC options_menu_sk[]=
{
  {0x0018,0x0000,(int)""},
  {0x0001,0x0000,(int)"选择"},
  {0x003D,0x0000,(int)LGP_DOIT_PIC}
};

SOFTKEYSTAB options_menu_skt=
{
  options_menu_sk,0
};

HEADER_DESC options_menuhdr={0,0,0,0,NULL,(int)"选项",LGP_NULL};

MENUITEM_DESC options_menu_ITEMS[7]=
{
  {NULL,(int)"授权",                       LGP_NULL, 0, NULL, MENU_FLAG3, MENU_FLAG2},
  {NULL,(int)"创建JAD",               LGP_NULL, 0, NULL, MENU_FLAG3, MENU_FLAG2},
  {NULL,(int)"删除授权",           LGP_NULL, 0, NULL, MENU_FLAG3, MENU_FLAG2},
  {NULL,(int)"复制证书到Config盘", LGP_NULL, 0, NULL, MENU_FLAG3, MENU_FLAG2},
  {NULL,(int)"从.sbp删除记录",    LGP_NULL, 0, NULL, MENU_FLAG3, MENU_FLAG2},
  {NULL,(int)"储存记录到.sbp",       LGP_NULL, 0, NULL, MENU_FLAG3, MENU_FLAG2},
  {NULL,(int)"返回",                       LGP_NULL, 0, NULL, MENU_FLAG3, MENU_FLAG2},
};

const MENUPROCS_DESC options_menu_HNDLS[7]=
{
  sign_jad,
  generate_jad,
  remove_sign_from_jad,
  copy_certificate,
  remove_record_sbp,
  store_record_sbp,
  options_back,
};

const MENU_DESC options_menu_STRUCT=
{
  0,NULL,NULL,NULL,
  options_softkeys,
  &options_menu_skt,
  0x200+0x10,
  NULL,
  options_menu_ITEMS,   //Items
  options_menu_HNDLS,   //Procs
  7 //n
};

//flags 2:
//1 - with pics
//2 - don't show menu?
//4 
//0x10 - do scroll items
//0x40 - without scrollbar
//0x100 - do right align
//0x200 - with enum 
//0x400 - without delimeter



#pragma inline
void patch_header_small(HEADER_DESC* head)
{
  head->rc.x=3;
#ifndef ELKA
  head->rc.y=YDISP+0x18;
#else
  head->rc.y=YDISP+35;
#endif
  head->rc.x2=ScreenW()-3-1;
#ifndef ELKA
  head->rc.y2=YDISP+0x18+0x13;
#else 
    head->rc.y2=YDISP+35+34;
#endif
}

int CreateOptionsMenu()
{
  patch_header_small((HEADER_DESC*)(&options_menuhdr));
  return (CreateMenu(1,0,&options_menu_STRUCT,&options_menuhdr,0,7,0,0)); 
}


void Free_FLIST(void)
{
  LockSched();
  FLIST*fl=(FLIST*)fltop;
  fltop=0;
  UnlockSched();
  FLIST*fl_prev;
  while(fl)
  {
    fl_prev=fl;
    fl=fl->next;
    FreeWS(fl_prev->fullname);
    FreeWS(fl_prev->filename);
    mfree(fl_prev);
  }
}


FLIST* Fill_FLIST(FLIST*fl,char* full_name, char* file_name,int is_dir)
{
  FLIST*ftop=(FLIST*)fltop;
  int len;
  WSHDR *ws; 
  
  if (ftop)
  {
    fl->next=malloc(sizeof(FLIST));
    fl=fl->next;
  }
  else 
    fltop=fl=malloc(sizeof(FLIST));
  len=strlen(file_name);
  ws=AllocWS(len);
  str_2ws(ws,file_name,len);
  fl->filename=ws;
  
  len=strlen(full_name);
  ws=AllocWS(len);
  str_2ws(ws,full_name,len);
  fl->fullname=ws;  
  
  fl->next=0;
  fl->is_dir=is_dir;
  return fl;
}
  
  
int GetFoldersLevel(const char * fname)
{
  int i=0;
  while(*fname)
  {
    if (*fname++=='\\') i++;
  }
  return i;
}
    
       
void FindFiles(const char *path)
{
  FLIST * fl=(FLIST *)fltop;
  DIR_ENTRY de;
  unsigned int err;
  char name[256];
  char * ext;
  strcpy(name,path);
  strcat(name,"*");
  if (FindFirstFile(&de,name,&err))
  {
    do
    {
      strcpy(name,de.folder_name);
      strcat(name,"\\");
      strcat(name,de.file_name);
      if (de.file_attr&FA_DIRECTORY)
      {
        strcat(name,"\\");
        fl=Fill_FLIST(fl,name,de.file_name,1);
      }
      else
      {
        if((ext=strrchr(name,'.')))
        {
          if(!strncmp_nocase(ext+1,"jar",3))
            fl=Fill_FLIST(fl,name,de.file_name,0);
        }
      }
    }
    while(FindNextFile(&de,&err));
  }
  FindClose(&de,&err);
  
  int len;
  WSHDR *ws; 
  if (GetFoldersLevel(path)>=1)  // §?§а§Т§С§У§Э§с§Ц§Ю §б§Ц§в§Ц§з§а§Х §Я§С §е§в§а§У§Ц§Я§о §У§н§к§Ц
  {
    fl=malloc(sizeof(FLIST));
    fl->next=(FLIST*)fltop;
    ws=AllocWS(2);
    str_2ws(ws,"..",2);
    fl->filename=ws;
    
    strcpy(name,path);
    len=strlen(name);
    len--;
    while(name[len-1]!='\\')
      len--;
    name[len]=0;
    ws=AllocWS(len);
    str_2ws(ws,name,len);
    if (GetFoldersLevel(path)==1)
      switch(ws->wsbody[1])
      {
      case '0':
         ws->wsbody[1]='1';break;
      case '1':
         ws->wsbody[1]='2';break;
      case '2':
         ws->wsbody[1]='4';break;
      case '4':
         ws->wsbody[1]='0';break;
      }
    fl->fullname=ws;  
    fl->is_dir=1;
    fltop=fl;
  }
}


int menusoftkeys[]={0,1,2};
SOFTKEY_DESC menu_sk[]=
{
  {0x0018,0x0000,(int)"选择"},
  {0x0001,0x0000,(int)"关闭"},
  {0x003D,0x0000,(int)LGP_DOIT_PIC}
};

SOFTKEYSTAB menu_skt=
{
  menu_sk,0
};


void filelist_menu_iconhndl(void *data, int curitem, void *unk);
int filelist_menu_onkey(void *data, GUI_MSG *msg);
void filelist_menu_ghook(void *data, int cmd);

char header[25];
HEADER_DESC filelist_HDR={0,0,NULL,NULL,NULL,(int)header,LGP_NULL};


MENU_DESC filelist_STRUCT=
{
  8,filelist_menu_onkey,filelist_menu_ghook,NULL,
  menusoftkeys,
  &menu_skt,
  1+0x10,
  filelist_menu_iconhndl,
  NULL,   //Items
  NULL,   //Procs
  0   //n
};


FLIST *FindFLISTtByN(int n)
{
  FLIST *fl=(FLIST *)fltop;
  int i=0;
  while(fl&&(i!=n))
  {
    fl=fl->next;
    i++;
  }
  return fl;
}

#pragma inline
int GetIconIndex(FLIST *t)
{
  return t->is_dir;
}

void create_menu_folder(void)
{
  Free_FLIST();
  int i=0;
  FLIST* fl;
  FindFiles(folder);
  fl=(FLIST*)fltop;
  while(fl)
  {
    fl=fl->next;
    i++;
  }
  if (!i) return; 
  patch_header(&filelist_HDR);
  strncpy(header,folder,24);
  patch_header(&filelist_HDR);
  filelist_menu_id=CreateMenu(0,0,&filelist_STRUCT,&filelist_HDR,0,i,0,0);
}

void remake_filelist();
void create_view(int n)
{ 
  FLIST* fl;
  fl=FindFLISTtByN(n);
  if (fl->is_dir)
  {
    ws_2str(fl->fullname,(char*)(&folder),128);
    remake_filelist();
  }
  else
  {
    wstrcpy(jar_file,fl->fullname);
    GeneralFunc_flag1(filelist_menu_id,1);
  }
}
  
void filelist_menu_iconhndl(void *data, int curitem, void *unk)
{
  FLIST *t;
  WSHDR *ws;
  void *item=AllocMenuItem(data);
  
  t=FindFLISTtByN(curitem);
  if (t)
  {
    ws=AllocMenuWS(data,wslen(t->filename));
    wstrcpy(ws,t->filename);
  }
  else
  {
    ws=AllocMenuWS(data,10);
    wsprintf(ws,"%t","错误");
  }
  SetMenuItemIconArray(data,item,S_ICONS);
  SetMenuItemText(data,item,ws,curitem);
  SetMenuItemIcon(data,curitem,GetIconIndex(t));
}

int filelist_menu_onkey(void *data, GUI_MSG *msg)
{
  int keycode=msg->keys;
  int i=GetCurMenuItem(data);
  if (keycode==0x3D||keycode==0x18)
  {
    create_view(i);
    return(-1);
  } 
  return(0);
}

void filelist_menu_ghook(void *data, int cmd)
{
  if (cmd==0x0A)
  {
    DisableIDLETMR();
  }
}


void remake_filelist(void)
{
  if (filelist_menu_id)
  {
    request_remake_filelist=1;
    if (IsGuiOnTop(filelist_menu_id))
    {
      GeneralFunc_flag1(filelist_menu_id,1);
    }
    else
    {
      request_close_filelist=1;
    }
  }
  else
  {
    create_menu_folder();
  }
}

SOFTKEY_DESC edit_sk[]=
{
  {0x0018,0x0000,(int)"选项"},
  {0x0001,0x0000,(int)"关闭"},
  {0x003D,0x0000,(int)LGP_DOIT_PIC}
};

SOFTKEYSTAB edit_skt=
{
  edit_sk,0
};  


void ed1_ghook(GUI *data, int cmd)
{
  int i;
  if (cmd==7)
  {
    SetSoftKey(data,&edit_sk[0],0);
    SetSoftKey(data,&edit_sk[1],1);
    i=EDIT_GetFocus(data);
    switch(i)
    {
    case 2:
      EDIT_SetTextToFocused(data,jar_file);  
    }
  }
  else if (cmd==0x0A)
  {
    DisableIDLETMR();
  }
}


int ed1_onkey(GUI *data, GUI_MSG *msg)
{
  int i;
  int l;
  if (msg->gbsmsg->msg==KEY_DOWN)
  {
    l=msg->gbsmsg->submess;
    switch(l)
    {
    case ENTER_BUTTON:
      i=EDIT_GetFocus(data);
      switch(i)
      {
      case 2:
        create_menu_folder();
        return (-1);
      }
      
    case LEFT_SOFT:
      CreateOptionsMenu();
      return(-1);
    }
  }
  return(0); //Do standart keys
  //1: close
}


  
HEADER_DESC ed1_hdr={0,0,0,0,NULL,(int)"Midlet Sign",LGP_NULL};

INPUTDIA_DESC ed1_desc=
{
  1,
  ed1_onkey,
  ed1_ghook,
  (void *)ed1_locret,
  0,
  &edit_skt,
  {0,0,0,0},
  4,
  100,
  101,
  0,
  0,
#ifdef NEWSGOLD
  0
#else
  0x40000000
#endif
};

int CreateMainMenu(void)
{
  void *ma=malloc_adr();
  void *eq;
  EDITCONTROL ec;
  WSHDR *head;
  
  PrepareEditControl(&ec);
  eq=AllocEQueue(ma,mfree_adr());
  head=AllocWS(50);
  wsprintf(head,"%t:","Jar文件");
  ConstructEditControl(&ec,1,0x40,head,wslen(head));
  AddEditControlToEditQend(eq,&ec,ma);
  
  str_2ws(jar_file,folder,255);  
  ConstructEditControl(&ec,8,0x40,jar_file,255);
  AddEditControlToEditQend(eq,&ec,ma); 
 
  patch_header(&ed1_hdr);
  patch_input(&ed1_desc);
  FreeWS(head);
  return (CreateInputTextDialog(&ed1_desc,&ed1_hdr,eq,1,0));
}



void maincsm_oncreate(CSM_RAM *data)
{
  MAIN_CSM *csm=(MAIN_CSM*)data;
  jar_file=AllocWS(256);
  csm->gui_id=CreateMainMenu();
}

void maincsm_onclose(CSM_RAM *csm)
{
  Free_FLIST();
  FreeWS(jar_file);
  SUBPROC((void *)ElfKiller);
}


int maincsm_onmessage(CSM_RAM *data, GBS_MSG *msg)
{
  MAIN_CSM *csm=(MAIN_CSM*)data;
  if (msg->msg==MSG_GUI_DESTROYED)
  {
    if ((int)msg->data0==csm->gui_id)
    {
      csm->csm.state=-3;
    }
    if ((int)msg->data0==filelist_menu_id)
    {
      filelist_menu_id=0;
      if (request_remake_filelist)
      {
        request_remake_filelist=0;
        create_menu_folder();
      }
    }    
  }
  return(1);
}


const struct
{
  CSM_DESC maincsm;
  WSHDR maincsm_name;
}MAINCSM =
{
  {
  maincsm_onmessage,
  maincsm_oncreate,
#ifdef NEWSGOLD
  0,
  0,
  0,
  0,
#endif
  maincsm_onclose,
  sizeof(MAIN_CSM),
  1,
  &minus11
  },
  {
    maincsm_name_body,
    NAMECSM_MAGIC1,
    NAMECSM_MAGIC2,
    0x0,
    19
  }
};

void UpdateCSMname(void)
{
  wsprintf((WSHDR *)(&MAINCSM.maincsm_name),"MidletSigner");
}

int main()
{
  InitConfig();
  S_ICONS[0]=(int)JAR_ICON;
  S_ICONS[1]=(int)FOLDER_ICON;
  S_ICONS[2]=0;
  MAIN_CSM csm;
  UpdateCSMname();
  LockSched();
  CreateCSM(&MAINCSM.maincsm,&csm,0);
  UnlockSched();
}

