diff options
author | Kenny Root <kenny@the-b.org> | 2014-10-01 23:04:51 +0100 |
---|---|---|
committer | Kenny Root <kenny@the-b.org> | 2014-10-01 12:48:19 +0100 |
commit | 49b779dcaf03e3598d2709b321e20ea029b25163 (patch) | |
tree | 05af547b1f1433d7dd6f7373d0b25a455e053a03 /src | |
parent | d64786d9197090c74072b648e487e3d34817bb57 (diff) | |
download | connectbot-49b779dcaf03e3598d2709b321e20ea029b25163.tar.gz connectbot-49b779dcaf03e3598d2709b321e20ea029b25163.tar.bz2 connectbot-49b779dcaf03e3598d2709b321e20ea029b25163.zip |
Convert to gradle build system
Diffstat (limited to 'src')
220 files changed, 0 insertions, 50982 deletions
diff --git a/src/com/google/ase/Exec.java b/src/com/google/ase/Exec.java deleted file mode 100644 index 016fdf3..0000000 --- a/src/com/google/ase/Exec.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.ase; - -import java.io.FileDescriptor; - -/** - * Tools for executing commands. - */ -public class Exec { - /** - * @param cmd - * The command to execute - * @param arg0 - * The first argument to the command, may be null - * @param arg1 - * the second argument to the command, may be null - * @return the file descriptor of the started process. - * - */ - public static FileDescriptor createSubprocess(String cmd, String arg0, String arg1) { - return createSubprocess(cmd, arg0, arg1, null); - } - - /** - * @param cmd - * The command to execute - * @param arg0 - * The first argument to the command, may be null - * @param arg1 - * the second argument to the command, may be null - * @param processId - * A one-element array to which the process ID of the started process will be written. - * @return the file descriptor of the started process. - * - */ - public static native FileDescriptor createSubprocess(String cmd, String arg0, String arg1, - int[] processId); - - public static native void setPtyWindowSize(FileDescriptor fd, int row, int col, int xpixel, - int ypixel); - - /** - * Causes the calling thread to wait for the process associated with the receiver to finish - * executing. - * - * @return The exit value of the Process being waited on - * - */ - public static native int waitFor(int processId); - - static { - System.loadLibrary("com_google_ase_Exec"); - } -} diff --git a/src/com/jcraft/jzlib/Adler32.java b/src/com/jcraft/jzlib/Adler32.java deleted file mode 100644 index d8b6ef8..0000000 --- a/src/com/jcraft/jzlib/Adler32.java +++ /dev/null @@ -1,94 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final class Adler32{ - - // largest prime smaller than 65536 - static final private int BASE=65521; - // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 - static final private int NMAX=5552; - - long adler32(long adler, byte[] buf, int index, int len){ - if(buf == null){ return 1L; } - - long s1=adler&0xffff; - long s2=(adler>>16)&0xffff; - int k; - - while(len > 0) { - k=len<NMAX?len:NMAX; - len-=k; - while(k>=16){ - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - s1+=buf[index++]&0xff; s2+=s1; - k-=16; - } - if(k!=0){ - do{ - s1+=buf[index++]&0xff; s2+=s1; - } - while(--k!=0); - } - s1%=BASE; - s2%=BASE; - } - return (s2<<16)|s1; - } - - /* - private java.util.zip.Adler32 adler=new java.util.zip.Adler32(); - long adler32(long value, byte[] buf, int index, int len){ - if(value==1) {adler.reset();} - if(buf==null) {adler.reset();} - else{adler.update(buf, index, len);} - return adler.getValue(); - } - */ -} diff --git a/src/com/jcraft/jzlib/Deflate.java b/src/com/jcraft/jzlib/Deflate.java deleted file mode 100644 index 9978802..0000000 --- a/src/com/jcraft/jzlib/Deflate.java +++ /dev/null @@ -1,1623 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -public -final class Deflate{ - - static final private int MAX_MEM_LEVEL=9; - - static final private int Z_DEFAULT_COMPRESSION=-1; - - static final private int MAX_WBITS=15; // 32K LZ77 window - static final private int DEF_MEM_LEVEL=8; - - static class Config{ - int good_length; // reduce lazy search above this match length - int max_lazy; // do not perform lazy search above this match length - int nice_length; // quit search above this match length - int max_chain; - int func; - Config(int good_length, int max_lazy, - int nice_length, int max_chain, int func){ - this.good_length=good_length; - this.max_lazy=max_lazy; - this.nice_length=nice_length; - this.max_chain=max_chain; - this.func=func; - } - } - - static final private int STORED=0; - static final private int FAST=1; - static final private int SLOW=2; - static final private Config[] config_table; - static{ - config_table=new Config[10]; - // good lazy nice chain - config_table[0]=new Config(0, 0, 0, 0, STORED); - config_table[1]=new Config(4, 4, 8, 4, FAST); - config_table[2]=new Config(4, 5, 16, 8, FAST); - config_table[3]=new Config(4, 6, 32, 32, FAST); - - config_table[4]=new Config(4, 4, 16, 16, SLOW); - config_table[5]=new Config(8, 16, 32, 32, SLOW); - config_table[6]=new Config(8, 16, 128, 128, SLOW); - config_table[7]=new Config(8, 32, 128, 256, SLOW); - config_table[8]=new Config(32, 128, 258, 1024, SLOW); - config_table[9]=new Config(32, 258, 258, 4096, SLOW); - } - - static final private String[] z_errmsg = { - "need dictionary", // Z_NEED_DICT 2 - "stream end", // Z_STREAM_END 1 - "", // Z_OK 0 - "file error", // Z_ERRNO (-1) - "stream error", // Z_STREAM_ERROR (-2) - "data error", // Z_DATA_ERROR (-3) - "insufficient memory", // Z_MEM_ERROR (-4) - "buffer error", // Z_BUF_ERROR (-5) - "incompatible version",// Z_VERSION_ERROR (-6) - "" - }; - - // block not completed, need more input or more output - static final private int NeedMore=0; - - // block flush performed - static final private int BlockDone=1; - - // finish started, need only more output at next deflate - static final private int FinishStarted=2; - - // finish done, accept no more input or output - static final private int FinishDone=3; - - // preset dictionary flag in zlib header - static final private int PRESET_DICT=0x20; - - static final private int Z_FILTERED=1; - static final private int Z_HUFFMAN_ONLY=2; - static final private int Z_DEFAULT_STRATEGY=0; - - static final private int Z_NO_FLUSH=0; - static final private int Z_PARTIAL_FLUSH=1; - static final private int Z_SYNC_FLUSH=2; - static final private int Z_FULL_FLUSH=3; - static final private int Z_FINISH=4; - - static final private int Z_OK=0; - static final private int Z_STREAM_END=1; - static final private int Z_NEED_DICT=2; - static final private int Z_ERRNO=-1; - static final private int Z_STREAM_ERROR=-2; - static final private int Z_DATA_ERROR=-3; - static final private int Z_MEM_ERROR=-4; - static final private int Z_BUF_ERROR=-5; - static final private int Z_VERSION_ERROR=-6; - - static final private int INIT_STATE=42; - static final private int BUSY_STATE=113; - static final private int FINISH_STATE=666; - - // The deflate compression method - static final private int Z_DEFLATED=8; - - static final private int STORED_BLOCK=0; - static final private int STATIC_TREES=1; - static final private int DYN_TREES=2; - - // The three kinds of block type - static final private int Z_BINARY=0; - static final private int Z_ASCII=1; - static final private int Z_UNKNOWN=2; - - static final private int Buf_size=8*2; - - // repeat previous bit length 3-6 times (2 bits of repeat count) - static final private int REP_3_6=16; - - // repeat a zero length 3-10 times (3 bits of repeat count) - static final private int REPZ_3_10=17; - - // repeat a zero length 11-138 times (7 bits of repeat count) - static final private int REPZ_11_138=18; - - static final private int MIN_MATCH=3; - static final private int MAX_MATCH=258; - static final private int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1); - - static final private int MAX_BITS=15; - static final private int D_CODES=30; - static final private int BL_CODES=19; - static final private int LENGTH_CODES=29; - static final private int LITERALS=256; - static final private int L_CODES=(LITERALS+1+LENGTH_CODES); - static final private int HEAP_SIZE=(2*L_CODES+1); - - static final private int END_BLOCK=256; - - ZStream strm; // pointer back to this zlib stream - int status; // as the name implies - byte[] pending_buf; // output still pending - int pending_buf_size; // size of pending_buf - int pending_out; // next pending byte to output to the stream - int pending; // nb of bytes in the pending buffer - int noheader; // suppress zlib header and adler32 - byte data_type; // UNKNOWN, BINARY or ASCII - byte method; // STORED (for zip only) or DEFLATED - int last_flush; // value of flush param for previous deflate call - - int w_size; // LZ77 window size (32K by default) - int w_bits; // log2(w_size) (8..16) - int w_mask; // w_size - 1 - - byte[] window; - // Sliding window. Input bytes are read into the second half of the window, - // and move to the first half later to keep a dictionary of at least wSize - // bytes. With this organization, matches are limited to a distance of - // wSize-MAX_MATCH bytes, but this ensures that IO is always - // performed with a length multiple of the block size. Also, it limits - // the window size to 64K, which is quite useful on MSDOS. - // To do: use the user input buffer as sliding window. - - int window_size; - // Actual size of window: 2*wSize, except when the user input buffer - // is directly used as sliding window. - - short[] prev; - // Link to older string with same hash index. To limit the size of this - // array to 64K, this link is maintained only for the last 32K strings. - // An index in this array is thus a window index modulo 32K. - - short[] head; // Heads of the hash chains or NIL. - - int ins_h; // hash index of string to be inserted - int hash_size; // number of elements in hash table - int hash_bits; // log2(hash_size) - int hash_mask; // hash_size-1 - - // Number of bits by which ins_h must be shifted at each input - // step. It must be such that after MIN_MATCH steps, the oldest - // byte no longer takes part in the hash key, that is: - // hash_shift * MIN_MATCH >= hash_bits - int hash_shift; - - // Window position at the beginning of the current output block. Gets - // negative when the window is moved backwards. - - int block_start; - - int match_length; // length of best match - int prev_match; // previous match - int match_available; // set if previous match exists - int strstart; // start of string to insert - int match_start; // start of matching string - int lookahead; // number of valid bytes ahead in window - - // Length of the best match at previous step. Matches not greater than this - // are discarded. This is used in the lazy match evaluation. - int prev_length; - - // To speed up deflation, hash chains are never searched beyond this - // length. A higher limit improves compression ratio but degrades the speed. - int max_chain_length; - - // Attempt to find a better match only when the current match is strictly - // smaller than this value. This mechanism is used only for compression - // levels >= 4. - int max_lazy_match; - - // Insert new strings in the hash table only if the match length is not - // greater than this length. This saves time but degrades compression. - // max_insert_length is used only for compression levels <= 3. - - int level; // compression level (1..9) - int strategy; // favor or force Huffman coding - - // Use a faster search when the previous match is longer than this - int good_match; - - // Stop searching when current match exceeds this - int nice_match; - - short[] dyn_ltree; // literal and length tree - short[] dyn_dtree; // distance tree - short[] bl_tree; // Huffman tree for bit lengths - - Tree l_desc=new Tree(); // desc for literal tree - Tree d_desc=new Tree(); // desc for distance tree - Tree bl_desc=new Tree(); // desc for bit length tree - - // number of codes at each bit length for an optimal tree - short[] bl_count=new short[MAX_BITS+1]; - - // heap used to build the Huffman trees - int[] heap=new int[2*L_CODES+1]; - - int heap_len; // number of elements in the heap - int heap_max; // element of largest frequency - // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - // The same heap array is used to build all trees. - - // Depth of each subtree used as tie breaker for trees of equal frequency - byte[] depth=new byte[2*L_CODES+1]; - - int l_buf; // index for literals or lengths */ - - // Size of match buffer for literals/lengths. There are 4 reasons for - // limiting lit_bufsize to 64K: - // - frequencies can be kept in 16 bit counters - // - if compression is not successful for the first block, all input - // data is still in the window so we can still emit a stored block even - // when input comes from standard input. (This can also be done for - // all blocks if lit_bufsize is not greater than 32K.) - // - if compression is not successful for a file smaller than 64K, we can - // even emit a stored file instead of a stored block (saving 5 bytes). - // This is applicable only for zip (not gzip or zlib). - // - creating new Huffman trees less frequently may not provide fast - // adaptation to changes in the input data statistics. (Take for - // example a binary file with poorly compressible code followed by - // a highly compressible string table.) Smaller buffer sizes give - // fast adaptation but have of course the overhead of transmitting - // trees more frequently. - // - I can't count above 4 - int lit_bufsize; - - int last_lit; // running index in l_buf - - // Buffer for distances. To simplify the code, d_buf and l_buf have - // the same number of elements. To use different lengths, an extra flag - // array would be necessary. - - int d_buf; // index of pendig_buf - - int opt_len; // bit length of current block with optimal trees - int static_len; // bit length of current block with static trees - int matches; // number of string matches in current block - int last_eob_len; // bit length of EOB code for last block - - // Output buffer. bits are inserted starting at the bottom (least - // significant bits). - short bi_buf; - - // Number of valid bits in bi_buf. All bits above the last valid bit - // are always zero. - int bi_valid; - - Deflate(){ - dyn_ltree=new short[HEAP_SIZE*2]; - dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree - bl_tree=new short[(2*BL_CODES+1)*2]; // Huffman tree for bit lengths - } - - void lm_init() { - window_size=2*w_size; - - head[hash_size-1]=0; - for(int i=0; i<hash_size-1; i++){ - head[i]=0; - } - - // Set the default configuration parameters: - max_lazy_match = Deflate.config_table[level].max_lazy; - good_match = Deflate.config_table[level].good_length; - nice_match = Deflate.config_table[level].nice_length; - max_chain_length = Deflate.config_table[level].max_chain; - - strstart = 0; - block_start = 0; - lookahead = 0; - match_length = prev_length = MIN_MATCH-1; - match_available = 0; - ins_h = 0; - } - - // Initialize the tree data structures for a new zlib stream. - void tr_init(){ - - l_desc.dyn_tree = dyn_ltree; - l_desc.stat_desc = StaticTree.static_l_desc; - - d_desc.dyn_tree = dyn_dtree; - d_desc.stat_desc = StaticTree.static_d_desc; - - bl_desc.dyn_tree = bl_tree; - bl_desc.stat_desc = StaticTree.static_bl_desc; - - bi_buf = 0; - bi_valid = 0; - last_eob_len = 8; // enough lookahead for inflate - - // Initialize the first block of the first file: - init_block(); - } - - void init_block(){ - // Initialize the trees. - for(int i = 0; i < L_CODES; i++) dyn_ltree[i*2] = 0; - for(int i= 0; i < D_CODES; i++) dyn_dtree[i*2] = 0; - for(int i= 0; i < BL_CODES; i++) bl_tree[i*2] = 0; - - dyn_ltree[END_BLOCK*2] = 1; - opt_len = static_len = 0; - last_lit = matches = 0; - } - - // Restore the heap property by moving down the tree starting at node k, - // exchanging a node with the smallest of its two sons if necessary, stopping - // when the heap property is re-established (each father smaller than its - // two sons). - void pqdownheap(short[] tree, // the tree to restore - int k // node to move down - ){ - int v = heap[k]; - int j = k << 1; // left son of k - while (j <= heap_len) { - // Set j to the smallest of the two sons: - if (j < heap_len && - smaller(tree, heap[j+1], heap[j], depth)){ - j++; - } - // Exit if v is smaller than both sons - if(smaller(tree, v, heap[j], depth)) break; - - // Exchange v with the smallest son - heap[k]=heap[j]; k = j; - // And continue down the tree, setting j to the left son of k - j <<= 1; - } - heap[k] = v; - } - - static boolean smaller(short[] tree, int n, int m, byte[] depth){ - short tn2=tree[n*2]; - short tm2=tree[m*2]; - return (tn2<tm2 || - (tn2==tm2 && depth[n] <= depth[m])); - } - - // Scan a literal or distance tree to determine the frequencies of the codes - // in the bit length tree. - void scan_tree (short[] tree,// the tree to be scanned - int max_code // and its largest code of non zero frequency - ){ - int n; // iterates over all tree elements - int prevlen = -1; // last emitted length - int curlen; // length of current code - int nextlen = tree[0*2+1]; // length of next code - int count = 0; // repeat count of the current code - int max_count = 7; // max repeat count - int min_count = 4; // min repeat count - - if (nextlen == 0){ max_count = 138; min_count = 3; } - tree[(max_code+1)*2+1] = (short)0xffff; // guard - - for(n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[(n+1)*2+1]; - if(++count < max_count && curlen == nextlen) { - continue; - } - else if(count < min_count) { - bl_tree[curlen*2] += count; - } - else if(curlen != 0) { - if(curlen != prevlen) bl_tree[curlen*2]++; - bl_tree[REP_3_6*2]++; - } - else if(count <= 10) { - bl_tree[REPZ_3_10*2]++; - } - else{ - bl_tree[REPZ_11_138*2]++; - } - count = 0; prevlen = curlen; - if(nextlen == 0) { - max_count = 138; min_count = 3; - } - else if(curlen == nextlen) { - max_count = 6; min_count = 3; - } - else{ - max_count = 7; min_count = 4; - } - } - } - - // Construct the Huffman tree for the bit lengths and return the index in - // bl_order of the last bit length code to send. - int build_bl_tree(){ - int max_blindex; // index of last bit length code of non zero freq - - // Determine the bit length frequencies for literal and distance trees - scan_tree(dyn_ltree, l_desc.max_code); - scan_tree(dyn_dtree, d_desc.max_code); - - // Build the bit length tree: - bl_desc.build_tree(this); - // opt_len now includes the length of the tree representations, except - // the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - - // Determine the number of bit length codes to send. The pkzip format - // requires that at least 4 bit length codes be sent. (appnote.txt says - // 3 but the actual value used is 4.) - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break; - } - // Update opt_len to include the bit length tree and counts - opt_len += 3*(max_blindex+1) + 5+5+4; - - return max_blindex; - } - - - // Send the header for a block using dynamic Huffman trees: the counts, the - // lengths of the bit length codes, the literal tree and the distance tree. - // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - void send_all_trees(int lcodes, int dcodes, int blcodes){ - int rank; // index in bl_order - - send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt - send_bits(dcodes-1, 5); - send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt - for (rank = 0; rank < blcodes; rank++) { - send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3); - } - send_tree(dyn_ltree, lcodes-1); // literal tree - send_tree(dyn_dtree, dcodes-1); // distance tree - } - - // Send a literal or distance tree in compressed form, using the codes in - // bl_tree. - void send_tree (short[] tree,// the tree to be sent - int max_code // and its largest code of non zero frequency - ){ - int n; // iterates over all tree elements - int prevlen = -1; // last emitted length - int curlen; // length of current code - int nextlen = tree[0*2+1]; // length of next code - int count = 0; // repeat count of the current code - int max_count = 7; // max repeat count - int min_count = 4; // min repeat count - - if (nextlen == 0){ max_count = 138; min_count = 3; } - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[(n+1)*2+1]; - if(++count < max_count && curlen == nextlen) { - continue; - } - else if(count < min_count) { - do { send_code(curlen, bl_tree); } while (--count != 0); - } - else if(curlen != 0){ - if(curlen != prevlen){ - send_code(curlen, bl_tree); count--; - } - send_code(REP_3_6, bl_tree); - send_bits(count-3, 2); - } - else if(count <= 10){ - send_code(REPZ_3_10, bl_tree); - send_bits(count-3, 3); - } - else{ - send_code(REPZ_11_138, bl_tree); - send_bits(count-11, 7); - } - count = 0; prevlen = curlen; - if(nextlen == 0){ - max_count = 138; min_count = 3; - } - else if(curlen == nextlen){ - max_count = 6; min_count = 3; - } - else{ - max_count = 7; min_count = 4; - } - } - } - - // Output a byte on the stream. - // IN assertion: there is enough room in pending_buf. - final void put_byte(byte[] p, int start, int len){ - System.arraycopy(p, start, pending_buf, pending, len); - pending+=len; - } - - final void put_byte(byte c){ - pending_buf[pending++]=c; - } - final void put_short(int w) { - put_byte((byte)(w/*&0xff*/)); - put_byte((byte)(w>>>8)); - } - final void putShortMSB(int b){ - put_byte((byte)(b>>8)); - put_byte((byte)(b/*&0xff*/)); - } - - final void send_code(int c, short[] tree){ - int c2=c*2; - send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff)); - } - - void send_bits(int value, int length){ - int len = length; - if (bi_valid > (int)Buf_size - len) { - int val = value; -// bi_buf |= (val << bi_valid); - bi_buf |= ((val << bi_valid)&0xffff); - put_short(bi_buf); - bi_buf = (short)(val >>> (Buf_size - bi_valid)); - bi_valid += len - Buf_size; - } else { -// bi_buf |= (value) << bi_valid; - bi_buf |= (((value) << bi_valid)&0xffff); - bi_valid += len; - } - } - - // Send one empty static block to give enough lookahead for inflate. - // This takes 10 bits, of which 7 may remain in the bit buffer. - // The current inflate code requires 9 bits of lookahead. If the - // last two codes for the previous block (real code plus EOB) were coded - // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - // the last real code. In this case we send two empty static blocks instead - // of one. (There are no problems if the previous block is stored or fixed.) - // To simplify the code, we assume the worst case of last real code encoded - // on one bit only. - void _tr_align(){ - send_bits(STATIC_TREES<<1, 3); - send_code(END_BLOCK, StaticTree.static_ltree); - - bi_flush(); - - // Of the 10 bits for the empty block, we have already sent - // (10 - bi_valid) bits. The lookahead for the last real code (before - // the EOB of the previous block) was thus at least one plus the length - // of the EOB plus what we have just sent of the empty static block. - if (1 + last_eob_len + 10 - bi_valid < 9) { - send_bits(STATIC_TREES<<1, 3); - send_code(END_BLOCK, StaticTree.static_ltree); - bi_flush(); - } - last_eob_len = 7; - } - - - // Save the match info and tally the frequency counts. Return true if - // the current block must be flushed. - boolean _tr_tally (int dist, // distance of matched string - int lc // match length-MIN_MATCH or unmatched char (if dist==0) - ){ - - pending_buf[d_buf+last_lit*2] = (byte)(dist>>>8); - pending_buf[d_buf+last_lit*2+1] = (byte)dist; - - pending_buf[l_buf+last_lit] = (byte)lc; last_lit++; - - if (dist == 0) { - // lc is the unmatched char - dyn_ltree[lc*2]++; - } - else { - matches++; - // Here, lc is the match length - MIN_MATCH - dist--; // dist = match distance - 1 - dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++; - dyn_dtree[Tree.d_code(dist)*2]++; - } - - if ((last_lit & 0x1fff) == 0 && level > 2) { - // Compute an upper bound for the compressed length - int out_length = last_lit*8; - int in_length = strstart - block_start; - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (int)dyn_dtree[dcode*2] * - (5L+Tree.extra_dbits[dcode]); - } - out_length >>>= 3; - if ((matches < (last_lit/2)) && out_length < in_length/2) return true; - } - - return (last_lit == lit_bufsize-1); - // We avoid equality with lit_bufsize because of wraparound at 64K - // on 16 bit machines and because stored blocks are restricted to - // 64K-1 bytes. - } - - // Send the block data compressed using the given Huffman trees - void compress_block(short[] ltree, short[] dtree){ - int dist; // distance of matched string - int lc; // match length or unmatched char (if dist == 0) - int lx = 0; // running index in l_buf - int code; // the code to send - int extra; // number of extra bits to send - - if (last_lit != 0){ - do{ - dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)| - (pending_buf[d_buf+lx*2+1]&0xff); - lc=(pending_buf[l_buf+lx])&0xff; lx++; - - if(dist == 0){ - send_code(lc, ltree); // send a literal byte - } - else{ - // Here, lc is the match length - MIN_MATCH - code = Tree._length_code[lc]; - - send_code(code+LITERALS+1, ltree); // send the length code - extra = Tree.extra_lbits[code]; - if(extra != 0){ - lc -= Tree.base_length[code]; - send_bits(lc, extra); // send the extra length bits - } - dist--; // dist is now the match distance - 1 - code = Tree.d_code(dist); - - send_code(code, dtree); // send the distance code - extra = Tree.extra_dbits[code]; - if (extra != 0) { - dist -= Tree.base_dist[code]; - send_bits(dist, extra); // send the extra distance bits - } - } // literal or match pair ? - - // Check that the overlay between pending_buf and d_buf+l_buf is ok: - } - while (lx < last_lit); - } - - send_code(END_BLOCK, ltree); - last_eob_len = ltree[END_BLOCK*2+1]; - } - - // Set the data type to ASCII or BINARY, using a crude approximation: - // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - // IN assertion: the fields freq of dyn_ltree are set and the total of all - // frequencies does not exceed 64K (to fit in an int on 16 bit machines). - void set_data_type(){ - int n = 0; - int ascii_freq = 0; - int bin_freq = 0; - while(n<7){ bin_freq += dyn_ltree[n*2]; n++;} - while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;} - while(n<LITERALS){ bin_freq += dyn_ltree[n*2]; n++;} - data_type=(byte)(bin_freq > (ascii_freq >>> 2) ? Z_BINARY : Z_ASCII); - } - - // Flush the bit buffer, keeping at most 7 bits in it. - void bi_flush(){ - if (bi_valid == 16) { - put_short(bi_buf); - bi_buf=0; - bi_valid=0; - } - else if (bi_valid >= 8) { - put_byte((byte)bi_buf); - bi_buf>>>=8; - bi_valid-=8; - } - } - - // Flush the bit buffer and align the output on a byte boundary - void bi_windup(){ - if (bi_valid > 8) { - put_short(bi_buf); - } else if (bi_valid > 0) { - put_byte((byte)bi_buf); - } - bi_buf = 0; - bi_valid = 0; - } - - // Copy a stored block, storing first the length and its - // one's complement if requested. - void copy_block(int buf, // the input data - int len, // its length - boolean header // true if block header must be written - ){ - int index=0; - bi_windup(); // align on byte boundary - last_eob_len = 8; // enough lookahead for inflate - - if (header) { - put_short((short)len); - put_short((short)~len); - } - - // while(len--!=0) { - // put_byte(window[buf+index]); - // index++; - // } - put_byte(window, buf, len); - } - - void flush_block_only(boolean eof){ - _tr_flush_block(block_start>=0 ? block_start : -1, - strstart-block_start, - eof); - block_start=strstart; - strm.flush_pending(); - } - - // Copy without compression as much as possible from the input stream, return - // the current block state. - // This function does not insert new strings in the dictionary since - // uncompressible data is probably not useful. This function is used - // only for the level=0 compression option. - // NOTE: this function should be optimized to avoid extra copying from - // window to pending_buf. - int deflate_stored(int flush){ - // Stored blocks are limited to 0xffff bytes, pending_buf is limited - // to pending_buf_size, and each stored block has a 5 byte header: - - int max_block_size = 0xffff; - int max_start; - - if(max_block_size > pending_buf_size - 5) { - max_block_size = pending_buf_size - 5; - } - - // Copy as much as possible from input to output: - while(true){ - // Fill the window as much as possible: - if(lookahead<=1){ - fill_window(); - if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore; - if(lookahead==0) break; // flush the current block - } - - strstart+=lookahead; - lookahead=0; - - // Emit a stored block if pending_buf will be full: - max_start=block_start+max_block_size; - if(strstart==0|| strstart>=max_start) { - // strstart == 0 is possible when wraparound on 16-bit machine - lookahead = (int)(strstart-max_start); - strstart = (int)max_start; - - flush_block_only(false); - if(strm.avail_out==0) return NeedMore; - - } - - // Flush if we may have to slide, otherwise block_start may become - // negative and the data will be gone: - if(strstart-block_start >= w_size-MIN_LOOKAHEAD) { - flush_block_only(false); - if(strm.avail_out==0) return NeedMore; - } - } - - flush_block_only(flush == Z_FINISH); - if(strm.avail_out==0) - return (flush == Z_FINISH) ? FinishStarted : NeedMore; - - return flush == Z_FINISH ? FinishDone : BlockDone; - } - - // Send a stored block - void _tr_stored_block(int buf, // input block - int stored_len, // length of input block - boolean eof // true if this is the last block for a file - ){ - send_bits((STORED_BLOCK<<1)+(eof?1:0), 3); // send block type - copy_block(buf, stored_len, true); // with header - } - - // Determine the best encoding for the current block: dynamic trees, static - // trees or store, and output the encoded block to the zip file. - void _tr_flush_block(int buf, // input block, or NULL if too old - int stored_len, // length of input block - boolean eof // true if this is the last block for a file - ) { - int opt_lenb, static_lenb;// opt_len and static_len in bytes - int max_blindex = 0; // index of last bit length code of non zero freq - - // Build the Huffman trees unless a stored block is forced - if(level > 0) { - // Check if the file is ascii or binary - if(data_type == Z_UNKNOWN) set_data_type(); - - // Construct the literal and distance trees - l_desc.build_tree(this); - - d_desc.build_tree(this); - - // At this point, opt_len and static_len are the total bit lengths of - // the compressed block data, excluding the tree representations. - - // Build the bit length tree for the above two trees, and get the index - // in bl_order of the last bit length code to send. - max_blindex=build_bl_tree(); - - // Determine the best encoding. Compute first the block length in bytes - opt_lenb=(opt_len+3+7)>>>3; - static_lenb=(static_len+3+7)>>>3; - - if(static_lenb<=opt_lenb) opt_lenb=static_lenb; - } - else { - opt_lenb=static_lenb=stored_len+5; // force a stored block - } - - if(stored_len+4<=opt_lenb && buf != -1){ - // 4: two words for the lengths - // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - // Otherwise we can't have processed more than WSIZE input bytes since - // the last block flush, because compression would have been - // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - // transform a block into a stored block. - _tr_stored_block(buf, stored_len, eof); - } - else if(static_lenb == opt_lenb){ - send_bits((STATIC_TREES<<1)+(eof?1:0), 3); - compress_block(StaticTree.static_ltree, StaticTree.static_dtree); - } - else{ - send_bits((DYN_TREES<<1)+(eof?1:0), 3); - send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1); - compress_block(dyn_ltree, dyn_dtree); - } - - // The above check is made mod 2^32, for files larger than 512 MB - // and uLong implemented on 32 bits. - - init_block(); - - if(eof){ - bi_windup(); - } - } - - // Fill the window when the lookahead becomes insufficient. - // Updates strstart and lookahead. - // - // IN assertion: lookahead < MIN_LOOKAHEAD - // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - // At least one byte has been read, or avail_in == 0; reads are - // performed for at least two bytes (required for the zip translate_eol - // option -- not supported here). - void fill_window(){ - int n, m; - int p; - int more; // Amount of free space at the end of the window. - - do{ - more = (window_size-lookahead-strstart); - - // Deal with !@#$% 64K limit: - if(more==0 && strstart==0 && lookahead==0){ - more = w_size; - } - else if(more==-1) { - // Very unlikely, but possible on 16 bit machine if strstart == 0 - // and lookahead == 1 (input done one byte at time) - more--; - - // If the window is almost full and there is insufficient lookahead, - // move the upper half to the lower one to make room in the upper half. - } - else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) { - System.arraycopy(window, w_size, window, 0, w_size); - match_start-=w_size; - strstart-=w_size; // we now have strstart >= MAX_DIST - block_start-=w_size; - - // Slide the hash table (could be avoided with 32 bit values - // at the expense of memory usage). We slide even when level == 0 - // to keep the hash table consistent if we switch back to level > 0 - // later. (Using level 0 permanently is not an optimal usage of - // zlib, so we don't care about this pathological case.) - - n = hash_size; - p=n; - do { - m = (head[--p]&0xffff); - head[p]=(m>=w_size ? (short)(m-w_size) : 0); - } - while (--n != 0); - - n = w_size; - p = n; - do { - m = (prev[--p]&0xffff); - prev[p] = (m >= w_size ? (short)(m-w_size) : 0); - // If n is not on any hash chain, prev[n] is garbage but - // its value will never be used. - } - while (--n!=0); - more += w_size; - } - - if (strm.avail_in == 0) return; - - // If there was no sliding: - // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - // more == window_size - lookahead - strstart - // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - // => more >= window_size - 2*WSIZE + 2 - // In the BIG_MEM or MMAP case (not yet supported), - // window_size == input_size + MIN_LOOKAHEAD && - // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - // Otherwise, window_size == 2*WSIZE so more >= 2. - // If there was sliding, more >= WSIZE. So in all cases, more >= 2. - - n = strm.read_buf(window, strstart + lookahead, more); - lookahead += n; - - // Initialize the hash value now that we have some input: - if(lookahead >= MIN_MATCH) { - ins_h = window[strstart]&0xff; - ins_h=(((ins_h)<<hash_shift)^(window[strstart+1]&0xff))&hash_mask; - } - // If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - // but this is not important since only literal bytes will be emitted. - } - while (lookahead < MIN_LOOKAHEAD && strm.avail_in != 0); - } - - // Compress as much as possible from the input stream, return the current - // block state. - // This function does not perform lazy evaluation of matches and inserts - // new strings in the dictionary only for unmatched strings or for short - // matches. It is used only for the fast compression options. - int deflate_fast(int flush){ -// short hash_head = 0; // head of the hash chain - int hash_head = 0; // head of the hash chain - boolean bflush; // set if current block must be flushed - - while(true){ - // Make sure that we always have enough lookahead, except - // at the end of the input file. We need MAX_MATCH bytes - // for the next match, plus MIN_MATCH bytes to insert the - // string following the next match. - if(lookahead < MIN_LOOKAHEAD){ - fill_window(); - if(lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH){ - return NeedMore; - } - if(lookahead == 0) break; // flush the current block - } - - // Insert the string window[strstart .. strstart+2] in the - // dictionary, and set hash_head to the head of the hash chain: - if(lookahead >= MIN_MATCH){ - ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask; - -// prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head=(head[ins_h]&0xffff); - prev[strstart&w_mask]=head[ins_h]; - head[ins_h]=(short)strstart; - } - - // Find the longest match, discarding those <= prev_length. - // At this point we have always match_length < MIN_MATCH - - if(hash_head!=0L && - ((strstart-hash_head)&0xffff) <= w_size-MIN_LOOKAHEAD - ){ - // To simplify the code, we prevent matches with the string - // of window index 0 (in particular we have to avoid a match - // of the string with itself at the start of the input file). - if(strategy != Z_HUFFMAN_ONLY){ - match_length=longest_match (hash_head); - } - // longest_match() sets match_start - } - if(match_length>=MIN_MATCH){ - // check_match(strstart, match_start, match_length); - - bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH); - - lookahead -= match_length; - - // Insert new strings in the hash table only if the match length - // is not too large. This saves time but degrades compression. - if(match_length <= max_lazy_match && - lookahead >= MIN_MATCH) { - match_length--; // string at strstart already in hash table - do{ - strstart++; - - ins_h=((ins_h<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask; -// prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head=(head[ins_h]&0xffff); - prev[strstart&w_mask]=head[ins_h]; - head[ins_h]=(short)strstart; - - // strstart never exceeds WSIZE-MAX_MATCH, so there are - // always MIN_MATCH bytes ahead. - } - while (--match_length != 0); - strstart++; - } - else{ - strstart += match_length; - match_length = 0; - ins_h = window[strstart]&0xff; - - ins_h=(((ins_h)<<hash_shift)^(window[strstart+1]&0xff))&hash_mask; - // If lookahead < MIN_MATCH, ins_h is garbage, but it does not - // matter since it will be recomputed at next deflate call. - } - } - else { - // No match, output a literal byte - - bflush=_tr_tally(0, window[strstart]&0xff); - lookahead--; - strstart++; - } - if (bflush){ - - flush_block_only(false); - if(strm.avail_out==0) return NeedMore; - } - } - - flush_block_only(flush == Z_FINISH); - if(strm.avail_out==0){ - if(flush == Z_FINISH) return FinishStarted; - else return NeedMore; - } - return flush==Z_FINISH ? FinishDone : BlockDone; - } - - // Same as above, but achieves better compression. We use a lazy - // evaluation for matches: a match is finally adopted only if there is - // no better match at the next window position. - int deflate_slow(int flush){ -// short hash_head = 0; // head of hash chain - int hash_head = 0; // head of hash chain - boolean bflush; // set if current block must be flushed - - // Process the input block. - while(true){ - // Make sure that we always have enough lookahead, except - // at the end of the input file. We need MAX_MATCH bytes - // for the next match, plus MIN_MATCH bytes to insert the - // string following the next match. - - if (lookahead < MIN_LOOKAHEAD) { - fill_window(); - if(lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return NeedMore; - } - if(lookahead == 0) break; // flush the current block - } - - // Insert the string window[strstart .. strstart+2] in the - // dictionary, and set hash_head to the head of the hash chain: - - if(lookahead >= MIN_MATCH) { - ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff)) & hash_mask; -// prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head=(head[ins_h]&0xffff); - prev[strstart&w_mask]=head[ins_h]; - head[ins_h]=(short)strstart; - } - - // Find the longest match, discarding those <= prev_length. - prev_length = match_length; prev_match = match_start; - match_length = MIN_MATCH-1; - - if (hash_head != 0 && prev_length < max_lazy_match && - ((strstart-hash_head)&0xffff) <= w_size-MIN_LOOKAHEAD - ){ - // To simplify the code, we prevent matches with the string - // of window index 0 (in particular we have to avoid a match - // of the string with itself at the start of the input file). - - if(strategy != Z_HUFFMAN_ONLY) { - match_length = longest_match(hash_head); - } - // longest_match() sets match_start - - if (match_length <= 5 && (strategy == Z_FILTERED || - (match_length == MIN_MATCH && - strstart - match_start > 4096))) { - - // If prev_match is also MIN_MATCH, match_start is garbage - // but we will ignore the current match anyway. - match_length = MIN_MATCH-1; - } - } - - // If there was a match at the previous step and the current - // match is not better, output the previous match: - if(prev_length >= MIN_MATCH && match_length <= prev_length) { - int max_insert = strstart + lookahead - MIN_MATCH; - // Do not insert strings in hash table beyond this. - - // check_match(strstart-1, prev_match, prev_length); - - bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH); - - // Insert in hash table all strings up to the end of the match. - // strstart-1 and strstart are already inserted. If there is not - // enough lookahead, the last two strings are not inserted in - // the hash table. - lookahead -= prev_length-1; - prev_length -= 2; - do{ - if(++strstart <= max_insert) { - ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask; - //prev[strstart&w_mask]=hash_head=head[ins_h]; - hash_head=(head[ins_h]&0xffff); - prev[strstart&w_mask]=head[ins_h]; - head[ins_h]=(short)strstart; - } - } - while(--prev_length != 0); - match_available = 0; - match_length = MIN_MATCH-1; - strstart++; - - if (bflush){ - flush_block_only(false); - if(strm.avail_out==0) return NeedMore; - } - } else if (match_available!=0) { - - // If there was no match at the previous position, output a - // single literal. If there was a match but the current match - // is longer, truncate the previous match to a single literal. - - bflush=_tr_tally(0, window[strstart-1]&0xff); - - if (bflush) { - flush_block_only(false); - } - strstart++; - lookahead--; - if(strm.avail_out == 0) return NeedMore; - } else { - // There is no previous match to compare with, wait for - // the next step to decide. - - match_available = 1; - strstart++; - lookahead--; - } - } - - if(match_available!=0) { - bflush=_tr_tally(0, window[strstart-1]&0xff); - match_available = 0; - } - flush_block_only(flush == Z_FINISH); - - if(strm.avail_out==0){ - if(flush == Z_FINISH) return FinishStarted; - else return NeedMore; - } - - return flush == Z_FINISH ? FinishDone : BlockDone; - } - - int longest_match(int cur_match){ - int chain_length = max_chain_length; // max hash chain length - int scan = strstart; // current string - int match; // matched string - int len; // length of current match - int best_len = prev_length; // best match length so far - int limit = strstart>(w_size-MIN_LOOKAHEAD) ? - strstart-(w_size-MIN_LOOKAHEAD) : 0; - int nice_match=this.nice_match; - - // Stop when cur_match becomes <= limit. To simplify the code, - // we prevent matches with the string of window index 0. - - int wmask = w_mask; - - int strend = strstart + MAX_MATCH; - byte scan_end1 = window[scan+best_len-1]; - byte scan_end = window[scan+best_len]; - - // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - // It is easy to get rid of this optimization if necessary. - - // Do not waste too much time if we already have a good match: - if (prev_length >= good_match) { - chain_length >>= 2; - } - - // Do not look for matches beyond the end of the input. This is necessary - // to make deflate deterministic. - if (nice_match > lookahead) nice_match = lookahead; - - do { - match = cur_match; - - // Skip to next match if the match length cannot increase - // or if the match length is less than 2: - if (window[match+best_len] != scan_end || - window[match+best_len-1] != scan_end1 || - window[match] != window[scan] || - window[++match] != window[scan+1]) continue; - - // The check at best_len-1 can be removed because it will be made - // again later. (This heuristic is not always a win.) - // It is not necessary to compare scan[2] and match[2] since they - // are always equal when the other bytes match, given that - // the hash keys are equal and that HASH_BITS >= 8. - scan += 2; match++; - - // We check for insufficient lookahead only every 8th comparison; - // the 256th check will be made at strstart+258. - do { - } while (window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - window[++scan] == window[++match] && - scan < strend); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - - if(len>best_len) { - match_start = cur_match; - best_len = len; - if (len >= nice_match) break; - scan_end1 = window[scan+best_len-1]; - scan_end = window[scan+best_len]; - } - - } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit - && --chain_length != 0); - - if (best_len <= lookahead) return best_len; - return lookahead; - } - - int deflateInit(ZStream strm, int level, int bits){ - return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY); - } - int deflateInit(ZStream strm, int level){ - return deflateInit(strm, level, MAX_WBITS); - } - int deflateInit2(ZStream strm, int level, int method, int windowBits, - int memLevel, int strategy){ - int noheader = 0; - // byte[] my_version=ZLIB_VERSION; - - // - // if (version == null || version[0] != my_version[0] - // || stream_size != sizeof(z_stream)) { - // return Z_VERSION_ERROR; - // } - - strm.msg = null; - - if (level == Z_DEFAULT_COMPRESSION) level = 6; - - if (windowBits < 0) { // undocumented feature: suppress zlib header - noheader = 1; - windowBits = -windowBits; - } - - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || - method != Z_DEFLATED || - windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; - } - - strm.dstate = (Deflate)this; - - this.noheader = noheader; - w_bits = windowBits; - w_size = 1 << w_bits; - w_mask = w_size - 1; - - hash_bits = memLevel + 7; - hash_size = 1 << hash_bits; - hash_mask = hash_size - 1; - hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH); - - window = new byte[w_size*2]; - prev = new short[w_size]; - head = new short[hash_size]; - - lit_bufsize = 1 << (memLevel + 6); // 16K elements by default - - // We overlay pending_buf and d_buf+l_buf. This works since the average - // output size for (length,distance) codes is <= 24 bits. - pending_buf = new byte[lit_bufsize*4]; - pending_buf_size = lit_bufsize*4; - - d_buf = lit_bufsize/2; - l_buf = (1+2)*lit_bufsize; - - this.level = level; - -//System.out.println("level="+level); - - this.strategy = strategy; - this.method = (byte)method; - - return deflateReset(strm); - } - - int deflateReset(ZStream strm){ - strm.total_in = strm.total_out = 0; - strm.msg = null; // - strm.data_type = Z_UNKNOWN; - - pending = 0; - pending_out = 0; - - if(noheader < 0) { - noheader = 0; // was set to -1 by deflate(..., Z_FINISH); - } - status = (noheader!=0) ? BUSY_STATE : INIT_STATE; - strm.adler=strm._adler.adler32(0, null, 0, 0); - - last_flush = Z_NO_FLUSH; - - tr_init(); - lm_init(); - return Z_OK; - } - - int deflateEnd(){ - if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){ - return Z_STREAM_ERROR; - } - // Deallocate in reverse order of allocations: - pending_buf=null; - head=null; - prev=null; - window=null; - // free - // dstate=null; - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; - } - - int deflateParams(ZStream strm, int _level, int _strategy){ - int err=Z_OK; - - if(_level == Z_DEFAULT_COMPRESSION){ - _level = 6; - } - if(_level < 0 || _level > 9 || - _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; - } - - if(config_table[level].func!=config_table[_level].func && - strm.total_in != 0) { - // Flush the last buffer: - err = strm.deflate(Z_PARTIAL_FLUSH); - } - - if(level != _level) { - level = _level; - max_lazy_match = config_table[level].max_lazy; - good_match = config_table[level].good_length; - nice_match = config_table[level].nice_length; - max_chain_length = config_table[level].max_chain; - } - strategy = _strategy; - return err; - } - - int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){ - int length = dictLength; - int index=0; - - if(dictionary == null || status != INIT_STATE) - return Z_STREAM_ERROR; - - strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength); - - if(length < MIN_MATCH) return Z_OK; - if(length > w_size-MIN_LOOKAHEAD){ - length = w_size-MIN_LOOKAHEAD; - index=dictLength-length; // use the tail of the dictionary - } - System.arraycopy(dictionary, index, window, 0, length); - strstart = length; - block_start = length; - - // Insert all strings in the hash table (except for the last two bytes). - // s->lookahead stays null, so s->ins_h will be recomputed at the next - // call of fill_window. - - ins_h = window[0]&0xff; - ins_h=(((ins_h)<<hash_shift)^(window[1]&0xff))&hash_mask; - - for(int n=0; n<=length-MIN_MATCH; n++){ - ins_h=(((ins_h)<<hash_shift)^(window[(n)+(MIN_MATCH-1)]&0xff))&hash_mask; - prev[n&w_mask]=head[ins_h]; - head[ins_h]=(short)n; - } - return Z_OK; - } - - int deflate(ZStream strm, int flush){ - int old_flush; - - if(flush>Z_FINISH || flush<0){ - return Z_STREAM_ERROR; - } - - if(strm.next_out == null || - (strm.next_in == null && strm.avail_in != 0) || - (status == FINISH_STATE && flush != Z_FINISH)) { - strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)]; - return Z_STREAM_ERROR; - } - if(strm.avail_out == 0){ - strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; - return Z_BUF_ERROR; - } - - this.strm = strm; // just in case - old_flush = last_flush; - last_flush = flush; - - // Write the zlib header - if(status == INIT_STATE) { - int header = (Z_DEFLATED+((w_bits-8)<<4))<<8; - int level_flags=((level-1)&0xff)>>1; - - if(level_flags>3) level_flags=3; - header |= (level_flags<<6); - if(strstart!=0) header |= PRESET_DICT; - header+=31-(header % 31); - - status=BUSY_STATE; - putShortMSB(header); - - - // Save the adler32 of the preset dictionary: - if(strstart!=0){ - putShortMSB((int)(strm.adler>>>16)); - putShortMSB((int)(strm.adler&0xffff)); - } - strm.adler=strm._adler.adler32(0, null, 0, 0); - } - - // Flush as much pending output as possible - if(pending != 0) { - strm.flush_pending(); - if(strm.avail_out == 0) { - //System.out.println(" avail_out==0"); - // Since avail_out is 0, deflate will be called again with - // more output space, but possibly with both pending and - // avail_in equal to zero. There won't be anything to do, - // but this is not an error situation so make sure we - // return OK instead of BUF_ERROR at next call of deflate: - last_flush = -1; - return Z_OK; - } - - // Make sure there is something to do and avoid duplicate consecutive - // flushes. For repeated and useless calls with Z_FINISH, we keep - // returning Z_STREAM_END instead of Z_BUFF_ERROR. - } - else if(strm.avail_in==0 && flush <= old_flush && - flush != Z_FINISH) { - strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; - return Z_BUF_ERROR; - } - - // User must not provide more input after the first FINISH: - if(status == FINISH_STATE && strm.avail_in != 0) { - strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)]; - return Z_BUF_ERROR; - } - - // Start a new block or continue the current one. - if(strm.avail_in!=0 || lookahead!=0 || - (flush != Z_NO_FLUSH && status != FINISH_STATE)) { - int bstate=-1; - switch(config_table[level].func){ - case STORED: - bstate = deflate_stored(flush); - break; - case FAST: - bstate = deflate_fast(flush); - break; - case SLOW: - bstate = deflate_slow(flush); - break; - default: - } - - if (bstate==FinishStarted || bstate==FinishDone) { - status = FINISH_STATE; - } - if (bstate==NeedMore || bstate==FinishStarted) { - if(strm.avail_out == 0) { - last_flush = -1; // avoid BUF_ERROR next call, see above - } - return Z_OK; - // If flush != Z_NO_FLUSH && avail_out == 0, the next call - // of deflate should use the same flush parameter to make sure - // that the flush is complete. So we don't have to output an - // empty block here, this will be done at next call. This also - // ensures that for a very small output buffer, we emit at most - // one empty block. - } - - if (bstate==BlockDone) { - if(flush == Z_PARTIAL_FLUSH) { - _tr_align(); - } - else { // FULL_FLUSH or SYNC_FLUSH - _tr_stored_block(0, 0, false); - // For a full flush, this empty block will be recognized - // as a special marker by inflate_sync(). - if(flush == Z_FULL_FLUSH) { - //state.head[s.hash_size-1]=0; - for(int i=0; i<hash_size/*-1*/; i++) // forget history - head[i]=0; - } - } - strm.flush_pending(); - if(strm.avail_out == 0) { - last_flush = -1; // avoid BUF_ERROR at next call, see above - return Z_OK; - } - } - } - - if(flush!=Z_FINISH) return Z_OK; - if(noheader!=0) return Z_STREAM_END; - - // Write the zlib trailer (adler32) - putShortMSB((int)(strm.adler>>>16)); - putShortMSB((int)(strm.adler&0xffff)); - strm.flush_pending(); - - // If avail_out is zero, the application will call deflate again - // to flush the rest. - noheader = -1; // write the trailer only once! - return pending != 0 ? Z_OK : Z_STREAM_END; - } -} diff --git a/src/com/jcraft/jzlib/InfBlocks.java b/src/com/jcraft/jzlib/InfBlocks.java deleted file mode 100644 index f6997fc..0000000 --- a/src/com/jcraft/jzlib/InfBlocks.java +++ /dev/null @@ -1,614 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final class InfBlocks{ - static final private int MANY=1440; - - // And'ing with mask[n] masks the lower n bits - static final private int[] inflate_mask = { - 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, - 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, - 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, - 0x00007fff, 0x0000ffff - }; - - // Table for deflate from PKZIP's appnote.txt. - static final int[] border = { // Order of the bit length code lengths - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - }; - - static final private int Z_OK=0; - static final private int Z_STREAM_END=1; - static final private int Z_NEED_DICT=2; - static final private int Z_ERRNO=-1; - static final private int Z_STREAM_ERROR=-2; - static final private int Z_DATA_ERROR=-3; - static final private int Z_MEM_ERROR=-4; - static final private int Z_BUF_ERROR=-5; - static final private int Z_VERSION_ERROR=-6; - - static final private int TYPE=0; // get type bits (3, including end bit) - static final private int LENS=1; // get lengths for stored - static final private int STORED=2;// processing stored block - static final private int TABLE=3; // get table lengths - static final private int BTREE=4; // get bit lengths tree for a dynamic block - static final private int DTREE=5; // get length, distance trees for a dynamic block - static final private int CODES=6; // processing fixed or dynamic block - static final private int DRY=7; // output remaining window bytes - static final private int DONE=8; // finished last block, done - static final private int BAD=9; // ot a data error--stuck here - - int mode; // current inflate_block mode - - int left; // if STORED, bytes left to copy - - int table; // table lengths (14 bits) - int index; // index into blens (or border) - int[] blens; // bit lengths of codes - int[] bb=new int[1]; // bit length tree depth - int[] tb=new int[1]; // bit length decoding tree - - InfCodes codes=new InfCodes(); // if CODES, current state - - int last; // true if this block is the last block - - // mode independent information - int bitk; // bits in bit buffer - int bitb; // bit buffer - int[] hufts; // single malloc for tree space - byte[] window; // sliding window - int end; // one byte after sliding window - int read; // window read pointer - int write; // window write pointer - Object checkfn; // check function - long check; // check on output - - InfTree inftree=new InfTree(); - - InfBlocks(ZStream z, Object checkfn, int w){ - hufts=new int[MANY*3]; - window=new byte[w]; - end=w; - this.checkfn = checkfn; - mode = TYPE; - reset(z, null); - } - - void reset(ZStream z, long[] c){ - if(c!=null) c[0]=check; - if(mode==BTREE || mode==DTREE){ - } - if(mode==CODES){ - codes.free(z); - } - mode=TYPE; - bitk=0; - bitb=0; - read=write=0; - - if(checkfn != null) - z.adler=check=z._adler.adler32(0L, null, 0, 0); - } - - int proc(ZStream z, int r){ - int t; // temporary storage - int b; // bit buffer - int k; // bits in bit buffer - int p; // input data pointer - int n; // bytes available there - int q; // output window write pointer - int m; // bytes to end of window or read pointer - - // copy input/output information to locals (UPDATE macro restores) - {p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;} - {q=write;m=(int)(q<read?read-q-1:end-q);} - - // process input based on current state - while(true){ - switch (mode){ - case TYPE: - - while(k<(3)){ - if(n!=0){ - r=Z_OK; - } - else{ - bitb=b; bitk=k; - z.avail_in=n; - z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - }; - n--; - b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - t = (int)(b & 7); - last = t & 1; - - switch (t >>> 1){ - case 0: // stored - {b>>>=(3);k-=(3);} - t = k & 7; // go to byte boundary - - {b>>>=(t);k-=(t);} - mode = LENS; // get length of stored block - break; - case 1: // fixed - { - int[] bl=new int[1]; - int[] bd=new int[1]; - int[][] tl=new int[1][]; - int[][] td=new int[1][]; - - InfTree.inflate_trees_fixed(bl, bd, tl, td, z); - codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z); - } - - {b>>>=(3);k-=(3);} - - mode = CODES; - break; - case 2: // dynamic - - {b>>>=(3);k-=(3);} - - mode = TABLE; - break; - case 3: // illegal - - {b>>>=(3);k-=(3);} - mode = BAD; - z.msg = "invalid block type"; - r = Z_DATA_ERROR; - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - } - break; - case LENS: - - while(k<(32)){ - if(n!=0){ - r=Z_OK; - } - else{ - bitb=b; bitk=k; - z.avail_in=n; - z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - }; - n--; - b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - if ((((~b) >>> 16) & 0xffff) != (b & 0xffff)){ - mode = BAD; - z.msg = "invalid stored block lengths"; - r = Z_DATA_ERROR; - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - } - left = (b & 0xffff); - b = k = 0; // dump bits - mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE); - break; - case STORED: - if (n == 0){ - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - } - - if(m==0){ - if(q==end&&read!=0){ - q=0; m=(int)(q<read?read-q-1:end-q); - } - if(m==0){ - write=q; - r=inflate_flush(z,r); - q=write;m=(int)(q<read?read-q-1:end-q); - if(q==end&&read!=0){ - q=0; m=(int)(q<read?read-q-1:end-q); - } - if(m==0){ - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - } - } - } - r=Z_OK; - - t = left; - if(t>n) t = n; - if(t>m) t = m; - System.arraycopy(z.next_in, p, window, q, t); - p += t; n -= t; - q += t; m -= t; - if ((left -= t) != 0) - break; - mode = last!=0 ? DRY : TYPE; - break; - case TABLE: - - while(k<(14)){ - if(n!=0){ - r=Z_OK; - } - else{ - bitb=b; bitk=k; - z.avail_in=n; - z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - }; - n--; - b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - table = t = (b & 0x3fff); - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - mode = BAD; - z.msg = "too many length or distance symbols"; - r = Z_DATA_ERROR; - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - } - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if(blens==null || blens.length<t){ - blens=new int[t]; - } - else{ - for(int i=0; i<t; i++){blens[i]=0;} - } - - {b>>>=(14);k-=(14);} - - index = 0; - mode = BTREE; - case BTREE: - while (index < 4 + (table >>> 10)){ - while(k<(3)){ - if(n!=0){ - r=Z_OK; - } - else{ - bitb=b; bitk=k; - z.avail_in=n; - z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - }; - n--; - b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - blens[border[index++]] = b&7; - - {b>>>=(3);k-=(3);} - } - - while(index < 19){ - blens[border[index++]] = 0; - } - - bb[0] = 7; - t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z); - if (t != Z_OK){ - r = t; - if (r == Z_DATA_ERROR){ - blens=null; - mode = BAD; - } - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - } - - index = 0; - mode = DTREE; - case DTREE: - while (true){ - t = table; - if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){ - break; - } - - int[] h; - int i, j, c; - - t = bb[0]; - - while(k<(t)){ - if(n!=0){ - r=Z_OK; - } - else{ - bitb=b; bitk=k; - z.avail_in=n; - z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - }; - n--; - b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - if(tb[0]==-1){ - //System.err.println("null..."); - } - - t=hufts[(tb[0]+(b&inflate_mask[t]))*3+1]; - c=hufts[(tb[0]+(b&inflate_mask[t]))*3+2]; - - if (c < 16){ - b>>>=(t);k-=(t); - blens[index++] = c; - } - else { // c == 16..18 - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - - while(k<(t+i)){ - if(n!=0){ - r=Z_OK; - } - else{ - bitb=b; bitk=k; - z.avail_in=n; - z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - }; - n--; - b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - b>>>=(t);k-=(t); - - j += (b & inflate_mask[i]); - - b>>>=(i);k-=(i); - - i = index; - t = table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)){ - blens=null; - mode = BAD; - z.msg = "invalid bit length repeat"; - r = Z_DATA_ERROR; - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - } - - c = c == 16 ? blens[i-1] : 0; - do{ - blens[i++] = c; - } - while (--j!=0); - index = i; - } - } - - tb[0]=-1; - { - int[] bl=new int[1]; - int[] bd=new int[1]; - int[] tl=new int[1]; - int[] td=new int[1]; - bl[0] = 9; // must be <= 9 for lookahead assumptions - bd[0] = 6; // must be <= 9 for lookahead assumptions - - t = table; - t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), - 1 + ((t >> 5) & 0x1f), - blens, bl, bd, tl, td, hufts, z); - - if (t != Z_OK){ - if (t == Z_DATA_ERROR){ - blens=null; - mode = BAD; - } - r = t; - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z,r); - } - codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z); - } - mode = CODES; - case CODES: - bitb=b; bitk=k; - z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - - if ((r = codes.proc(this, z, r)) != Z_STREAM_END){ - return inflate_flush(z, r); - } - r = Z_OK; - codes.free(z); - - p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk; - q=write;m=(int)(q<read?read-q-1:end-q); - - if (last==0){ - mode = TYPE; - break; - } - mode = DRY; - case DRY: - write=q; - r=inflate_flush(z, r); - q=write; m=(int)(q<read?read-q-1:end-q); - if (read != write){ - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z, r); - } - mode = DONE; - case DONE: - r = Z_STREAM_END; - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z, r); - case BAD: - r = Z_DATA_ERROR; - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z, r); - - default: - r = Z_STREAM_ERROR; - - bitb=b; bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - write=q; - return inflate_flush(z, r); - } - } - } - - void free(ZStream z){ - reset(z, null); - window=null; - hufts=null; - //ZFREE(z, s); - } - - void set_dictionary(byte[] d, int start, int n){ - System.arraycopy(d, start, window, 0, n); - read = write = n; - } - - // Returns true if inflate is currently at the end of a block generated - // by Z_SYNC_FLUSH or Z_FULL_FLUSH. - int sync_point(){ - return mode == LENS ? 1 : 0; - } - - // copy as much as possible from the sliding window to the output area - int inflate_flush(ZStream z, int r){ - int n; - int p; - int q; - - // local copies of source and destination pointers - p = z.next_out_index; - q = read; - - // compute number of bytes to copy as far as end of window - n = (int)((q <= write ? write : end) - q); - if (n > z.avail_out) n = z.avail_out; - if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; - - // update counters - z.avail_out -= n; - z.total_out += n; - - // update check information - if(checkfn != null) - z.adler=check=z._adler.adler32(check, window, q, n); - - // copy as far as end of window - System.arraycopy(window, q, z.next_out, p, n); - p += n; - q += n; - - // see if more to copy at beginning of window - if (q == end){ - // wrap pointers - q = 0; - if (write == end) - write = 0; - - // compute bytes to copy - n = write - q; - if (n > z.avail_out) n = z.avail_out; - if (n!=0 && r == Z_BUF_ERROR) r = Z_OK; - - // update counters - z.avail_out -= n; - z.total_out += n; - - // update check information - if(checkfn != null) - z.adler=check=z._adler.adler32(check, window, q, n); - - // copy - System.arraycopy(window, q, z.next_out, p, n); - p += n; - q += n; - } - - // update pointers - z.next_out_index = p; - read = q; - - // done - return r; - } -} diff --git a/src/com/jcraft/jzlib/InfCodes.java b/src/com/jcraft/jzlib/InfCodes.java deleted file mode 100644 index c768fb1..0000000 --- a/src/com/jcraft/jzlib/InfCodes.java +++ /dev/null @@ -1,605 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final class InfCodes{ - - static final private int[] inflate_mask = { - 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, - 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, - 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, - 0x00007fff, 0x0000ffff - }; - - static final private int Z_OK=0; - static final private int Z_STREAM_END=1; - static final private int Z_NEED_DICT=2; - static final private int Z_ERRNO=-1; - static final private int Z_STREAM_ERROR=-2; - static final private int Z_DATA_ERROR=-3; - static final private int Z_MEM_ERROR=-4; - static final private int Z_BUF_ERROR=-5; - static final private int Z_VERSION_ERROR=-6; - - // waiting for "i:"=input, - // "o:"=output, - // "x:"=nothing - static final private int START=0; // x: set up for LEN - static final private int LEN=1; // i: get length/literal/eob next - static final private int LENEXT=2; // i: getting length extra (have base) - static final private int DIST=3; // i: get distance next - static final private int DISTEXT=4;// i: getting distance extra - static final private int COPY=5; // o: copying bytes in window, waiting for space - static final private int LIT=6; // o: got literal, waiting for output space - static final private int WASH=7; // o: got eob, possibly still output waiting - static final private int END=8; // x: got eob and all data flushed - static final private int BADCODE=9;// x: got error - - int mode; // current inflate_codes mode - - // mode dependent information - int len; - - int[] tree; // pointer into tree - int tree_index=0; - int need; // bits needed - - int lit; - - // if EXT or COPY, where and how much - int get; // bits to get for extra - int dist; // distance back to copy from - - byte lbits; // ltree bits decoded per branch - byte dbits; // dtree bits decoder per branch - int[] ltree; // literal/length/eob tree - int ltree_index; // literal/length/eob tree - int[] dtree; // distance tree - int dtree_index; // distance tree - - InfCodes(){ - } - void init(int bl, int bd, - int[] tl, int tl_index, - int[] td, int td_index, ZStream z){ - mode=START; - lbits=(byte)bl; - dbits=(byte)bd; - ltree=tl; - ltree_index=tl_index; - dtree = td; - dtree_index=td_index; - tree=null; - } - - int proc(InfBlocks s, ZStream z, int r){ - int j; // temporary storage - int[] t; // temporary pointer - int tindex; // temporary pointer - int e; // extra bits or operation - int b=0; // bit buffer - int k=0; // bits in bit buffer - int p=0; // input data pointer - int n; // bytes available there - int q; // output window write pointer - int m; // bytes to end of window or read pointer - int f; // pointer to copy strings from - - // copy input/output information to locals (UPDATE macro restores) - p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; - q=s.write;m=q<s.read?s.read-q-1:s.end-q; - - // process input and output based on current state - while (true){ - switch (mode){ - // waiting for "i:"=input, "o:"=output, "x:"=nothing - case START: // x: set up for LEN - if (m >= 258 && n >= 10){ - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - r = inflate_fast(lbits, dbits, - ltree, ltree_index, - dtree, dtree_index, - s, z); - - p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; - q=s.write;m=q<s.read?s.read-q-1:s.end-q; - - if (r != Z_OK){ - mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } - need = lbits; - tree = ltree; - tree_index=ltree_index; - - mode = LEN; - case LEN: // i: get length/literal/eob next - j = need; - - while(k<(j)){ - if(n!=0)r=Z_OK; - else{ - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - } - n--; - b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - tindex=(tree_index+(b&inflate_mask[j]))*3; - - b>>>=(tree[tindex+1]); - k-=(tree[tindex+1]); - - e=tree[tindex]; - - if(e == 0){ // literal - lit = tree[tindex+2]; - mode = LIT; - break; - } - if((e & 16)!=0 ){ // length - get = e & 15; - len = tree[tindex+2]; - mode = LENEXT; - break; - } - if ((e & 64) == 0){ // next table - need = e; - tree_index = tindex/3+tree[tindex+2]; - break; - } - if ((e & 32)!=0){ // end of block - mode = WASH; - break; - } - mode = BADCODE; // invalid code - z.msg = "invalid literal/length code"; - r = Z_DATA_ERROR; - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - - case LENEXT: // i: getting length extra (have base) - j = get; - - while(k<(j)){ - if(n!=0)r=Z_OK; - else{ - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - } - n--; b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - len += (b & inflate_mask[j]); - - b>>=j; - k-=j; - - need = dbits; - tree = dtree; - tree_index=dtree_index; - mode = DIST; - case DIST: // i: get distance next - j = need; - - while(k<(j)){ - if(n!=0)r=Z_OK; - else{ - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - } - n--; b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - tindex=(tree_index+(b & inflate_mask[j]))*3; - - b>>=tree[tindex+1]; - k-=tree[tindex+1]; - - e = (tree[tindex]); - if((e & 16)!=0){ // distance - get = e & 15; - dist = tree[tindex+2]; - mode = DISTEXT; - break; - } - if ((e & 64) == 0){ // next table - need = e; - tree_index = tindex/3 + tree[tindex+2]; - break; - } - mode = BADCODE; // invalid code - z.msg = "invalid distance code"; - r = Z_DATA_ERROR; - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - - case DISTEXT: // i: getting distance extra - j = get; - - while(k<(j)){ - if(n!=0)r=Z_OK; - else{ - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - } - n--; b|=(z.next_in[p++]&0xff)<<k; - k+=8; - } - - dist += (b & inflate_mask[j]); - - b>>=j; - k-=j; - - mode = COPY; - case COPY: // o: copying bytes in window, waiting for space - f = q - dist; - while(f < 0){ // modulo window size-"while" instead - f += s.end; // of "if" handles invalid distances - } - while (len!=0){ - - if(m==0){ - if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;} - if(m==0){ - s.write=q; r=s.inflate_flush(z,r); - q=s.write;m=q<s.read?s.read-q-1:s.end-q; - - if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;} - - if(m==0){ - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - } - } - } - - s.window[q++]=s.window[f++]; m--; - - if (f == s.end) - f = 0; - len--; - } - mode = START; - break; - case LIT: // o: got literal, waiting for output space - if(m==0){ - if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;} - if(m==0){ - s.write=q; r=s.inflate_flush(z,r); - q=s.write;m=q<s.read?s.read-q-1:s.end-q; - - if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;} - if(m==0){ - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - } - } - } - r=Z_OK; - - s.window[q++]=(byte)lit; m--; - - mode = START; - break; - case WASH: // o: got eob, possibly more output - if (k > 7){ // return unused byte, if any - k -= 8; - n++; - p--; // can always return one - } - - s.write=q; r=s.inflate_flush(z,r); - q=s.write;m=q<s.read?s.read-q-1:s.end-q; - - if (s.read != s.write){ - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - } - mode = END; - case END: - r = Z_STREAM_END; - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - - case BADCODE: // x: got error - - r = Z_DATA_ERROR; - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - - default: - r = Z_STREAM_ERROR; - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - return s.inflate_flush(z,r); - } - } - } - - void free(ZStream z){ - // ZFREE(z, c); - } - - // Called with number of bytes left to write in window at least 258 - // (the maximum string length) and number of input bytes available - // at least ten. The ten bytes are six bytes for the longest length/ - // distance pair plus four bytes for overloading the bit buffer. - - int inflate_fast(int bl, int bd, - int[] tl, int tl_index, - int[] td, int td_index, - InfBlocks s, ZStream z){ - int t; // temporary pointer - int[] tp; // temporary pointer - int tp_index; // temporary pointer - int e; // extra bits or operation - int b; // bit buffer - int k; // bits in bit buffer - int p; // input data pointer - int n; // bytes available there - int q; // output window write pointer - int m; // bytes to end of window or read pointer - int ml; // mask for literal/length tree - int md; // mask for distance tree - int c; // bytes to copy - int d; // distance back to copy from - int r; // copy source pointer - - int tp_index_t_3; // (tp_index+t)*3 - - // load input, output, bit values - p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk; - q=s.write;m=q<s.read?s.read-q-1:s.end-q; - - // initialize masks - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - // do until not enough input or output space for fast loop - do { // assume called with m >= 258 && n >= 10 - // get literal/length code - while(k<(20)){ // max bits for literal/length code - n--; - b|=(z.next_in[p++]&0xff)<<k;k+=8; - } - - t= b&ml; - tp=tl; - tp_index=tl_index; - tp_index_t_3=(tp_index+t)*3; - if ((e = tp[tp_index_t_3]) == 0){ - b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); - - s.window[q++] = (byte)tp[tp_index_t_3+2]; - m--; - continue; - } - do { - - b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); - - if((e&16)!=0){ - e &= 15; - c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]); - - b>>=e; k-=e; - - // decode distance base of block to copy - while(k<(15)){ // max bits for distance code - n--; - b|=(z.next_in[p++]&0xff)<<k;k+=8; - } - - t= b&md; - tp=td; - tp_index=td_index; - tp_index_t_3=(tp_index+t)*3; - e = tp[tp_index_t_3]; - - do { - - b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); - - if((e&16)!=0){ - // get extra bits to add to distance base - e &= 15; - while(k<(e)){ // get extra bits (up to 13) - n--; - b|=(z.next_in[p++]&0xff)<<k;k+=8; - } - - d = tp[tp_index_t_3+2] + (b&inflate_mask[e]); - - b>>=(e); k-=(e); - - // do the copy - m -= c; - if (q >= d){ // offset before dest - // just copy - r=q-d; - if(q-r>0 && 2>(q-r)){ - s.window[q++]=s.window[r++]; // minimum count is three, - s.window[q++]=s.window[r++]; // so unroll loop a little - c-=2; - } - else{ - System.arraycopy(s.window, r, s.window, q, 2); - q+=2; r+=2; c-=2; - } - } - else{ // else offset after destination - r=q-d; - do{ - r+=s.end; // force pointer in window - }while(r<0); // covers invalid distances - e=s.end-r; - if(c>e){ // if source crosses, - c-=e; // wrapped copy - if(q-r>0 && e>(q-r)){ - do{s.window[q++] = s.window[r++];} - while(--e!=0); - } - else{ - System.arraycopy(s.window, r, s.window, q, e); - q+=e; r+=e; e=0; - } - r = 0; // copy rest from start of window - } - - } - - // copy all or what's left - if(q-r>0 && c>(q-r)){ - do{s.window[q++] = s.window[r++];} - while(--c!=0); - } - else{ - System.arraycopy(s.window, r, s.window, q, c); - q+=c; r+=c; c=0; - } - break; - } - else if((e&64)==0){ - t+=tp[tp_index_t_3+2]; - t+=(b&inflate_mask[e]); - tp_index_t_3=(tp_index+t)*3; - e=tp[tp_index_t_3]; - } - else{ - z.msg = "invalid distance code"; - - c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3; - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - - return Z_DATA_ERROR; - } - } - while(true); - break; - } - - if((e&64)==0){ - t+=tp[tp_index_t_3+2]; - t+=(b&inflate_mask[e]); - tp_index_t_3=(tp_index+t)*3; - if((e=tp[tp_index_t_3])==0){ - - b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]); - - s.window[q++]=(byte)tp[tp_index_t_3+2]; - m--; - break; - } - } - else if((e&32)!=0){ - - c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3; - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - - return Z_STREAM_END; - } - else{ - z.msg="invalid literal/length code"; - - c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3; - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - - return Z_DATA_ERROR; - } - } - while(true); - } - while(m>=258 && n>= 10); - - // not enough input or output--restore pointers and return - c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3; - - s.bitb=b;s.bitk=k; - z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p; - s.write=q; - - return Z_OK; - } -} diff --git a/src/com/jcraft/jzlib/InfTree.java b/src/com/jcraft/jzlib/InfTree.java deleted file mode 100644 index cbca436..0000000 --- a/src/com/jcraft/jzlib/InfTree.java +++ /dev/null @@ -1,520 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final class InfTree{ - - static final private int MANY=1440; - - static final private int Z_OK=0; - static final private int Z_STREAM_END=1; - static final private int Z_NEED_DICT=2; - static final private int Z_ERRNO=-1; - static final private int Z_STREAM_ERROR=-2; - static final private int Z_DATA_ERROR=-3; - static final private int Z_MEM_ERROR=-4; - static final private int Z_BUF_ERROR=-5; - static final private int Z_VERSION_ERROR=-6; - - static final int fixed_bl = 9; - static final int fixed_bd = 5; - - static final int[] fixed_tl = { - 96,7,256, 0,8,80, 0,8,16, 84,8,115, - 82,7,31, 0,8,112, 0,8,48, 0,9,192, - 80,7,10, 0,8,96, 0,8,32, 0,9,160, - 0,8,0, 0,8,128, 0,8,64, 0,9,224, - 80,7,6, 0,8,88, 0,8,24, 0,9,144, - 83,7,59, 0,8,120, 0,8,56, 0,9,208, - 81,7,17, 0,8,104, 0,8,40, 0,9,176, - 0,8,8, 0,8,136, 0,8,72, 0,9,240, - 80,7,4, 0,8,84, 0,8,20, 85,8,227, - 83,7,43, 0,8,116, 0,8,52, 0,9,200, - 81,7,13, 0,8,100, 0,8,36, 0,9,168, - 0,8,4, 0,8,132, 0,8,68, 0,9,232, - 80,7,8, 0,8,92, 0,8,28, 0,9,152, - 84,7,83, 0,8,124, 0,8,60, 0,9,216, - 82,7,23, 0,8,108, 0,8,44, 0,9,184, - 0,8,12, 0,8,140, 0,8,76, 0,9,248, - 80,7,3, 0,8,82, 0,8,18, 85,8,163, - 83,7,35, 0,8,114, 0,8,50, 0,9,196, - 81,7,11, 0,8,98, 0,8,34, 0,9,164, - 0,8,2, 0,8,130, 0,8,66, 0,9,228, - 80,7,7, 0,8,90, 0,8,26, 0,9,148, - 84,7,67, 0,8,122, 0,8,58, 0,9,212, - 82,7,19, 0,8,106, 0,8,42, 0,9,180, - 0,8,10, 0,8,138, 0,8,74, 0,9,244, - 80,7,5, 0,8,86, 0,8,22, 192,8,0, - 83,7,51, 0,8,118, 0,8,54, 0,9,204, - 81,7,15, 0,8,102, 0,8,38, 0,9,172, - 0,8,6, 0,8,134, 0,8,70, 0,9,236, - 80,7,9, 0,8,94, 0,8,30, 0,9,156, - 84,7,99, 0,8,126, 0,8,62, 0,9,220, - 82,7,27, 0,8,110, 0,8,46, 0,9,188, - 0,8,14, 0,8,142, 0,8,78, 0,9,252, - 96,7,256, 0,8,81, 0,8,17, 85,8,131, - 82,7,31, 0,8,113, 0,8,49, 0,9,194, - 80,7,10, 0,8,97, 0,8,33, 0,9,162, - 0,8,1, 0,8,129, 0,8,65, 0,9,226, - 80,7,6, 0,8,89, 0,8,25, 0,9,146, - 83,7,59, 0,8,121, 0,8,57, 0,9,210, - 81,7,17, 0,8,105, 0,8,41, 0,9,178, - 0,8,9, 0,8,137, 0,8,73, 0,9,242, - 80,7,4, 0,8,85, 0,8,21, 80,8,258, - 83,7,43, 0,8,117, 0,8,53, 0,9,202, - 81,7,13, 0,8,101, 0,8,37, 0,9,170, - 0,8,5, 0,8,133, 0,8,69, 0,9,234, - 80,7,8, 0,8,93, 0,8,29, 0,9,154, - 84,7,83, 0,8,125, 0,8,61, 0,9,218, - 82,7,23, 0,8,109, 0,8,45, 0,9,186, - 0,8,13, 0,8,141, 0,8,77, 0,9,250, - 80,7,3, 0,8,83, 0,8,19, 85,8,195, - 83,7,35, 0,8,115, 0,8,51, 0,9,198, - 81,7,11, 0,8,99, 0,8,35, 0,9,166, - 0,8,3, 0,8,131, 0,8,67, 0,9,230, - 80,7,7, 0,8,91, 0,8,27, 0,9,150, - 84,7,67, 0,8,123, 0,8,59, 0,9,214, - 82,7,19, 0,8,107, 0,8,43, 0,9,182, - 0,8,11, 0,8,139, 0,8,75, 0,9,246, - 80,7,5, 0,8,87, 0,8,23, 192,8,0, - 83,7,51, 0,8,119, 0,8,55, 0,9,206, - 81,7,15, 0,8,103, 0,8,39, 0,9,174, - 0,8,7, 0,8,135, 0,8,71, 0,9,238, - 80,7,9, 0,8,95, 0,8,31, 0,9,158, - 84,7,99, 0,8,127, 0,8,63, 0,9,222, - 82,7,27, 0,8,111, 0,8,47, 0,9,190, - 0,8,15, 0,8,143, 0,8,79, 0,9,254, - 96,7,256, 0,8,80, 0,8,16, 84,8,115, - 82,7,31, 0,8,112, 0,8,48, 0,9,193, - - 80,7,10, 0,8,96, 0,8,32, 0,9,161, - 0,8,0, 0,8,128, 0,8,64, 0,9,225, - 80,7,6, 0,8,88, 0,8,24, 0,9,145, - 83,7,59, 0,8,120, 0,8,56, 0,9,209, - 81,7,17, 0,8,104, 0,8,40, 0,9,177, - 0,8,8, 0,8,136, 0,8,72, 0,9,241, - 80,7,4, 0,8,84, 0,8,20, 85,8,227, - 83,7,43, 0,8,116, 0,8,52, 0,9,201, - 81,7,13, 0,8,100, 0,8,36, 0,9,169, - 0,8,4, 0,8,132, 0,8,68, 0,9,233, - 80,7,8, 0,8,92, 0,8,28, 0,9,153, - 84,7,83, 0,8,124, 0,8,60, 0,9,217, - 82,7,23, 0,8,108, 0,8,44, 0,9,185, - 0,8,12, 0,8,140, 0,8,76, 0,9,249, - 80,7,3, 0,8,82, 0,8,18, 85,8,163, - 83,7,35, 0,8,114, 0,8,50, 0,9,197, - 81,7,11, 0,8,98, 0,8,34, 0,9,165, - 0,8,2, 0,8,130, 0,8,66, 0,9,229, - 80,7,7, 0,8,90, 0,8,26, 0,9,149, - 84,7,67, 0,8,122, 0,8,58, 0,9,213, - 82,7,19, 0,8,106, 0,8,42, 0,9,181, - 0,8,10, 0,8,138, 0,8,74, 0,9,245, - 80,7,5, 0,8,86, 0,8,22, 192,8,0, - 83,7,51, 0,8,118, 0,8,54, 0,9,205, - 81,7,15, 0,8,102, 0,8,38, 0,9,173, - 0,8,6, 0,8,134, 0,8,70, 0,9,237, - 80,7,9, 0,8,94, 0,8,30, 0,9,157, - 84,7,99, 0,8,126, 0,8,62, 0,9,221, - 82,7,27, 0,8,110, 0,8,46, 0,9,189, - 0,8,14, 0,8,142, 0,8,78, 0,9,253, - 96,7,256, 0,8,81, 0,8,17, 85,8,131, - 82,7,31, 0,8,113, 0,8,49, 0,9,195, - 80,7,10, 0,8,97, 0,8,33, 0,9,163, - 0,8,1, 0,8,129, 0,8,65, 0,9,227, - 80,7,6, 0,8,89, 0,8,25, 0,9,147, - 83,7,59, 0,8,121, 0,8,57, 0,9,211, - 81,7,17, 0,8,105, 0,8,41, 0,9,179, - 0,8,9, 0,8,137, 0,8,73, 0,9,243, - 80,7,4, 0,8,85, 0,8,21, 80,8,258, - 83,7,43, 0,8,117, 0,8,53, 0,9,203, - 81,7,13, 0,8,101, 0,8,37, 0,9,171, - 0,8,5, 0,8,133, 0,8,69, 0,9,235, - 80,7,8, 0,8,93, 0,8,29, 0,9,155, - 84,7,83, 0,8,125, 0,8,61, 0,9,219, - 82,7,23, 0,8,109, 0,8,45, 0,9,187, - 0,8,13, 0,8,141, 0,8,77, 0,9,251, - 80,7,3, 0,8,83, 0,8,19, 85,8,195, - 83,7,35, 0,8,115, 0,8,51, 0,9,199, - 81,7,11, 0,8,99, 0,8,35, 0,9,167, - 0,8,3, 0,8,131, 0,8,67, 0,9,231, - 80,7,7, 0,8,91, 0,8,27, 0,9,151, - 84,7,67, 0,8,123, 0,8,59, 0,9,215, - 82,7,19, 0,8,107, 0,8,43, 0,9,183, - 0,8,11, 0,8,139, 0,8,75, 0,9,247, - 80,7,5, 0,8,87, 0,8,23, 192,8,0, - 83,7,51, 0,8,119, 0,8,55, 0,9,207, - 81,7,15, 0,8,103, 0,8,39, 0,9,175, - 0,8,7, 0,8,135, 0,8,71, 0,9,239, - 80,7,9, 0,8,95, 0,8,31, 0,9,159, - 84,7,99, 0,8,127, 0,8,63, 0,9,223, - 82,7,27, 0,8,111, 0,8,47, 0,9,191, - 0,8,15, 0,8,143, 0,8,79, 0,9,255 - }; - static final int[] fixed_td = { - 80,5,1, 87,5,257, 83,5,17, 91,5,4097, - 81,5,5, 89,5,1025, 85,5,65, 93,5,16385, - 80,5,3, 88,5,513, 84,5,33, 92,5,8193, - 82,5,9, 90,5,2049, 86,5,129, 192,5,24577, - 80,5,2, 87,5,385, 83,5,25, 91,5,6145, - 81,5,7, 89,5,1537, 85,5,97, 93,5,24577, - 80,5,4, 88,5,769, 84,5,49, 92,5,12289, - 82,5,13, 90,5,3073, 86,5,193, 192,5,24577 - }; - - // Tables for deflate from PKZIP's appnote.txt. - static final int[] cplens = { // Copy lengths for literal codes 257..285 - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 - }; - - // see note #13 above about 258 - static final int[] cplext = { // Extra bits for literal codes 257..285 - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid - }; - - static final int[] cpdist = { // Copy offsets for distance codes 0..29 - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 - }; - - static final int[] cpdext = { // Extra bits for distance codes - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - - // If BMAX needs to be larger than 16, then h and x[] should be uLong. - static final int BMAX=15; // maximum bit length of any code - - int[] hn = null; // hufts used in space - int[] v = null; // work area for huft_build - int[] c = null; // bit length count table - int[] r = null; // table entry for structure assignment - int[] u = null; // table stack - int[] x = null; // bit offsets, then code stack - - private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX) - int bindex, - int n, // number of codes (assumed <= 288) - int s, // number of simple-valued codes (0..s-1) - int[] d, // list of base values for non-simple codes - int[] e, // list of extra bits for non-simple codes - int[] t, // result: starting table - int[] m, // maximum lookup bits, returns actual - int[] hp,// space for trees - int[] hn,// hufts used in space - int[] v // working area: values in order of bit length - ){ - // Given a list of code lengths and a maximum table size, make a set of - // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - // if the given code set is incomplete (the tables are still built in this - // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - // lengths), or Z_MEM_ERROR if not enough memory. - - int a; // counter for codes of length k - int f; // i repeats in table every f entries - int g; // maximum code length - int h; // table level - int i; // counter, current code - int j; // counter - int k; // number of bits in current code - int l; // bits per table (returned in m) - int mask; // (1 << w) - 1, to avoid cc -O bug on HP - int p; // pointer into c[], b[], or v[] - int q; // points to current table - int w; // bits before this table == (l * h) - int xp; // pointer into x - int y; // number of dummy codes added - int z; // number of entries in current table - - // Generate counts for each bit length - - p = 0; i = n; - do { - c[b[bindex+p]]++; p++; i--; // assume all entries <= BMAX - }while(i!=0); - - if(c[0] == n){ // null input--all zero length codes - t[0] = -1; - m[0] = 0; - return Z_OK; - } - - // Find minimum and maximum length, bound *m by those - l = m[0]; - for (j = 1; j <= BMAX; j++) - if(c[j]!=0) break; - k = j; // minimum code length - if(l < j){ - l = j; - } - for (i = BMAX; i!=0; i--){ - if(c[i]!=0) break; - } - g = i; // maximum code length - if(l > i){ - l = i; - } - m[0] = l; - - // Adjust last length count to fill out codes, if needed - for (y = 1 << j; j < i; j++, y <<= 1){ - if ((y -= c[j]) < 0){ - return Z_DATA_ERROR; - } - } - if ((y -= c[i]) < 0){ - return Z_DATA_ERROR; - } - c[i] += y; - - // Generate starting offsets into the value table for each length - x[1] = j = 0; - p = 1; xp = 2; - while (--i!=0) { // note that i == g from above - x[xp] = (j += c[p]); - xp++; - p++; - } - - // Make a table of values in order of bit lengths - i = 0; p = 0; - do { - if ((j = b[bindex+p]) != 0){ - v[x[j]++] = i; - } - p++; - } - while (++i < n); - n = x[g]; // set n to length of v - - // Generate the Huffman codes and for each, make the table entries - x[0] = i = 0; // first Huffman code is zero - p = 0; // grab values in bit order - h = -1; // no tables yet--level -1 - w = -l; // bits decoded == (l * h) - u[0] = 0; // just to keep compilers happy - q = 0; // ditto - z = 0; // ditto - - // go through the bit lengths (k already is bits in shortest code) - for (; k <= g; k++){ - a = c[k]; - while (a--!=0){ - // here i is the Huffman code of length k bits for value *p - // make tables up to required level - while (k > w + l){ - h++; - w += l; // previous table always l bits - // compute minimum size table less than or equal to l bits - z = g - w; - z = (z > l) ? l : z; // table size upper limit - if((f=1<<(j=k-w))>a+1){ // try a k-w bit table - // too few codes for k-w bit table - f -= a + 1; // deduct codes from patterns left - xp = k; - if(j < z){ - while (++j < z){ // try smaller tables up to z bits - if((f <<= 1) <= c[++xp]) - break; // enough codes to use up j bits - f -= c[xp]; // else deduct codes from patterns - } - } - } - z = 1 << j; // table entries for j-bit table - - // allocate new table - if (hn[0] + z > MANY){ // (note: doesn't matter for fixed) - return Z_DATA_ERROR; // overflow of MANY - } - u[h] = q = /*hp+*/ hn[0]; // DEBUG - hn[0] += z; - - // connect to last table, if there is one - if(h!=0){ - x[h]=i; // save pattern for backing up - r[0]=(byte)j; // bits in this table - r[1]=(byte)l; // bits to dump before this table - j=i>>>(w - l); - r[2] = (int)(q - u[h-1] - j); // offset to this table - System.arraycopy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table - } - else{ - t[0] = q; // first table is returned result - } - } - - // set up table entry in r - r[1] = (byte)(k - w); - if (p >= n){ - r[0] = 128 + 64; // out of values--invalid code - } - else if (v[p] < s){ - r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block - r[2] = v[p++]; // simple code is just the value - } - else{ - r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists - r[2]=d[v[p++] - s]; - } - - // fill code-like entries with r - f=1<<(k-w); - for (j=i>>>w;j<z;j+=f){ - System.arraycopy(r, 0, hp, (q+j)*3, 3); - } - - // backwards increment the k-bit code i - for (j = 1 << (k - 1); (i & j)!=0; j >>>= 1){ - i ^= j; - } - i ^= j; - - // backup over finished tables - mask = (1 << w) - 1; // needed on HP, cc -O bug - while ((i & mask) != x[h]){ - h--; // don't need to update q - w -= l; - mask = (1 << w) - 1; - } - } - } - // Return Z_BUF_ERROR if we were given an incomplete table - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; - } - - int inflate_trees_bits(int[] c, // 19 code lengths - int[] bb, // bits tree desired/actual depth - int[] tb, // bits tree result - int[] hp, // space for trees - ZStream z // for messages - ){ - int result; - initWorkArea(19); - hn[0]=0; - result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v); - - if(result == Z_DATA_ERROR){ - z.msg = "oversubscribed dynamic bit lengths tree"; - } - else if(result == Z_BUF_ERROR || bb[0] == 0){ - z.msg = "incomplete dynamic bit lengths tree"; - result = Z_DATA_ERROR; - } - return result; - } - - int inflate_trees_dynamic(int nl, // number of literal/length codes - int nd, // number of distance codes - int[] c, // that many (total) code lengths - int[] bl, // literal desired/actual bit depth - int[] bd, // distance desired/actual bit depth - int[] tl, // literal/length tree result - int[] td, // distance tree result - int[] hp, // space for trees - ZStream z // for messages - ){ - int result; - - // build literal/length tree - initWorkArea(288); - hn[0]=0; - result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v); - if (result != Z_OK || bl[0] == 0){ - if(result == Z_DATA_ERROR){ - z.msg = "oversubscribed literal/length tree"; - } - else if (result != Z_MEM_ERROR){ - z.msg = "incomplete literal/length tree"; - result = Z_DATA_ERROR; - } - return result; - } - - // build distance tree - initWorkArea(288); - result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v); - - if (result != Z_OK || (bd[0] == 0 && nl > 257)){ - if (result == Z_DATA_ERROR){ - z.msg = "oversubscribed distance tree"; - } - else if (result == Z_BUF_ERROR) { - z.msg = "incomplete distance tree"; - result = Z_DATA_ERROR; - } - else if (result != Z_MEM_ERROR){ - z.msg = "empty distance tree with lengths"; - result = Z_DATA_ERROR; - } - return result; - } - - return Z_OK; - } - - static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth - int[] bd, //distance desired/actual bit depth - int[][] tl,//literal/length tree result - int[][] td,//distance tree result - ZStream z //for memory allocation - ){ - bl[0]=fixed_bl; - bd[0]=fixed_bd; - tl[0]=fixed_tl; - td[0]=fixed_td; - return Z_OK; - } - - private void initWorkArea(int vsize){ - if(hn==null){ - hn=new int[1]; - v=new int[vsize]; - c=new int[BMAX+1]; - r=new int[3]; - u=new int[BMAX]; - x=new int[BMAX+1]; - } - if(v.length<vsize){ v=new int[vsize]; } - for(int i=0; i<vsize; i++){v[i]=0;} - for(int i=0; i<BMAX+1; i++){c[i]=0;} - for(int i=0; i<3; i++){r[i]=0;} -// for(int i=0; i<BMAX; i++){u[i]=0;} - System.arraycopy(c, 0, u, 0, BMAX); -// for(int i=0; i<BMAX+1; i++){x[i]=0;} - System.arraycopy(c, 0, x, 0, BMAX+1); - } -} diff --git a/src/com/jcraft/jzlib/Inflate.java b/src/com/jcraft/jzlib/Inflate.java deleted file mode 100644 index 30310f6..0000000 --- a/src/com/jcraft/jzlib/Inflate.java +++ /dev/null @@ -1,374 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final class Inflate{ - - static final private int MAX_WBITS=15; // 32K LZ77 window - - // preset dictionary flag in zlib header - static final private int PRESET_DICT=0x20; - - static final int Z_NO_FLUSH=0; - static final int Z_PARTIAL_FLUSH=1; - static final int Z_SYNC_FLUSH=2; - static final int Z_FULL_FLUSH=3; - static final int Z_FINISH=4; - - static final private int Z_DEFLATED=8; - - static final private int Z_OK=0; - static final private int Z_STREAM_END=1; - static final private int Z_NEED_DICT=2; - static final private int Z_ERRNO=-1; - static final private int Z_STREAM_ERROR=-2; - static final private int Z_DATA_ERROR=-3; - static final private int Z_MEM_ERROR=-4; - static final private int Z_BUF_ERROR=-5; - static final private int Z_VERSION_ERROR=-6; - - static final private int METHOD=0; // waiting for method byte - static final private int FLAG=1; // waiting for flag byte - static final private int DICT4=2; // four dictionary check bytes to go - static final private int DICT3=3; // three dictionary check bytes to go - static final private int DICT2=4; // two dictionary check bytes to go - static final private int DICT1=5; // one dictionary check byte to go - static final private int DICT0=6; // waiting for inflateSetDictionary - static final private int BLOCKS=7; // decompressing blocks - static final private int CHECK4=8; // four check bytes to go - static final private int CHECK3=9; // three check bytes to go - static final private int CHECK2=10; // two check bytes to go - static final private int CHECK1=11; // one check byte to go - static final private int DONE=12; // finished check, done - static final private int BAD=13; // got an error--stay here - - int mode; // current inflate mode - - // mode dependent information - int method; // if FLAGS, method byte - - // if CHECK, check values to compare - long[] was=new long[1] ; // computed check value - long need; // stream check value - - // if BAD, inflateSync's marker bytes count - int marker; - - // mode independent information - int nowrap; // flag for no wrapper - int wbits; // log2(window size) (8..15, defaults to 15) - - InfBlocks blocks; // current inflate_blocks state - - int inflateReset(ZStream z){ - if(z == null || z.istate == null) return Z_STREAM_ERROR; - - z.total_in = z.total_out = 0; - z.msg = null; - z.istate.mode = z.istate.nowrap!=0 ? BLOCKS : METHOD; - z.istate.blocks.reset(z, null); - return Z_OK; - } - - int inflateEnd(ZStream z){ - if(blocks != null) - blocks.free(z); - blocks=null; - // ZFREE(z, z->state); - return Z_OK; - } - - int inflateInit(ZStream z, int w){ - z.msg = null; - blocks = null; - - // handle undocumented nowrap option (no zlib header or check) - nowrap = 0; - if(w < 0){ - w = - w; - nowrap = 1; - } - - // set window size - if(w<8 ||w>15){ - inflateEnd(z); - return Z_STREAM_ERROR; - } - wbits=w; - - z.istate.blocks=new InfBlocks(z, - z.istate.nowrap!=0 ? null : this, - 1<<w); - - // reset state - inflateReset(z); - return Z_OK; - } - - int inflate(ZStream z, int f){ - int r; - int b; - - if(z == null || z.istate == null || z.next_in == null) - return Z_STREAM_ERROR; - f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; - r = Z_BUF_ERROR; - while (true){ -//System.out.println("mode: "+z.istate.mode); - switch (z.istate.mode){ - case METHOD: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - if(((z.istate.method = z.next_in[z.next_in_index++])&0xf)!=Z_DEFLATED){ - z.istate.mode = BAD; - z.msg="unknown compression method"; - z.istate.marker = 5; // can't try inflateSync - break; - } - if((z.istate.method>>4)+8>z.istate.wbits){ - z.istate.mode = BAD; - z.msg="invalid window size"; - z.istate.marker = 5; // can't try inflateSync - break; - } - z.istate.mode=FLAG; - case FLAG: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - b = (z.next_in[z.next_in_index++])&0xff; - - if((((z.istate.method << 8)+b) % 31)!=0){ - z.istate.mode = BAD; - z.msg = "incorrect header check"; - z.istate.marker = 5; // can't try inflateSync - break; - } - - if((b&PRESET_DICT)==0){ - z.istate.mode = BLOCKS; - break; - } - z.istate.mode = DICT4; - case DICT4: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; - z.istate.mode=DICT3; - case DICT3: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; - z.istate.mode=DICT2; - case DICT2: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; - z.istate.mode=DICT1; - case DICT1: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - z.istate.need += (z.next_in[z.next_in_index++]&0xffL); - z.adler = z.istate.need; - z.istate.mode = DICT0; - return Z_NEED_DICT; - case DICT0: - z.istate.mode = BAD; - z.msg = "need dictionary"; - z.istate.marker = 0; // can try inflateSync - return Z_STREAM_ERROR; - case BLOCKS: - - r = z.istate.blocks.proc(z, r); - if(r == Z_DATA_ERROR){ - z.istate.mode = BAD; - z.istate.marker = 0; // can try inflateSync - break; - } - if(r == Z_OK){ - r = f; - } - if(r != Z_STREAM_END){ - return r; - } - r = f; - z.istate.blocks.reset(z, z.istate.was); - if(z.istate.nowrap!=0){ - z.istate.mode=DONE; - break; - } - z.istate.mode=CHECK4; - case CHECK4: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L; - z.istate.mode=CHECK3; - case CHECK3: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L; - z.istate.mode = CHECK2; - case CHECK2: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L; - z.istate.mode = CHECK1; - case CHECK1: - - if(z.avail_in==0)return r;r=f; - - z.avail_in--; z.total_in++; - z.istate.need+=(z.next_in[z.next_in_index++]&0xffL); - - if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){ - z.istate.mode = BAD; - z.msg = "incorrect data check"; - z.istate.marker = 5; // can't try inflateSync - break; - } - - z.istate.mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - } - } - - - int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){ - int index=0; - int length = dictLength; - if(z==null || z.istate == null|| z.istate.mode != DICT0) - return Z_STREAM_ERROR; - - if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){ - return Z_DATA_ERROR; - } - - z.adler = z._adler.adler32(0, null, 0, 0); - - if(length >= (1<<z.istate.wbits)){ - length = (1<<z.istate.wbits)-1; - index=dictLength - length; - } - z.istate.blocks.set_dictionary(dictionary, index, length); - z.istate.mode = BLOCKS; - return Z_OK; - } - - static private byte[] mark = {(byte)0, (byte)0, (byte)0xff, (byte)0xff}; - - int inflateSync(ZStream z){ - int n; // number of bytes to look at - int p; // pointer to bytes - int m; // number of marker bytes found in a row - long r, w; // temporaries to save total_in and total_out - - // set up - if(z == null || z.istate == null) - return Z_STREAM_ERROR; - if(z.istate.mode != BAD){ - z.istate.mode = BAD; - z.istate.marker = 0; - } - if((n=z.avail_in)==0) - return Z_BUF_ERROR; - p=z.next_in_index; - m=z.istate.marker; - - // search - while (n!=0 && m < 4){ - if(z.next_in[p] == mark[m]){ - m++; - } - else if(z.next_in[p]!=0){ - m = 0; - } - else{ - m = 4 - m; - } - p++; n--; - } - - // restore - z.total_in += p-z.next_in_index; - z.next_in_index = p; - z.avail_in = n; - z.istate.marker = m; - - // return no joy or set up to restart on a new block - if(m != 4){ - return Z_DATA_ERROR; - } - r=z.total_in; w=z.total_out; - inflateReset(z); - z.total_in=r; z.total_out = w; - z.istate.mode = BLOCKS; - return Z_OK; - } - - // Returns true if inflate is currently at the end of a block generated - // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH - // but removes the length bytes of the resulting empty stored block. When - // decompressing, PPP checks that at the end of input packet, inflate is - // waiting for these length bytes. - int inflateSyncPoint(ZStream z){ - if(z == null || z.istate == null || z.istate.blocks == null) - return Z_STREAM_ERROR; - return z.istate.blocks.sync_point(); - } -} diff --git a/src/com/jcraft/jzlib/JZlib.java b/src/com/jcraft/jzlib/JZlib.java deleted file mode 100644 index b84d7a1..0000000 --- a/src/com/jcraft/jzlib/JZlib.java +++ /dev/null @@ -1,67 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final public class JZlib{ - private static final String version="1.0.2"; - public static String version(){return version;} - - // compression levels - static final public int Z_NO_COMPRESSION=0; - static final public int Z_BEST_SPEED=1; - static final public int Z_BEST_COMPRESSION=9; - static final public int Z_DEFAULT_COMPRESSION=(-1); - - // compression strategy - static final public int Z_FILTERED=1; - static final public int Z_HUFFMAN_ONLY=2; - static final public int Z_DEFAULT_STRATEGY=0; - - static final public int Z_NO_FLUSH=0; - static final public int Z_PARTIAL_FLUSH=1; - static final public int Z_SYNC_FLUSH=2; - static final public int Z_FULL_FLUSH=3; - static final public int Z_FINISH=4; - - static final public int Z_OK=0; - static final public int Z_STREAM_END=1; - static final public int Z_NEED_DICT=2; - static final public int Z_ERRNO=-1; - static final public int Z_STREAM_ERROR=-2; - static final public int Z_DATA_ERROR=-3; - static final public int Z_MEM_ERROR=-4; - static final public int Z_BUF_ERROR=-5; - static final public int Z_VERSION_ERROR=-6; -} diff --git a/src/com/jcraft/jzlib/StaticTree.java b/src/com/jcraft/jzlib/StaticTree.java deleted file mode 100644 index 0f7f577..0000000 --- a/src/com/jcraft/jzlib/StaticTree.java +++ /dev/null @@ -1,149 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final class StaticTree{ - static final private int MAX_BITS=15; - - static final private int BL_CODES=19; - static final private int D_CODES=30; - static final private int LITERALS=256; - static final private int LENGTH_CODES=29; - static final private int L_CODES=(LITERALS+1+LENGTH_CODES); - - // Bit length codes must not exceed MAX_BL_BITS bits - static final int MAX_BL_BITS=7; - - static final short[] static_ltree = { - 12, 8, 140, 8, 76, 8, 204, 8, 44, 8, - 172, 8, 108, 8, 236, 8, 28, 8, 156, 8, - 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, - 252, 8, 2, 8, 130, 8, 66, 8, 194, 8, - 34, 8, 162, 8, 98, 8, 226, 8, 18, 8, - 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, - 114, 8, 242, 8, 10, 8, 138, 8, 74, 8, - 202, 8, 42, 8, 170, 8, 106, 8, 234, 8, - 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, - 186, 8, 122, 8, 250, 8, 6, 8, 134, 8, - 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, - 230, 8, 22, 8, 150, 8, 86, 8, 214, 8, - 54, 8, 182, 8, 118, 8, 246, 8, 14, 8, - 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, - 110, 8, 238, 8, 30, 8, 158, 8, 94, 8, - 222, 8, 62, 8, 190, 8, 126, 8, 254, 8, - 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, - 161, 8, 97, 8, 225, 8, 17, 8, 145, 8, - 81, 8, 209, 8, 49, 8, 177, 8, 113, 8, - 241, 8, 9, 8, 137, 8, 73, 8, 201, 8, - 41, 8, 169, 8, 105, 8, 233, 8, 25, 8, - 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, - 121, 8, 249, 8, 5, 8, 133, 8, 69, 8, - 197, 8, 37, 8, 165, 8, 101, 8, 229, 8, - 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, - 181, 8, 117, 8, 245, 8, 13, 8, 141, 8, - 77, 8, 205, 8, 45, 8, 173, 8, 109, 8, - 237, 8, 29, 8, 157, 8, 93, 8, 221, 8, - 61, 8, 189, 8, 125, 8, 253, 8, 19, 9, - 275, 9, 147, 9, 403, 9, 83, 9, 339, 9, - 211, 9, 467, 9, 51, 9, 307, 9, 179, 9, - 435, 9, 115, 9, 371, 9, 243, 9, 499, 9, - 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, - 331, 9, 203, 9, 459, 9, 43, 9, 299, 9, - 171, 9, 427, 9, 107, 9, 363, 9, 235, 9, - 491, 9, 27, 9, 283, 9, 155, 9, 411, 9, - 91, 9, 347, 9, 219, 9, 475, 9, 59, 9, - 315, 9, 187, 9, 443, 9, 123, 9, 379, 9, - 251, 9, 507, 9, 7, 9, 263, 9, 135, 9, - 391, 9, 71, 9, 327, 9, 199, 9, 455, 9, - 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, - 359, 9, 231, 9, 487, 9, 23, 9, 279, 9, - 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, - 471, 9, 55, 9, 311, 9, 183, 9, 439, 9, - 119, 9, 375, 9, 247, 9, 503, 9, 15, 9, - 271, 9, 143, 9, 399, 9, 79, 9, 335, 9, - 207, 9, 463, 9, 47, 9, 303, 9, 175, 9, - 431, 9, 111, 9, 367, 9, 239, 9, 495, 9, - 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, - 351, 9, 223, 9, 479, 9, 63, 9, 319, 9, - 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, - 511, 9, 0, 7, 64, 7, 32, 7, 96, 7, - 16, 7, 80, 7, 48, 7, 112, 7, 8, 7, - 72, 7, 40, 7, 104, 7, 24, 7, 88, 7, - 56, 7, 120, 7, 4, 7, 68, 7, 36, 7, - 100, 7, 20, 7, 84, 7, 52, 7, 116, 7, - 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, - 163, 8, 99, 8, 227, 8 - }; - - static final short[] static_dtree = { - 0, 5, 16, 5, 8, 5, 24, 5, 4, 5, - 20, 5, 12, 5, 28, 5, 2, 5, 18, 5, - 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, - 30, 5, 1, 5, 17, 5, 9, 5, 25, 5, - 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, - 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 - }; - - static StaticTree static_l_desc = - new StaticTree(static_ltree, Tree.extra_lbits, - LITERALS+1, L_CODES, MAX_BITS); - - static StaticTree static_d_desc = - new StaticTree(static_dtree, Tree.extra_dbits, - 0, D_CODES, MAX_BITS); - - static StaticTree static_bl_desc = - new StaticTree(null, Tree.extra_blbits, - 0, BL_CODES, MAX_BL_BITS); - - short[] static_tree; // static tree or null - int[] extra_bits; // extra bits for each code or null - int extra_base; // base index for extra_bits - int elems; // max number of elements in the tree - int max_length; // max bit length for the codes - - StaticTree(short[] static_tree, - int[] extra_bits, - int extra_base, - int elems, - int max_length - ){ - this.static_tree=static_tree; - this.extra_bits=extra_bits; - this.extra_base=extra_base; - this.elems=elems; - this.max_length=max_length; - } -} diff --git a/src/com/jcraft/jzlib/Tree.java b/src/com/jcraft/jzlib/Tree.java deleted file mode 100644 index 8103897..0000000 --- a/src/com/jcraft/jzlib/Tree.java +++ /dev/null @@ -1,365 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final class Tree{ - static final private int MAX_BITS=15; - static final private int BL_CODES=19; - static final private int D_CODES=30; - static final private int LITERALS=256; - static final private int LENGTH_CODES=29; - static final private int L_CODES=(LITERALS+1+LENGTH_CODES); - static final private int HEAP_SIZE=(2*L_CODES+1); - - // Bit length codes must not exceed MAX_BL_BITS bits - static final int MAX_BL_BITS=7; - - // end of block literal code - static final int END_BLOCK=256; - - // repeat previous bit length 3-6 times (2 bits of repeat count) - static final int REP_3_6=16; - - // repeat a zero length 3-10 times (3 bits of repeat count) - static final int REPZ_3_10=17; - - // repeat a zero length 11-138 times (7 bits of repeat count) - static final int REPZ_11_138=18; - - // extra bits for each length code - static final int[] extra_lbits={ - 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0 - }; - - // extra bits for each distance code - static final int[] extra_dbits={ - 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 - }; - - // extra bits for each bit length code - static final int[] extra_blbits={ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7 - }; - - static final byte[] bl_order={ - 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; - - - // The lengths of the bit length codes are sent in order of decreasing - // probability, to avoid transmitting the lengths for unused bit - // length codes. - - static final int Buf_size=8*2; - - // see definition of array dist_code below - static final int DIST_CODE_LEN=512; - - static final byte[] _dist_code = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, - 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, - 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 - }; - - static final byte[] _length_code={ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, - 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, - 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, - 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 - }; - - static final int[] base_length = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, - 64, 80, 96, 112, 128, 160, 192, 224, 0 - }; - - static final int[] base_dist = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 - }; - - // Mapping from a distance to a distance code. dist is the distance - 1 and - // must not have side effects. _dist_code[256] and _dist_code[257] are never - // used. - static int d_code(int dist){ - return ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>>7)]); - } - - short[] dyn_tree; // the dynamic tree - int max_code; // largest code with non zero frequency - StaticTree stat_desc; // the corresponding static tree - - // Compute the optimal bit lengths for a tree and update the total bit length - // for the current block. - // IN assertion: the fields freq and dad are set, heap[heap_max] and - // above are the tree nodes sorted by increasing frequency. - // OUT assertions: the field len is set to the optimal bit length, the - // array bl_count contains the frequencies for each bit length. - // The length opt_len is updated; static_len is also updated if stree is - // not null. - void gen_bitlen(Deflate s){ - short[] tree = dyn_tree; - short[] stree = stat_desc.static_tree; - int[] extra = stat_desc.extra_bits; - int base = stat_desc.extra_base; - int max_length = stat_desc.max_length; - int h; // heap index - int n, m; // iterate over the tree elements - int bits; // bit length - int xbits; // extra bits - short f; // frequency - int overflow = 0; // number of elements with bit length too large - - for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0; - - // In a first pass, compute the optimal bit lengths (which may - // overflow in the case of the bit length tree). - tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap - - for(h=s.heap_max+1; h<HEAP_SIZE; h++){ - n = s.heap[h]; - bits = tree[tree[n*2+1]*2+1] + 1; - if (bits > max_length){ bits = max_length; overflow++; } - tree[n*2+1] = (short)bits; - // We overwrite tree[n*2+1] which is no longer needed - - if (n > max_code) continue; // not a leaf node - - s.bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n*2]; - s.opt_len += f * (bits + xbits); - if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits); - } - if (overflow == 0) return; - - // This happens for example on obj2 and pic of the Calgary corpus - // Find the first bit length which could increase: - do { - bits = max_length-1; - while(s.bl_count[bits]==0) bits--; - s.bl_count[bits]--; // move one leaf down the tree - s.bl_count[bits+1]+=2; // move one overflow item as its brother - s.bl_count[max_length]--; - // The brother of the overflow item also moves one step up, - // but this does not affect bl_count[max_length] - overflow -= 2; - } - while (overflow > 0); - - for (bits = max_length; bits != 0; bits--) { - n = s.bl_count[bits]; - while (n != 0) { - m = s.heap[--h]; - if (m > max_code) continue; - if (tree[m*2+1] != bits) { - s.opt_len += ((long)bits - (long)tree[m*2+1])*(long)tree[m*2]; - tree[m*2+1] = (short)bits; - } - n--; - } - } - } - - // Construct one Huffman tree and assigns the code bit strings and lengths. - // Update the total bit length for the current block. - // IN assertion: the field freq is set for all tree elements. - // OUT assertions: the fields len and code are set to the optimal bit length - // and corresponding code. The length opt_len is updated; static_len is - // also updated if stree is not null. The field max_code is set. - void build_tree(Deflate s){ - short[] tree=dyn_tree; - short[] stree=stat_desc.static_tree; - int elems=stat_desc.elems; - int n, m; // iterate over heap elements - int max_code=-1; // largest code with non zero frequency - int node; // new node being created - - // Construct the initial heap, with least frequent element in - // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - // heap[0] is not used. - s.heap_len = 0; - s.heap_max = HEAP_SIZE; - - for(n=0; n<elems; n++) { - if(tree[n*2] != 0) { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - } - else{ - tree[n*2+1] = 0; - } - } - - // The pkzip format requires that at least one distance code exists, - // and that at least one bit should be sent even if there is only one - // possible code. So to avoid special checks later on we force at least - // two codes of non zero frequency. - while (s.heap_len < 2) { - node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); - tree[node*2] = 1; - s.depth[node] = 0; - s.opt_len--; if (stree!=null) s.static_len -= stree[node*2+1]; - // node is 0 or 1 so it does not have extra bits - } - this.max_code = max_code; - - // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - // establish sub-heaps of increasing lengths: - - for(n=s.heap_len/2;n>=1; n--) - s.pqdownheap(tree, n); - - // Construct the Huffman tree by repeatedly combining the least two - // frequent nodes. - - node=elems; // next internal node of the tree - do{ - // n = node of least frequency - n=s.heap[1]; - s.heap[1]=s.heap[s.heap_len--]; - s.pqdownheap(tree, 1); - m=s.heap[1]; // m = node of next least frequency - - s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency - s.heap[--s.heap_max] = m; - - // Create a new node father of n and m - tree[node*2] = (short)(tree[n*2] + tree[m*2]); - s.depth[node] = (byte)(Math.max(s.depth[n],s.depth[m])+1); - tree[n*2+1] = tree[m*2+1] = (short)node; - - // and insert the new node in the heap - s.heap[1] = node++; - s.pqdownheap(tree, 1); - } - while(s.heap_len>=2); - - s.heap[--s.heap_max] = s.heap[1]; - - // At this point, the fields freq and dad are set. We can now - // generate the bit lengths. - - gen_bitlen(s); - - // The field len is now set, we can generate the bit codes - gen_codes(tree, max_code, s.bl_count); - } - - // Generate the codes for a given tree and bit counts (which need not be - // optimal). - // IN assertion: the array bl_count contains the bit length statistics for - // the given tree and the field len is set for all tree elements. - // OUT assertion: the field code is set for all tree elements of non - // zero code length. - static void gen_codes(short[] tree, // the tree to decorate - int max_code, // largest code with non zero frequency - short[] bl_count // number of codes at each bit length - ){ - short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length - short code = 0; // running code value - int bits; // bit index - int n; // code index - - // The distribution counts are first used to generate the code values - // without bit reversal. - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1); - } - - // Check that the bit counts in bl_count are consistent. The last code - // must be all ones. - //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, - // "inconsistent bit counts"); - //Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); - - for (n = 0; n <= max_code; n++) { - int len = tree[n*2+1]; - if (len == 0) continue; - // Now reverse the bits - tree[n*2] = (short)(bi_reverse(next_code[len]++, len)); - } - } - - // Reverse the first len bits of a code, using straightforward code (a faster - // method would use a table) - // IN assertion: 1 <= len <= 15 - static int bi_reverse(int code, // the value to invert - int len // its bit length - ){ - int res = 0; - do{ - res|=code&1; - code>>>=1; - res<<=1; - } - while(--len>0); - return res>>>1; - } -} - diff --git a/src/com/jcraft/jzlib/ZInputStream.java b/src/com/jcraft/jzlib/ZInputStream.java deleted file mode 100644 index 3f97c44..0000000 --- a/src/com/jcraft/jzlib/ZInputStream.java +++ /dev/null @@ -1,149 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ -/* -Copyright (c) 2001 Lapo Luchini. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS -OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; -import java.io.*; - -public class ZInputStream extends FilterInputStream { - - protected ZStream z=new ZStream(); - protected int bufsize=512; - protected int flush=JZlib.Z_NO_FLUSH; - protected byte[] buf=new byte[bufsize], - buf1=new byte[1]; - protected boolean compress; - - protected InputStream in=null; - - public ZInputStream(InputStream in) { - this(in, false); - } - public ZInputStream(InputStream in, boolean nowrap) { - super(in); - this.in=in; - z.inflateInit(nowrap); - compress=false; - z.next_in=buf; - z.next_in_index=0; - z.avail_in=0; - } - - public ZInputStream(InputStream in, int level) { - super(in); - this.in=in; - z.deflateInit(level); - compress=true; - z.next_in=buf; - z.next_in_index=0; - z.avail_in=0; - } - - /*public int available() throws IOException { - return inf.finished() ? 0 : 1; - }*/ - - public int read() throws IOException { - if(read(buf1, 0, 1)==-1) - return(-1); - return(buf1[0]&0xFF); - } - - private boolean nomoreinput=false; - - public int read(byte[] b, int off, int len) throws IOException { - if(len==0) - return(0); - int err; - z.next_out=b; - z.next_out_index=off; - z.avail_out=len; - do { - if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it - z.next_in_index=0; - z.avail_in=in.read(buf, 0, bufsize);//(bufsize<z.avail_out ? bufsize : z.avail_out)); - if(z.avail_in==-1) { - z.avail_in=0; - nomoreinput=true; - } - } - if(compress) - err=z.deflate(flush); - else - err=z.inflate(flush); - if(nomoreinput&&(err==JZlib.Z_BUF_ERROR)) - return(-1); - if(err!=JZlib.Z_OK && err!=JZlib.Z_STREAM_END) - throw new ZStreamException((compress ? "de" : "in")+"flating: "+z.msg); - if((nomoreinput||err==JZlib.Z_STREAM_END)&&(z.avail_out==len)) - return(-1); - } - while(z.avail_out==len&&err==JZlib.Z_OK); - //System.err.print("("+(len-z.avail_out)+")"); - return(len-z.avail_out); - } - - public long skip(long n) throws IOException { - int len=512; - if(n<len) - len=(int)n; - byte[] tmp=new byte[len]; - return((long)read(tmp)); - } - - public int getFlushMode() { - return(flush); - } - - public void setFlushMode(int flush) { - this.flush=flush; - } - - /** - * Returns the total number of bytes input so far. - */ - public long getTotalIn() { - return z.total_in; - } - - /** - * Returns the total number of bytes output so far. - */ - public long getTotalOut() { - return z.total_out; - } - - public void close() throws IOException{ - in.close(); - } -} diff --git a/src/com/jcraft/jzlib/ZOutputStream.java b/src/com/jcraft/jzlib/ZOutputStream.java deleted file mode 100644 index afee65b..0000000 --- a/src/com/jcraft/jzlib/ZOutputStream.java +++ /dev/null @@ -1,156 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ -/* -Copyright (c) 2001 Lapo Luchini. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS -OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; -import java.io.*; - -public class ZOutputStream extends OutputStream { - - protected ZStream z=new ZStream(); - protected int bufsize=512; - protected int flush=JZlib.Z_NO_FLUSH; - protected byte[] buf=new byte[bufsize], - buf1=new byte[1]; - protected boolean compress; - - protected OutputStream out; - - public ZOutputStream(OutputStream out) { - super(); - this.out=out; - z.inflateInit(); - compress=false; - } - - public ZOutputStream(OutputStream out, int level) { - this(out, level, false); - } - public ZOutputStream(OutputStream out, int level, boolean nowrap) { - super(); - this.out=out; - z.deflateInit(level, nowrap); - compress=true; - } - - public void write(int b) throws IOException { - buf1[0]=(byte)b; - write(buf1, 0, 1); - } - - public void write(byte b[], int off, int len) throws IOException { - if(len==0) - return; - int err; - z.next_in=b; - z.next_in_index=off; - z.avail_in=len; - do{ - z.next_out=buf; - z.next_out_index=0; - z.avail_out=bufsize; - if(compress) - err=z.deflate(flush); - else - err=z.inflate(flush); - if(err!=JZlib.Z_OK) - throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg); - out.write(buf, 0, bufsize-z.avail_out); - } - while(z.avail_in>0 || z.avail_out==0); - } - - public int getFlushMode() { - return(flush); - } - - public void setFlushMode(int flush) { - this.flush=flush; - } - - public void finish() throws IOException { - int err; - do{ - z.next_out=buf; - z.next_out_index=0; - z.avail_out=bufsize; - if(compress){ err=z.deflate(JZlib.Z_FINISH); } - else{ err=z.inflate(JZlib.Z_FINISH); } - if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK) - throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg); - if(bufsize-z.avail_out>0){ - out.write(buf, 0, bufsize-z.avail_out); - } - } - while(z.avail_in>0 || z.avail_out==0); - flush(); - } - public void end() { - if(z==null) - return; - if(compress){ z.deflateEnd(); } - else{ z.inflateEnd(); } - z.free(); - z=null; - } - public void close() throws IOException { - try{ - try{finish();} - catch (IOException ignored) {} - } - finally{ - end(); - out.close(); - out=null; - } - } - - /** - * Returns the total number of bytes input so far. - */ - public long getTotalIn() { - return z.total_in; - } - - /** - * Returns the total number of bytes output so far. - */ - public long getTotalOut() { - return z.total_out; - } - - public void flush() throws IOException { - out.flush(); - } - -} diff --git a/src/com/jcraft/jzlib/ZStream.java b/src/com/jcraft/jzlib/ZStream.java deleted file mode 100644 index 334475e..0000000 --- a/src/com/jcraft/jzlib/ZStream.java +++ /dev/null @@ -1,211 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -final public class ZStream{ - - static final private int MAX_WBITS=15; // 32K LZ77 window - static final private int DEF_WBITS=MAX_WBITS; - - static final private int Z_NO_FLUSH=0; - static final private int Z_PARTIAL_FLUSH=1; - static final private int Z_SYNC_FLUSH=2; - static final private int Z_FULL_FLUSH=3; - static final private int Z_FINISH=4; - - static final private int MAX_MEM_LEVEL=9; - - static final private int Z_OK=0; - static final private int Z_STREAM_END=1; - static final private int Z_NEED_DICT=2; - static final private int Z_ERRNO=-1; - static final private int Z_STREAM_ERROR=-2; - static final private int Z_DATA_ERROR=-3; - static final private int Z_MEM_ERROR=-4; - static final private int Z_BUF_ERROR=-5; - static final private int Z_VERSION_ERROR=-6; - - public byte[] next_in; // next input byte - public int next_in_index; - public int avail_in; // number of bytes available at next_in - public long total_in; // total nb of input bytes read so far - - public byte[] next_out; // next output byte should be put there - public int next_out_index; - public int avail_out; // remaining free space at next_out - public long total_out; // total nb of bytes output so far - - public String msg; - - Deflate dstate; - Inflate istate; - - int data_type; // best guess about the data type: ascii or binary - - public long adler; - Adler32 _adler=new Adler32(); - - public int inflateInit(){ - return inflateInit(DEF_WBITS); - } - public int inflateInit(boolean nowrap){ - return inflateInit(DEF_WBITS, nowrap); - } - public int inflateInit(int w){ - return inflateInit(w, false); - } - - public int inflateInit(int w, boolean nowrap){ - istate=new Inflate(); - return istate.inflateInit(this, nowrap?-w:w); - } - - public int inflate(int f){ - if(istate==null) return Z_STREAM_ERROR; - return istate.inflate(this, f); - } - public int inflateEnd(){ - if(istate==null) return Z_STREAM_ERROR; - int ret=istate.inflateEnd(this); - istate = null; - return ret; - } - public int inflateSync(){ - if(istate == null) - return Z_STREAM_ERROR; - return istate.inflateSync(this); - } - public int inflateSetDictionary(byte[] dictionary, int dictLength){ - if(istate == null) - return Z_STREAM_ERROR; - return istate.inflateSetDictionary(this, dictionary, dictLength); - } - - public int deflateInit(int level){ - return deflateInit(level, MAX_WBITS); - } - public int deflateInit(int level, boolean nowrap){ - return deflateInit(level, MAX_WBITS, nowrap); - } - public int deflateInit(int level, int bits){ - return deflateInit(level, bits, false); - } - public int deflateInit(int level, int bits, boolean nowrap){ - dstate=new Deflate(); - return dstate.deflateInit(this, level, nowrap?-bits:bits); - } - public int deflate(int flush){ - if(dstate==null){ - return Z_STREAM_ERROR; - } - return dstate.deflate(this, flush); - } - public int deflateEnd(){ - if(dstate==null) return Z_STREAM_ERROR; - int ret=dstate.deflateEnd(); - dstate=null; - return ret; - } - public int deflateParams(int level, int strategy){ - if(dstate==null) return Z_STREAM_ERROR; - return dstate.deflateParams(this, level, strategy); - } - public int deflateSetDictionary (byte[] dictionary, int dictLength){ - if(dstate == null) - return Z_STREAM_ERROR; - return dstate.deflateSetDictionary(this, dictionary, dictLength); - } - - // Flush as much pending output as possible. All deflate() output goes - // through this function so some applications may wish to modify it - // to avoid allocating a large strm->next_out buffer and copying into it. - // (See also read_buf()). - void flush_pending(){ - int len=dstate.pending; - - if(len>avail_out) len=avail_out; - if(len==0) return; - - if(dstate.pending_buf.length<=dstate.pending_out || - next_out.length<=next_out_index || - dstate.pending_buf.length<(dstate.pending_out+len) || - next_out.length<(next_out_index+len)){ - System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+ - ", "+next_out.length+", "+next_out_index+", "+len); - System.out.println("avail_out="+avail_out); - } - - System.arraycopy(dstate.pending_buf, dstate.pending_out, - next_out, next_out_index, len); - - next_out_index+=len; - dstate.pending_out+=len; - total_out+=len; - avail_out-=len; - dstate.pending-=len; - if(dstate.pending==0){ - dstate.pending_out=0; - } - } - - // Read a new buffer from the current input stream, update the adler32 - // and total number of bytes read. All deflate() input goes through - // this function so some applications may wish to modify it to avoid - // allocating a large strm->next_in buffer and copying from it. - // (See also flush_pending()). - int read_buf(byte[] buf, int start, int size) { - int len=avail_in; - - if(len>size) len=size; - if(len==0) return 0; - - avail_in-=len; - - if(dstate.noheader==0) { - adler=_adler.adler32(adler, next_in, next_in_index, len); - } - System.arraycopy(next_in, next_in_index, buf, start, len); - next_in_index += len; - total_in += len; - return len; - } - - public void free(){ - next_in=null; - next_out=null; - msg=null; - _adler=null; - } -} diff --git a/src/com/jcraft/jzlib/ZStreamException.java b/src/com/jcraft/jzlib/ZStreamException.java deleted file mode 100644 index 308bb8a..0000000 --- a/src/com/jcraft/jzlib/ZStreamException.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -*-mode:java; c-basic-offset:2; -*- */ -/* -Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, -INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/* - * This program is based on zlib-1.1.3, so all credit should go authors - * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) - * and contributors of zlib. - */ - -package com.jcraft.jzlib; - -public class ZStreamException extends java.io.IOException { - public ZStreamException() { - super(); - } - public ZStreamException(String s) { - super(s); - } -} diff --git a/src/com/trilead/ssh2/AuthAgentCallback.java b/src/com/trilead/ssh2/AuthAgentCallback.java deleted file mode 100644 index 7fe270b..0000000 --- a/src/com/trilead/ssh2/AuthAgentCallback.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.trilead.ssh2; - -import java.security.KeyPair; -import java.util.Map; - -/** - * AuthAgentCallback. - * - * @author Kenny Root - * @version $Id$ - */ -public interface AuthAgentCallback { - - /** - * @return array of blobs containing the OpenSSH-format encoded public keys - */ - Map<String,byte[]> retrieveIdentities(); - - /** - * @param key A <code>RSAPrivateKey</code> or <code>DSAPrivateKey</code> - * containing a DSA or RSA private key of - * the user in Trilead object format. - * @param comment comment associated with this key - * @param confirmUse whether to prompt before using this key - * @param lifetime lifetime in seconds for key to be remembered - * @return success or failure - */ - boolean addIdentity(KeyPair pair, String comment, boolean confirmUse, int lifetime); - - /** - * @param publicKey byte blob containing the OpenSSH-format encoded public key - * @return success or failure - */ - boolean removeIdentity(byte[] publicKey); - - /** - * @return success or failure - */ - boolean removeAllIdentities(); - - /** - * @param publicKey byte blob containing the OpenSSH-format encoded public key - * @return A <code>RSAPrivateKey</code> or <code>DSAPrivateKey</code> - * containing a DSA or RSA private key of - * the user in Trilead object format. - */ - KeyPair getKeyPair(byte[] publicKey); - - /** - * @return - */ - boolean isAgentLocked(); - - /** - * @param lockPassphrase - */ - boolean setAgentLock(String lockPassphrase); - - /** - * @param unlockPassphrase - * @return - */ - boolean requestAgentUnlock(String unlockPassphrase); -} diff --git a/src/com/trilead/ssh2/ChannelCondition.java b/src/com/trilead/ssh2/ChannelCondition.java deleted file mode 100644 index df1ad50..0000000 --- a/src/com/trilead/ssh2/ChannelCondition.java +++ /dev/null @@ -1,61 +0,0 @@ - -package com.trilead.ssh2; - -/** - * Contains constants that can be used to specify what conditions to wait for on - * a SSH-2 channel (e.g., represented by a {@link Session}). - * - * @see Session#waitForCondition(int, long) - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ChannelCondition.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public abstract interface ChannelCondition -{ - /** - * A timeout has occurred, none of your requested conditions is fulfilled. - * However, other conditions may be true - therefore, NEVER use the "==" - * operator to test for this (or any other) condition. Always use - * something like <code>((cond & ChannelCondition.CLOSED) != 0)</code>. - */ - public static final int TIMEOUT = 1; - - /** - * The underlying SSH-2 channel, however not necessarily the whole connection, - * has been closed. This implies <code>EOF</code>. Note that there may still - * be unread stdout or stderr data in the local window, i.e, <code>STDOUT_DATA</code> - * or/and <code>STDERR_DATA</code> may be set at the same time. - */ - public static final int CLOSED = 2; - - /** - * There is stdout data available that is ready to be consumed. - */ - public static final int STDOUT_DATA = 4; - - /** - * There is stderr data available that is ready to be consumed. - */ - public static final int STDERR_DATA = 8; - - /** - * EOF on has been reached, no more _new_ stdout or stderr data will arrive - * from the remote server. However, there may be unread stdout or stderr - * data, i.e, <code>STDOUT_DATA</code> or/and <code>STDERR_DATA</code> - * may be set at the same time. - */ - public static final int EOF = 16; - - /** - * The exit status of the remote process is available. - * Some servers never send the exist status, or occasionally "forget" to do so. - */ - public static final int EXIT_STATUS = 32; - - /** - * The exit signal of the remote process is available. - */ - public static final int EXIT_SIGNAL = 64; - -} diff --git a/src/com/trilead/ssh2/Connection.java b/src/com/trilead/ssh2/Connection.java deleted file mode 100644 index 163fdb5..0000000 --- a/src/com/trilead/ssh2/Connection.java +++ /dev/null @@ -1,1628 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.CharArrayWriter; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketTimeoutException; -import java.security.KeyPair; -import java.security.SecureRandom; -import java.security.Security; -import java.util.Set; -import java.util.Vector; - -import com.trilead.ssh2.auth.AuthenticationManager; -import com.trilead.ssh2.channel.ChannelManager; -import com.trilead.ssh2.crypto.CryptoWishList; -import com.trilead.ssh2.crypto.cipher.BlockCipherFactory; -import com.trilead.ssh2.crypto.digest.MAC; -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.PacketIgnore; -import com.trilead.ssh2.transport.KexManager; -import com.trilead.ssh2.transport.TransportManager; -import com.trilead.ssh2.util.TimeoutService; -import com.trilead.ssh2.util.TimeoutService.TimeoutToken; - -/** - * A <code>Connection</code> is used to establish an encrypted TCP/IP - * connection to a SSH-2 server. - * <p> - * Typically, one - * <ol> - * <li>creates a {@link #Connection(String) Connection} object.</li> - * <li>calls the {@link #connect() connect()} method.</li> - * <li>calls some of the authentication methods (e.g., - * {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}).</li> - * <li>calls one or several times the {@link #openSession() openSession()} - * method.</li> - * <li>finally, one must close the connection and release resources with the - * {@link #close() close()} method.</li> - * </ol> - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Connection.java,v 1.3 2008/04/01 12:38:09 cplattne Exp $ - */ - -public class Connection -{ - /** - * The identifier presented to the SSH-2 server. - */ - public final static String identification = "TrileadSSH2Java_213"; - - /** - * Will be used to generate all random data needed for the current - * connection. Note: SecureRandom.nextBytes() is thread safe. - */ - private SecureRandom generator; - - /** - * Unless you know what you are doing, you will never need this. - * - * @return The list of supported cipher algorithms by this implementation. - */ - public static synchronized String[] getAvailableCiphers() - { - return BlockCipherFactory.getDefaultCipherList(); - } - - /** - * Unless you know what you are doing, you will never need this. - * - * @return The list of supported MAC algorthims by this implementation. - */ - public static synchronized String[] getAvailableMACs() - { - return MAC.getMacList(); - } - - /** - * Unless you know what you are doing, you will never need this. - * - * @return The list of supported server host key algorthims by this - * implementation. - */ - public static synchronized String[] getAvailableServerHostKeyAlgorithms() - { - return KexManager.getDefaultServerHostkeyAlgorithmList(); - } - - private AuthenticationManager am; - - private boolean authenticated = false; - private boolean compression = false; - private ChannelManager cm; - - private CryptoWishList cryptoWishList = new CryptoWishList(); - - private DHGexParameters dhgexpara = new DHGexParameters(); - - private final String hostname; - - private final int port; - - private TransportManager tm; - - private boolean tcpNoDelay = false; - - private ProxyData proxyData = null; - - private Vector<ConnectionMonitor> connectionMonitors = new Vector<ConnectionMonitor>(); - - /** - * Prepares a fresh <code>Connection</code> object which can then be used - * to establish a connection to the specified SSH-2 server. - * <p> - * Same as {@link #Connection(String, int) Connection(hostname, 22)}. - * - * @param hostname - * the hostname of the SSH-2 server. - */ - public Connection(String hostname) - { - this(hostname, 22); - } - - /** - * Prepares a fresh <code>Connection</code> object which can then be used - * to establish a connection to the specified SSH-2 server. - * - * @param hostname - * the host where we later want to connect to. - * @param port - * port on the server, normally 22. - */ - public Connection(String hostname, int port) - { - this.hostname = hostname; - this.port = port; - } - - /** - * After a successful connect, one has to authenticate oneself. This method - * is based on DSA (it uses DSA to sign a challenge sent by the server). - * <p> - * If the authentication phase is complete, <code>true</code> will be - * returned. If the server does not accept the request (or if further - * authentication steps are needed), <code>false</code> is returned and - * one can retry either by using this or any other authentication method - * (use the <code>getRemainingAuthMethods</code> method to get a list of - * the remaining possible methods). - * - * @param user - * A <code>String</code> holding the username. - * @param pem - * A <code>String</code> containing the DSA private key of the - * user in OpenSSH key format (PEM, you can't miss the - * "-----BEGIN DSA PRIVATE KEY-----" tag). The string may contain - * linefeeds. - * @param password - * If the PEM string is 3DES encrypted ("DES-EDE3-CBC"), then you - * must specify the password. Otherwise, this argument will be - * ignored and can be set to <code>null</code>. - * - * @return whether the connection is now authenticated. - * @throws IOException - * - * @deprecated You should use one of the - * {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()} - * methods, this method is just a wrapper for it and will - * disappear in future builds. - * - */ - public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException - { - if (tm == null) - throw new IllegalStateException("Connection is not established!"); - - if (authenticated) - throw new IllegalStateException("Connection is already authenticated!"); - - if (am == null) - am = new AuthenticationManager(tm); - - if (cm == null) - cm = new ChannelManager(tm); - - if (user == null) - throw new IllegalArgumentException("user argument is null"); - - if (pem == null) - throw new IllegalArgumentException("pem argument is null"); - - authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND()); - - return authenticated; - } - - /** - * A wrapper that calls - * {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback) - * authenticateWithKeyboardInteractivewith} a <code>null</code> submethod - * list. - * - * @param user - * A <code>String</code> holding the username. - * @param cb - * An <code>InteractiveCallback</code> which will be used to - * determine the responses to the questions asked by the server. - * @return whether the connection is now authenticated. - * @throws IOException - */ - public synchronized boolean authenticateWithKeyboardInteractive(String user, InteractiveCallback cb) - throws IOException - { - return authenticateWithKeyboardInteractive(user, null, cb); - } - - /** - * After a successful connect, one has to authenticate oneself. This method - * is based on "keyboard-interactive", specified in - * draft-ietf-secsh-auth-kbdinteract-XX. Basically, you have to define a - * callback object which will be feeded with challenges generated by the - * server. Answers are then sent back to the server. It is possible that the - * callback will be called several times during the invocation of this - * method (e.g., if the server replies to the callback's answer(s) with - * another challenge...) - * <p> - * If the authentication phase is complete, <code>true</code> will be - * returned. If the server does not accept the request (or if further - * authentication steps are needed), <code>false</code> is returned and - * one can retry either by using this or any other authentication method - * (use the <code>getRemainingAuthMethods</code> method to get a list of - * the remaining possible methods). - * <p> - * Note: some SSH servers advertise "keyboard-interactive", however, any - * interactive request will be denied (without having sent any challenge to - * the client). - * - * @param user - * A <code>String</code> holding the username. - * @param submethods - * An array of submethod names, see - * draft-ietf-secsh-auth-kbdinteract-XX. May be <code>null</code> - * to indicate an empty list. - * @param cb - * An <code>InteractiveCallback</code> which will be used to - * determine the responses to the questions asked by the server. - * - * @return whether the connection is now authenticated. - * @throws IOException - */ - public synchronized boolean authenticateWithKeyboardInteractive(String user, String[] submethods, - InteractiveCallback cb) throws IOException - { - if (cb == null) - throw new IllegalArgumentException("Callback may not ne NULL!"); - - if (tm == null) - throw new IllegalStateException("Connection is not established!"); - - if (authenticated) - throw new IllegalStateException("Connection is already authenticated!"); - - if (am == null) - am = new AuthenticationManager(tm); - - if (cm == null) - cm = new ChannelManager(tm); - - if (user == null) - throw new IllegalArgumentException("user argument is null"); - - authenticated = am.authenticateInteractive(user, submethods, cb); - - return authenticated; - } - - /** - * After a successful connect, one has to authenticate oneself. This method - * sends username and password to the server. - * <p> - * If the authentication phase is complete, <code>true</code> will be - * returned. If the server does not accept the request (or if further - * authentication steps are needed), <code>false</code> is returned and - * one can retry either by using this or any other authentication method - * (use the <code>getRemainingAuthMethods</code> method to get a list of - * the remaining possible methods). - * <p> - * Note: if this method fails, then please double-check that it is actually - * offered by the server (use - * {@link #getRemainingAuthMethods(String) getRemainingAuthMethods()}. - * <p> - * Often, password authentication is disabled, but users are not aware of - * it. Many servers only offer "publickey" and "keyboard-interactive". - * However, even though "keyboard-interactive" *feels* like password - * authentication (e.g., when using the putty or openssh clients) it is - * *not* the same mechanism. - * - * @param user - * @param password - * @return if the connection is now authenticated. - * @throws IOException - */ - public synchronized boolean authenticateWithPassword(String user, String password) throws IOException - { - if (tm == null) - throw new IllegalStateException("Connection is not established!"); - - if (authenticated) - throw new IllegalStateException("Connection is already authenticated!"); - - if (am == null) - am = new AuthenticationManager(tm); - - if (cm == null) - cm = new ChannelManager(tm); - - if (user == null) - throw new IllegalArgumentException("user argument is null"); - - if (password == null) - throw new IllegalArgumentException("password argument is null"); - - authenticated = am.authenticatePassword(user, password); - - return authenticated; - } - - /** - * After a successful connect, one has to authenticate oneself. This method - * can be used to explicitly use the special "none" authentication method - * (where only a username has to be specified). - * <p> - * Note 1: The "none" method may always be tried by clients, however as by - * the specs, the server will not explicitly announce it. In other words, - * the "none" token will never show up in the list returned by - * {@link #getRemainingAuthMethods(String)}. - * <p> - * Note 2: no matter which one of the authenticateWithXXX() methods you - * call, the library will always issue exactly one initial "none" - * authentication request to retrieve the initially allowed list of - * authentication methods by the server. Please read RFC 4252 for the - * details. - * <p> - * If the authentication phase is complete, <code>true</code> will be - * returned. If further authentication steps are needed, <code>false</code> - * is returned and one can retry by any other authentication method (use the - * <code>getRemainingAuthMethods</code> method to get a list of the - * remaining possible methods). - * - * @param user - * @return if the connection is now authenticated. - * @throws IOException - */ - public synchronized boolean authenticateWithNone(String user) throws IOException - { - if (tm == null) - throw new IllegalStateException("Connection is not established!"); - - if (authenticated) - throw new IllegalStateException("Connection is already authenticated!"); - - if (am == null) - am = new AuthenticationManager(tm); - - if (cm == null) - cm = new ChannelManager(tm); - - if (user == null) - throw new IllegalArgumentException("user argument is null"); - - /* Trigger the sending of the PacketUserauthRequestNone packet */ - /* (if not already done) */ - - authenticated = am.authenticateNone(user); - - return authenticated; - } - - /** - * After a successful connect, one has to authenticate oneself. The - * authentication method "publickey" works by signing a challenge sent by - * the server. The signature is either DSA or RSA based - it just depends on - * the type of private key you specify, either a DSA or RSA private key in - * PEM format. And yes, this is may seem to be a little confusing, the - * method is called "publickey" in the SSH-2 protocol specification, however - * since we need to generate a signature, you actually have to supply a - * private key =). - * <p> - * The private key contained in the PEM file may also be encrypted - * ("Proc-Type: 4,ENCRYPTED"). The library supports DES-CBC and DES-EDE3-CBC - * encryption, as well as the more exotic PEM encrpytions AES-128-CBC, - * AES-192-CBC and AES-256-CBC. - * <p> - * If the authentication phase is complete, <code>true</code> will be - * returned. If the server does not accept the request (or if further - * authentication steps are needed), <code>false</code> is returned and - * one can retry either by using this or any other authentication method - * (use the <code>getRemainingAuthMethods</code> method to get a list of - * the remaining possible methods). - * <p> - * NOTE PUTTY USERS: Event though your key file may start with - * "-----BEGIN..." it is not in the expected format. You have to convert it - * to the OpenSSH key format by using the "puttygen" tool (can be downloaded - * from the Putty website). Simply load your key and then use the - * "Conversions/Export OpenSSH key" functionality to get a proper PEM file. - * - * @param user - * A <code>String</code> holding the username. - * @param pemPrivateKey - * A <code>char[]</code> containing a DSA or RSA private key of - * the user in OpenSSH key format (PEM, you can't miss the - * "-----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE - * KEY-----" tag). The char array may contain - * linebreaks/linefeeds. - * @param password - * If the PEM structure is encrypted ("Proc-Type: 4,ENCRYPTED") - * then you must specify a password. Otherwise, this argument - * will be ignored and can be set to <code>null</code>. - * - * @return whether the connection is now authenticated. - * @throws IOException - */ - public synchronized boolean authenticateWithPublicKey(String user, char[] pemPrivateKey, String password) - throws IOException - { - if (tm == null) - throw new IllegalStateException("Connection is not established!"); - - if (authenticated) - throw new IllegalStateException("Connection is already authenticated!"); - - if (am == null) - am = new AuthenticationManager(tm); - - if (cm == null) - cm = new ChannelManager(tm); - - if (user == null) - throw new IllegalArgumentException("user argument is null"); - - if (pemPrivateKey == null) - throw new IllegalArgumentException("pemPrivateKey argument is null"); - - authenticated = am.authenticatePublicKey(user, pemPrivateKey, password, getOrCreateSecureRND()); - - return authenticated; - } - - /** - * After a successful connect, one has to authenticate oneself. The - * authentication method "publickey" works by signing a challenge sent by - * the server. The signature is either DSA or RSA based - it just depends on - * the type of private key you specify, either a DSA or RSA private key in - * PEM format. And yes, this is may seem to be a little confusing, the - * method is called "publickey" in the SSH-2 protocol specification, however - * since we need to generate a signature, you actually have to supply a - * private key =). - * <p> - * If the authentication phase is complete, <code>true</code> will be - * returned. If the server does not accept the request (or if further - * authentication steps are needed), <code>false</code> is returned and - * one can retry either by using this or any other authentication method - * (use the <code>getRemainingAuthMethods</code> method to get a list of - * the remaining possible methods). - * - * @param user - * A <code>String</code> holding the username. - * @param key - * A <code>RSAPrivateKey</code> or <code>DSAPrivateKey</code> - * containing a DSA or RSA private key of - * the user in Trilead object format. - * - * @return whether the connection is now authenticated. - * @throws IOException - */ - public synchronized boolean authenticateWithPublicKey(String user, KeyPair pair) - throws IOException - { - if (tm == null) - throw new IllegalStateException("Connection is not established!"); - - if (authenticated) - throw new IllegalStateException("Connection is already authenticated!"); - - if (am == null) - am = new AuthenticationManager(tm); - - if (cm == null) - cm = new ChannelManager(tm); - - if (user == null) - throw new IllegalArgumentException("user argument is null"); - - if (pair == null) - throw new IllegalArgumentException("Key pair argument is null"); - - authenticated = am.authenticatePublicKey(user, pair, getOrCreateSecureRND()); - - return authenticated; - } - /** - * A convenience wrapper function which reads in a private key (PEM format, - * either DSA or RSA) and then calls - * <code>authenticateWithPublicKey(String, char[], String)</code>. - * <p> - * NOTE PUTTY USERS: Event though your key file may start with - * "-----BEGIN..." it is not in the expected format. You have to convert it - * to the OpenSSH key format by using the "puttygen" tool (can be downloaded - * from the Putty website). Simply load your key and then use the - * "Conversions/Export OpenSSH key" functionality to get a proper PEM file. - * - * @param user - * A <code>String</code> holding the username. - * @param pemFile - * A <code>File</code> object pointing to a file containing a - * DSA or RSA private key of the user in OpenSSH key format (PEM, - * you can't miss the "-----BEGIN DSA PRIVATE KEY-----" or - * "-----BEGIN RSA PRIVATE KEY-----" tag). - * @param password - * If the PEM file is encrypted then you must specify the - * password. Otherwise, this argument will be ignored and can be - * set to <code>null</code>. - * - * @return whether the connection is now authenticated. - * @throws IOException - */ - public synchronized boolean authenticateWithPublicKey(String user, File pemFile, String password) - throws IOException - { - if (pemFile == null) - throw new IllegalArgumentException("pemFile argument is null"); - - char[] buff = new char[256]; - - CharArrayWriter cw = new CharArrayWriter(); - - FileReader fr = new FileReader(pemFile); - - while (true) - { - int len = fr.read(buff); - if (len < 0) - break; - cw.write(buff, 0, len); - } - - fr.close(); - - return authenticateWithPublicKey(user, cw.toCharArray(), password); - } - - /** - * Add a {@link ConnectionMonitor} to this connection. Can be invoked at any - * time, but it is best to add connection monitors before invoking - * <code>connect()</code> to avoid glitches (e.g., you add a connection - * monitor after a successful connect(), but the connection has died in the - * mean time. Then, your connection monitor won't be notified.) - * <p> - * You can add as many monitors as you like. - * - * @see ConnectionMonitor - * - * @param cmon - * An object implementing the <code>ConnectionMonitor</code> - * interface. - */ - public synchronized void addConnectionMonitor(ConnectionMonitor cmon) - { - if (cmon == null) - throw new IllegalArgumentException("cmon argument is null"); - - connectionMonitors.addElement(cmon); - - if (tm != null) - tm.setConnectionMonitors(connectionMonitors); - } - - /** - * Controls whether compression is used on the link or not. - * <p> - * Note: This can only be called before connect() - * @param enabled whether to enable compression - * @throws IOException - */ - public synchronized void setCompression(boolean enabled) throws IOException { - if (tm != null) - throw new IOException("Connection to " + hostname + " is already in connected state!"); - - compression = enabled; - } - - /** - * Close the connection to the SSH-2 server. All assigned sessions will be - * closed, too. Can be called at any time. Don't forget to call this once - * you don't need a connection anymore - otherwise the receiver thread may - * run forever. - */ - public synchronized void close() - { - Throwable t = new Throwable("Closed due to user request."); - close(t, false); - } - - private void close(Throwable t, boolean hard) - { - if (cm != null) - cm.closeAllChannels(); - - if (tm != null) - { - tm.close(t, hard == false); - tm = null; - } - am = null; - cm = null; - authenticated = false; - } - - /** - * Same as - * {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}. - * - * @return see comments for the - * {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} - * method. - * @throws IOException - */ - public synchronized ConnectionInfo connect() throws IOException - { - return connect(null, 0, 0); - } - - /** - * Same as - * {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}. - * - * @return see comments for the - * {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} - * method. - * @throws IOException - */ - public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException - { - return connect(verifier, 0, 0); - } - - /** - * Connect to the SSH-2 server and, as soon as the server has presented its - * host key, use the - * {@link ServerHostKeyVerifier#verifyServerHostKey(String, int, String, - * byte[]) ServerHostKeyVerifier.verifyServerHostKey()} method of the - * <code>verifier</code> to ask for permission to proceed. If - * <code>verifier</code> is <code>null</code>, then any host key will - * be accepted - this is NOT recommended, since it makes man-in-the-middle - * attackes VERY easy (somebody could put a proxy SSH server between you and - * the real server). - * <p> - * Note: The verifier will be called before doing any crypto calculations - * (i.e., diffie-hellman). Therefore, if you don't like the presented host - * key then no CPU cycles are wasted (and the evil server has less - * information about us). - * <p> - * However, it is still possible that the server presented a fake host key: - * the server cheated (typically a sign for a man-in-the-middle attack) and - * is not able to generate a signature that matches its host key. Don't - * worry, the library will detect such a scenario later when checking the - * signature (the signature cannot be checked before having completed the - * diffie-hellman exchange). - * <p> - * Note 2: The {@link ServerHostKeyVerifier#verifyServerHostKey(String, int, - * String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()} method will - * *NOT* be called from the current thread, the call is being made from a - * background thread (there is a background dispatcher thread for every - * established connection). - * <p> - * Note 3: This method will block as long as the key exchange of the - * underlying connection has not been completed (and you have not specified - * any timeouts). - * <p> - * Note 4: If you want to re-use a connection object that was successfully - * connected, then you must call the {@link #close()} method before invoking - * <code>connect()</code> again. - * - * @param verifier - * An object that implements the {@link ServerHostKeyVerifier} - * interface. Pass <code>null</code> to accept any server host - * key - NOT recommended. - * - * @param connectTimeout - * Connect the underlying TCP socket to the server with the given - * timeout value (non-negative, in milliseconds). Zero means no - * timeout. If a proxy is being used (see - * {@link #setProxyData(ProxyData)}), then this timeout is used - * for the connection establishment to the proxy. - * - * @param kexTimeout - * Timeout for complete connection establishment (non-negative, - * in milliseconds). Zero means no timeout. The timeout counts - * from the moment you invoke the connect() method and is - * cancelled as soon as the first key-exchange round has - * finished. It is possible that the timeout event will be fired - * during the invocation of the <code>verifier</code> callback, - * but it will only have an effect after the - * <code>verifier</code> returns. - * - * @return A {@link ConnectionInfo} object containing the details of the - * established connection. - * - * @throws IOException - * If any problem occurs, e.g., the server's host key is not - * accepted by the <code>verifier</code> or there is problem - * during the initial crypto setup (e.g., the signature sent by - * the server is wrong). - * <p> - * In case of a timeout (either connectTimeout or kexTimeout) a - * SocketTimeoutException is thrown. - * <p> - * An exception may also be thrown if the connection was already - * successfully connected (no matter if the connection broke in - * the mean time) and you invoke <code>connect()</code> again - * without having called {@link #close()} first. - * <p> - * If a HTTP proxy is being used and the proxy refuses the - * connection, then a {@link HTTPProxyException} may be thrown, - * which contains the details returned by the proxy. If the - * proxy is buggy and does not return a proper HTTP response, - * then a normal IOException is thrown instead. - */ - public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout) - throws IOException - { - final class TimeoutState - { - boolean isCancelled = false; - boolean timeoutSocketClosed = false; - } - - if (tm != null) - throw new IOException("Connection to " + hostname + " is already in connected state!"); - - if (connectTimeout < 0) - throw new IllegalArgumentException("connectTimeout must be non-negative!"); - - if (kexTimeout < 0) - throw new IllegalArgumentException("kexTimeout must be non-negative!"); - - final TimeoutState state = new TimeoutState(); - - tm = new TransportManager(hostname, port); - - tm.setConnectionMonitors(connectionMonitors); - - // Don't offer compression if not requested - if (!compression) { - cryptoWishList.c2s_comp_algos = new String[] { "none" }; - cryptoWishList.s2c_comp_algos = new String[] { "none" }; - } - - /* - * Make sure that the runnable below will observe the new value of "tm" - * and "state" (the runnable will be executed in a different thread, - * which may be already running, that is why we need a memory barrier - * here). See also the comment in Channel.java if you are interested in - * the details. - * - * OKOK, this is paranoid since adding the runnable to the todo list of - * the TimeoutService will ensure that all writes have been flushed - * before the Runnable reads anything (there is a synchronized block in - * TimeoutService.addTimeoutHandler). - */ - - synchronized (tm) - { - /* We could actually synchronize on anything. */ - } - - try - { - TimeoutToken token = null; - - if (kexTimeout > 0) - { - final Runnable timeoutHandler = new Runnable() - { - public void run() - { - synchronized (state) - { - if (state.isCancelled) - return; - state.timeoutSocketClosed = true; - tm.close(new SocketTimeoutException("The connect timeout expired"), false); - } - } - }; - - long timeoutHorizont = System.currentTimeMillis() + kexTimeout; - - token = TimeoutService.addTimeoutHandler(timeoutHorizont, timeoutHandler); - } - - try - { - tm.initialize(cryptoWishList, verifier, dhgexpara, connectTimeout, getOrCreateSecureRND(), proxyData); - } - catch (SocketTimeoutException se) - { - throw (SocketTimeoutException) new SocketTimeoutException( - "The connect() operation on the socket timed out.").initCause(se); - } - - tm.setTcpNoDelay(tcpNoDelay); - - /* Wait until first KEX has finished */ - - ConnectionInfo ci = tm.getConnectionInfo(1); - - /* Now try to cancel the timeout, if needed */ - - if (token != null) - { - TimeoutService.cancelTimeoutHandler(token); - - /* Were we too late? */ - - synchronized (state) - { - if (state.timeoutSocketClosed) - throw new IOException("This exception will be replaced by the one below =)"); - /* - * Just in case the "cancelTimeoutHandler" invocation came - * just a little bit too late but the handler did not enter - * the semaphore yet - we can still stop it. - */ - state.isCancelled = true; - } - } - - return ci; - } - catch (SocketTimeoutException ste) - { - throw ste; - } - catch (IOException e1) - { - /* This will also invoke any registered connection monitors */ - close(new Throwable("There was a problem during connect."), false); - - synchronized (state) - { - /* - * Show a clean exception, not something like "the socket is - * closed!?!" - */ - if (state.timeoutSocketClosed) - throw new SocketTimeoutException("The kexTimeout (" + kexTimeout + " ms) expired."); - } - - /* Do not wrap a HTTPProxyException */ - if (e1 instanceof HTTPProxyException) - throw e1; - - throw (IOException) new IOException("There was a problem while connecting to " + hostname + ":" + port) - .initCause(e1); - } - } - - /** - * Creates a new {@link LocalPortForwarder}. A - * <code>LocalPortForwarder</code> forwards TCP/IP connections that arrive - * at a local port via the secure tunnel to another host (which may or may - * not be identical to the remote SSH-2 server). - * <p> - * This method must only be called after one has passed successfully the - * authentication step. There is no limit on the number of concurrent - * forwardings. - * - * @param local_port - * the local port the LocalPortForwarder shall bind to. - * @param host_to_connect - * target address (IP or hostname) - * @param port_to_connect - * target port - * @return A {@link LocalPortForwarder} object. - * @throws IOException - */ - public synchronized LocalPortForwarder createLocalPortForwarder(int local_port, String host_to_connect, - int port_to_connect) throws IOException - { - if (tm == null) - throw new IllegalStateException("Cannot forward ports, you need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("Cannot forward ports, connection is not authenticated."); - - return new LocalPortForwarder(cm, local_port, host_to_connect, port_to_connect); - } - - /** - * Creates a new {@link LocalPortForwarder}. A - * <code>LocalPortForwarder</code> forwards TCP/IP connections that arrive - * at a local port via the secure tunnel to another host (which may or may - * not be identical to the remote SSH-2 server). - * <p> - * This method must only be called after one has passed successfully the - * authentication step. There is no limit on the number of concurrent - * forwardings. - * - * @param addr - * specifies the InetSocketAddress where the local socket shall - * be bound to. - * @param host_to_connect - * target address (IP or hostname) - * @param port_to_connect - * target port - * @return A {@link LocalPortForwarder} object. - * @throws IOException - */ - public synchronized LocalPortForwarder createLocalPortForwarder(InetSocketAddress addr, String host_to_connect, - int port_to_connect) throws IOException - { - if (tm == null) - throw new IllegalStateException("Cannot forward ports, you need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("Cannot forward ports, connection is not authenticated."); - - return new LocalPortForwarder(cm, addr, host_to_connect, port_to_connect); - } - - /** - * Creates a new {@link LocalStreamForwarder}. A - * <code>LocalStreamForwarder</code> manages an Input/Outputstream pair - * that is being forwarded via the secure tunnel into a TCP/IP connection to - * another host (which may or may not be identical to the remote SSH-2 - * server). - * - * @param host_to_connect - * @param port_to_connect - * @return A {@link LocalStreamForwarder} object. - * @throws IOException - */ - public synchronized LocalStreamForwarder createLocalStreamForwarder(String host_to_connect, int port_to_connect) - throws IOException - { - if (tm == null) - throw new IllegalStateException("Cannot forward, you need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("Cannot forward, connection is not authenticated."); - - return new LocalStreamForwarder(cm, host_to_connect, port_to_connect); - } - - /** - * Creates a new {@link DynamicPortForwarder}. A - * <code>DynamicPortForwarder</code> forwards TCP/IP connections that arrive - * at a local port via the secure tunnel to another host that is chosen via - * the SOCKS protocol. - * <p> - * This method must only be called after one has passed successfully the - * authentication step. There is no limit on the number of concurrent - * forwardings. - * - * @param local_port - * @return A {@link DynamicPortForwarder} object. - * @throws IOException - */ - public synchronized DynamicPortForwarder createDynamicPortForwarder(int local_port) throws IOException - { - if (tm == null) - throw new IllegalStateException("Cannot forward ports, you need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("Cannot forward ports, connection is not authenticated."); - - return new DynamicPortForwarder(cm, local_port); - } - - /** - * Creates a new {@link DynamicPortForwarder}. A - * <code>DynamicPortForwarder</code> forwards TCP/IP connections that arrive - * at a local port via the secure tunnel to another host that is chosen via - * the SOCKS protocol. - * <p> - * This method must only be called after one has passed successfully the - * authentication step. There is no limit on the number of concurrent - * forwardings. - * - * @param addr - * specifies the InetSocketAddress where the local socket shall - * be bound to. - * @return A {@link DynamicPortForwarder} object. - * @throws IOException - */ - public synchronized DynamicPortForwarder createDynamicPortForwarder(InetSocketAddress addr) throws IOException - { - if (tm == null) - throw new IllegalStateException("Cannot forward ports, you need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("Cannot forward ports, connection is not authenticated."); - - return new DynamicPortForwarder(cm, addr); - } - - /** - * Create a very basic {@link SCPClient} that can be used to copy files - * from/to the SSH-2 server. - * <p> - * Works only after one has passed successfully the authentication step. - * There is no limit on the number of concurrent SCP clients. - * <p> - * Note: This factory method will probably disappear in the future. - * - * @return A {@link SCPClient} object. - * @throws IOException - */ - public synchronized SCPClient createSCPClient() throws IOException - { - if (tm == null) - throw new IllegalStateException("Cannot create SCP client, you need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("Cannot create SCP client, connection is not authenticated."); - - return new SCPClient(this); - } - - /** - * Force an asynchronous key re-exchange (the call does not block). The - * latest values set for MAC, Cipher and DH group exchange parameters will - * be used. If a key exchange is currently in progress, then this method has - * the only effect that the so far specified parameters will be used for the - * next (server driven) key exchange. - * <p> - * Note: This implementation will never start a key exchange (other than the - * initial one) unless you or the SSH-2 server ask for it. - * - * @throws IOException - * In case of any failure behind the scenes. - */ - public synchronized void forceKeyExchange() throws IOException - { - if (tm == null) - throw new IllegalStateException("You need to establish a connection first."); - - tm.forceKeyExchange(cryptoWishList, dhgexpara); - } - - /** - * Returns the hostname that was passed to the constructor. - * - * @return the hostname - */ - public synchronized String getHostname() - { - return hostname; - } - - /** - * Returns the port that was passed to the constructor. - * - * @return the TCP port - */ - public synchronized int getPort() - { - return port; - } - - /** - * Returns a {@link ConnectionInfo} object containing the details of the - * connection. Can be called as soon as the connection has been established - * (successfully connected). - * - * @return A {@link ConnectionInfo} object. - * @throws IOException - * In case of any failure behind the scenes. - */ - public synchronized ConnectionInfo getConnectionInfo() throws IOException - { - if (tm == null) - throw new IllegalStateException( - "Cannot get details of connection, you need to establish a connection first."); - return tm.getConnectionInfo(1); - } - - /** - * After a successful connect, one has to authenticate oneself. This method - * can be used to tell which authentication methods are supported by the - * server at a certain stage of the authentication process (for the given - * username). - * <p> - * Note 1: the username will only be used if no authentication step was done - * so far (it will be used to ask the server for a list of possible - * authentication methods by sending the initial "none" request). Otherwise, - * this method ignores the user name and returns a cached method list (which - * is based on the information contained in the last negative server - * response). - * <p> - * Note 2: the server may return method names that are not supported by this - * implementation. - * <p> - * After a successful authentication, this method must not be called - * anymore. - * - * @param user - * A <code>String</code> holding the username. - * - * @return a (possibly emtpy) array holding authentication method names. - * @throws IOException - */ - public synchronized String[] getRemainingAuthMethods(String user) throws IOException - { - if (user == null) - throw new IllegalArgumentException("user argument may not be NULL!"); - - if (tm == null) - throw new IllegalStateException("Connection is not established!"); - - if (authenticated) - throw new IllegalStateException("Connection is already authenticated!"); - - if (am == null) - am = new AuthenticationManager(tm); - - if (cm == null) - cm = new ChannelManager(tm); - - return am.getRemainingMethods(user); - } - - /** - * Determines if the authentication phase is complete. Can be called at any - * time. - * - * @return <code>true</code> if no further authentication steps are - * needed. - */ - public synchronized boolean isAuthenticationComplete() - { - return authenticated; - } - - /** - * Returns true if there was at least one failed authentication request and - * the last failed authentication request was marked with "partial success" - * by the server. This is only needed in the rare case of SSH-2 server - * setups that cannot be satisfied with a single successful authentication - * request (i.e., multiple authentication steps are needed.) - * <p> - * If you are interested in the details, then have a look at RFC4252. - * - * @return if the there was a failed authentication step and the last one - * was marked as a "partial success". - */ - public synchronized boolean isAuthenticationPartialSuccess() - { - if (am == null) - return false; - - return am.getPartialSuccess(); - } - - /** - * Checks if a specified authentication method is available. This method is - * actually just a wrapper for {@link #getRemainingAuthMethods(String) - * getRemainingAuthMethods()}. - * - * @param user - * A <code>String</code> holding the username. - * @param method - * An authentication method name (e.g., "publickey", "password", - * "keyboard-interactive") as specified by the SSH-2 standard. - * @return if the specified authentication method is currently available. - * @throws IOException - */ - public synchronized boolean isAuthMethodAvailable(String user, String method) throws IOException - { - if (method == null) - throw new IllegalArgumentException("method argument may not be NULL!"); - - String methods[] = getRemainingAuthMethods(user); - - for (int i = 0; i < methods.length; i++) - { - if (methods[i].compareTo(method) == 0) - return true; - } - - return false; - } - - private final SecureRandom getOrCreateSecureRND() - { - if (generator == null) - generator = new SecureRandom(); - - return generator; - } - - /** - * Open a new {@link Session} on this connection. Works only after one has - * passed successfully the authentication step. There is no limit on the - * number of concurrent sessions. - * - * @return A {@link Session} object. - * @throws IOException - */ - public synchronized Session openSession() throws IOException - { - if (tm == null) - throw new IllegalStateException("Cannot open session, you need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("Cannot open session, connection is not authenticated."); - - return new Session(cm, getOrCreateSecureRND()); - } - - /** - * Send an SSH_MSG_IGNORE packet. This method will generate a random data - * attribute (length between 0 (invlusive) and 16 (exclusive) bytes, - * contents are random bytes). - * <p> - * This method must only be called once the connection is established. - * - * @throws IOException - */ - public synchronized void sendIgnorePacket() throws IOException - { - SecureRandom rnd = getOrCreateSecureRND(); - - byte[] data = new byte[rnd.nextInt(16)]; - rnd.nextBytes(data); - - sendIgnorePacket(data); - } - - /** - * Send an SSH_MSG_IGNORE packet with the given data attribute. - * <p> - * This method must only be called once the connection is established. - * - * @throws IOException - */ - public synchronized void sendIgnorePacket(byte[] data) throws IOException - { - if (data == null) - throw new IllegalArgumentException("data argument must not be null."); - - if (tm == null) - throw new IllegalStateException( - "Cannot send SSH_MSG_IGNORE packet, you need to establish a connection first."); - - PacketIgnore pi = new PacketIgnore(); - pi.setData(data); - - tm.sendMessage(pi.getPayload()); - } - - /** - * Removes duplicates from a String array, keeps only first occurence of - * each element. Does not destroy order of elements; can handle nulls. Uses - * a very efficient O(N^2) algorithm =) - * - * @param list - * a String array. - * @return a cleaned String array. - */ - private String[] removeDuplicates(String[] list) - { - if ((list == null) || (list.length < 2)) - return list; - - String[] list2 = new String[list.length]; - - int count = 0; - - for (int i = 0; i < list.length; i++) - { - boolean duplicate = false; - - String element = list[i]; - - for (int j = 0; j < count; j++) - { - if (((element == null) && (list2[j] == null)) || ((element != null) && (element.equals(list2[j])))) - { - duplicate = true; - break; - } - } - - if (duplicate) - continue; - - list2[count++] = list[i]; - } - - if (count == list2.length) - return list2; - - String[] tmp = new String[count]; - System.arraycopy(list2, 0, tmp, 0, count); - - return tmp; - } - - /** - * Unless you know what you are doing, you will never need this. - * - * @param ciphers - */ - public synchronized void setClient2ServerCiphers(String[] ciphers) - { - if ((ciphers == null) || (ciphers.length == 0)) - throw new IllegalArgumentException(); - ciphers = removeDuplicates(ciphers); - BlockCipherFactory.checkCipherList(ciphers); - cryptoWishList.c2s_enc_algos = ciphers; - } - - /** - * Unless you know what you are doing, you will never need this. - * - * @param macs - */ - public synchronized void setClient2ServerMACs(String[] macs) - { - if ((macs == null) || (macs.length == 0)) - throw new IllegalArgumentException(); - macs = removeDuplicates(macs); - MAC.checkMacList(macs); - cryptoWishList.c2s_mac_algos = macs; - } - - /** - * Sets the parameters for the diffie-hellman group exchange. Unless you - * know what you are doing, you will never need this. Default values are - * defined in the {@link DHGexParameters} class. - * - * @param dgp - * {@link DHGexParameters}, non null. - * - */ - public synchronized void setDHGexParameters(DHGexParameters dgp) - { - if (dgp == null) - throw new IllegalArgumentException(); - - dhgexpara = dgp; - } - - /** - * Unless you know what you are doing, you will never need this. - * - * @param ciphers - */ - public synchronized void setServer2ClientCiphers(String[] ciphers) - { - if ((ciphers == null) || (ciphers.length == 0)) - throw new IllegalArgumentException(); - ciphers = removeDuplicates(ciphers); - BlockCipherFactory.checkCipherList(ciphers); - cryptoWishList.s2c_enc_algos = ciphers; - } - - /** - * Unless you know what you are doing, you will never need this. - * - * @param macs - */ - public synchronized void setServer2ClientMACs(String[] macs) - { - if ((macs == null) || (macs.length == 0)) - throw new IllegalArgumentException(); - - macs = removeDuplicates(macs); - MAC.checkMacList(macs); - cryptoWishList.s2c_mac_algos = macs; - } - - /** - * Define the set of allowed server host key algorithms to be used for the - * following key exchange operations. - * <p> - * Unless you know what you are doing, you will never need this. - * - * @param algos - * An array of allowed server host key algorithms. SSH-2 defines - * <code>ssh-dss</code> and <code>ssh-rsa</code>. The - * entries of the array must be ordered after preference, i.e., - * the entry at index 0 is the most preferred one. You must - * specify at least one entry. - */ - public synchronized void setServerHostKeyAlgorithms(String[] algos) - { - if ((algos == null) || (algos.length == 0)) - throw new IllegalArgumentException(); - - algos = removeDuplicates(algos); - KexManager.checkServerHostkeyAlgorithmsList(algos); - cryptoWishList.serverHostKeyAlgorithms = algos; - } - - /** - * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the - * underlying socket. - * <p> - * Can be called at any time. If the connection has not yet been established - * then the passed value will be stored and set after the socket has been - * set up. The default value that will be used is <code>false</code>. - * - * @param enable - * the argument passed to the <code>Socket.setTCPNoDelay()</code> - * method. - * @throws IOException - */ - public synchronized void setTCPNoDelay(boolean enable) throws IOException - { - tcpNoDelay = enable; - - if (tm != null) - tm.setTcpNoDelay(enable); - } - - /** - * Used to tell the library that the connection shall be established through - * a proxy server. It only makes sense to call this method before calling - * the {@link #connect() connect()} method. - * <p> - * At the moment, only HTTP proxies are supported. - * <p> - * Note: This method can be called any number of times. The - * {@link #connect() connect()} method will use the value set in the last - * preceding invocation of this method. - * - * @see HTTPProxyData - * - * @param proxyData - * Connection information about the proxy. If <code>null</code>, - * then no proxy will be used (non surprisingly, this is also the - * default). - */ - public synchronized void setProxyData(ProxyData proxyData) - { - this.proxyData = proxyData; - } - - /** - * Request a remote port forwarding. If successful, then forwarded - * connections will be redirected to the given target address. You can - * cancle a requested remote port forwarding by calling - * {@link #cancelRemotePortForwarding(int) cancelRemotePortForwarding()}. - * <p> - * A call of this method will block until the peer either agreed or - * disagreed to your request- - * <p> - * Note 1: this method typically fails if you - * <ul> - * <li>pass a port number for which the used remote user has not enough - * permissions (i.e., port < 1024)</li> - * <li>or pass a port number that is already in use on the remote server</li> - * <li>or if remote port forwarding is disabled on the server.</li> - * </ul> - * <p> - * Note 2: (from the openssh man page): By default, the listening socket on - * the server will be bound to the loopback interface only. This may be - * overriden by specifying a bind address. Specifying a remote bind address - * will only succeed if the server's <b>GatewayPorts</b> option is enabled - * (see sshd_config(5)). - * - * @param bindAddress - * address to bind to on the server: - * <ul> - * <li>"" means that connections are to be accepted on all - * protocol families supported by the SSH implementation</li> - * <li>"0.0.0.0" means to listen on all IPv4 addresses</li> - * <li>"::" means to listen on all IPv6 addresses</li> - * <li>"localhost" means to listen on all protocol families - * supported by the SSH implementation on loopback addresses - * only, [RFC3330] and RFC3513]</li> - * <li>"127.0.0.1" and "::1" indicate listening on the loopback - * interfaces for IPv4 and IPv6 respectively</li> - * </ul> - * @param bindPort - * port number to bind on the server (must be > 0) - * @param targetAddress - * the target address (IP or hostname) - * @param targetPort - * the target port - * @throws IOException - */ - public synchronized void requestRemotePortForwarding(String bindAddress, int bindPort, String targetAddress, - int targetPort) throws IOException - { - if (tm == null) - throw new IllegalStateException("You need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("The connection is not authenticated."); - - if ((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0)) - throw new IllegalArgumentException(); - - cm.requestGlobalForward(bindAddress, bindPort, targetAddress, targetPort); - } - - /** - * Cancel an earlier requested remote port forwarding. Currently active - * forwardings will not be affected (e.g., disrupted). Note that further - * connection forwarding requests may be received until this method has - * returned. - * - * @param bindPort - * the allocated port number on the server - * @throws IOException - * if the remote side refuses the cancel request or another low - * level error occurs (e.g., the underlying connection is - * closed) - */ - public synchronized void cancelRemotePortForwarding(int bindPort) throws IOException - { - if (tm == null) - throw new IllegalStateException("You need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("The connection is not authenticated."); - - cm.requestCancelGlobalForward(bindPort); - } - - /** - * Provide your own instance of SecureRandom. Can be used, e.g., if you want - * to seed the used SecureRandom generator manually. - * <p> - * The SecureRandom instance is used during key exchanges, public key - * authentication, x11 cookie generation and the like. - * - * @param rnd - * a SecureRandom instance - */ - public synchronized void setSecureRandom(SecureRandom rnd) - { - if (rnd == null) - throw new IllegalArgumentException(); - - this.generator = rnd; - } - - /** - * Enable/disable debug logging. <b>Only do this when requested by Trilead - * support.</b> - * <p> - * For speed reasons, some static variables used to check whether debugging - * is enabled are not protected with locks. In other words, if you - * dynamicaly enable/disable debug logging, then some threads may still use - * the old setting. To be on the safe side, enable debugging before doing - * the <code>connect()</code> call. - * - * @param enable - * on/off - * @param logger - * a {@link DebugLogger DebugLogger} instance, <code>null</code> - * means logging using the simple logger which logs all messages - * to to stderr. Ignored if enabled is <code>false</code> - */ - public synchronized void enableDebugging(boolean enable, DebugLogger logger) - { - Logger.enabled = enable; - - if (enable == false) - { - Logger.logger = null; - } - else - { - if (logger == null) - { - logger = new DebugLogger() - { - - public void log(int level, String className, String message) - { - long now = System.currentTimeMillis(); - System.err.println(now + " : " + className + ": " + message); - } - }; - } - - Logger.logger = logger; - } - } - - /** - * This method can be used to perform end-to-end connection testing. It - * sends a 'ping' message to the server and waits for the 'pong' from the - * server. - * <p> - * When this method throws an exception, then you can assume that the - * connection should be abandoned. - * <p> - * Note: Works only after one has passed successfully the authentication - * step. - * <p> - * Implementation details: this method sends a SSH_MSG_GLOBAL_REQUEST - * request ('trilead-ping') to the server and waits for the - * SSH_MSG_REQUEST_FAILURE reply packet from the server. - * - * @throws IOException - * in case of any problem - */ - public synchronized void ping() throws IOException - { - if (tm == null) - throw new IllegalStateException("You need to establish a connection first."); - - if (!authenticated) - throw new IllegalStateException("The connection is not authenticated."); - - cm.requestGlobalTrileadPing(); - } -} diff --git a/src/com/trilead/ssh2/ConnectionInfo.java b/src/com/trilead/ssh2/ConnectionInfo.java deleted file mode 100644 index b0ddbcf..0000000 --- a/src/com/trilead/ssh2/ConnectionInfo.java +++ /dev/null @@ -1,53 +0,0 @@ - -package com.trilead.ssh2; - -/** - * In most cases you probably do not need the information contained in here. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ConnectionInfo.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class ConnectionInfo -{ - /** - * The used key exchange (KEX) algorithm in the latest key exchange. - */ - public String keyExchangeAlgorithm; - - /** - * The currently used crypto algorithm for packets from to the client to the - * server. - */ - public String clientToServerCryptoAlgorithm; - /** - * The currently used crypto algorithm for packets from to the server to the - * client. - */ - public String serverToClientCryptoAlgorithm; - - /** - * The currently used MAC algorithm for packets from to the client to the - * server. - */ - public String clientToServerMACAlgorithm; - /** - * The currently used MAC algorithm for packets from to the server to the - * client. - */ - public String serverToClientMACAlgorithm; - - /** - * The type of the server host key (currently either "ssh-dss" or - * "ssh-rsa"). - */ - public String serverHostKeyAlgorithm; - /** - * The server host key that was sent during the latest key exchange. - */ - public byte[] serverHostKey; - - /** - * Number of kex exchanges performed on this connection so far. - */ - public int keyExchangeCounter = 0; -} diff --git a/src/com/trilead/ssh2/ConnectionMonitor.java b/src/com/trilead/ssh2/ConnectionMonitor.java deleted file mode 100644 index 2f96d25..0000000 --- a/src/com/trilead/ssh2/ConnectionMonitor.java +++ /dev/null @@ -1,34 +0,0 @@ - -package com.trilead.ssh2; - -/** - * A <code>ConnectionMonitor</code> is used to get notified when the - * underlying socket of a connection is closed. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ConnectionMonitor.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public interface ConnectionMonitor -{ - /** - * This method is called after the connection's underlying - * socket has been closed. E.g., due to the {@link Connection#close()} request of the - * user, if the peer closed the connection, due to a fatal error during connect() - * (also if the socket cannot be established) or if a fatal error occured on - * an established connection. - * <p> - * This is an experimental feature. - * <p> - * You MUST NOT make any assumption about the thread that invokes this method. - * <p> - * <b>Please note: if the connection is not connected (e.g., there was no successful - * connect() call), then the invocation of {@link Connection#close()} will NOT trigger - * this method.</b> - * - * @see Connection#addConnectionMonitor(ConnectionMonitor) - * - * @param reason Includes an indication why the socket was closed. - */ - public void connectionLost(Throwable reason); -}
\ No newline at end of file diff --git a/src/com/trilead/ssh2/DHGexParameters.java b/src/com/trilead/ssh2/DHGexParameters.java deleted file mode 100644 index a2945ee..0000000 --- a/src/com/trilead/ssh2/DHGexParameters.java +++ /dev/null @@ -1,121 +0,0 @@ - -package com.trilead.ssh2; - -/** - * A <code>DHGexParameters</code> object can be used to specify parameters for - * the diffie-hellman group exchange. - * <p> - * Depending on which constructor is used, either the use of a - * <code>SSH_MSG_KEX_DH_GEX_REQUEST</code> or <code>SSH_MSG_KEX_DH_GEX_REQUEST_OLD</code> - * can be forced. - * - * @see Connection#setDHGexParameters(DHGexParameters) - * @author Christian Plattner, plattner@trilead.com - * @version $Id: DHGexParameters.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public class DHGexParameters -{ - private final int min_group_len; - private final int pref_group_len; - private final int max_group_len; - - private static final int MIN_ALLOWED = 1024; - private static final int MAX_ALLOWED = 8192; - - /** - * Same as calling {@link #DHGexParameters(int, int, int) DHGexParameters(1024, 1024, 4096)}. - * This is also the default used by the Connection class. - * - */ - public DHGexParameters() - { - this(1024, 1024, 4096); - } - - /** - * This constructor can be used to force the sending of a - * <code>SSH_MSG_KEX_DH_GEX_REQUEST_OLD</code> request. - * Internally, the minimum and maximum group lengths will - * be set to zero. - * - * @param pref_group_len has to be >= 1024 and <= 8192 - */ - public DHGexParameters(int pref_group_len) - { - if ((pref_group_len < MIN_ALLOWED) || (pref_group_len > MAX_ALLOWED)) - throw new IllegalArgumentException("pref_group_len out of range!"); - - this.pref_group_len = pref_group_len; - this.min_group_len = 0; - this.max_group_len = 0; - } - - /** - * This constructor can be used to force the sending of a - * <code>SSH_MSG_KEX_DH_GEX_REQUEST</code> request. - * <p> - * Note: older OpenSSH servers don't understand this request, in which - * case you should use the {@link #DHGexParameters(int)} constructor. - * <p> - * All values have to be >= 1024 and <= 8192. Furthermore, - * min_group_len <= pref_group_len <= max_group_len. - * - * @param min_group_len - * @param pref_group_len - * @param max_group_len - */ - public DHGexParameters(int min_group_len, int pref_group_len, int max_group_len) - { - if ((min_group_len < MIN_ALLOWED) || (min_group_len > MAX_ALLOWED)) - throw new IllegalArgumentException("min_group_len out of range!"); - - if ((pref_group_len < MIN_ALLOWED) || (pref_group_len > MAX_ALLOWED)) - throw new IllegalArgumentException("pref_group_len out of range!"); - - if ((max_group_len < MIN_ALLOWED) || (max_group_len > MAX_ALLOWED)) - throw new IllegalArgumentException("max_group_len out of range!"); - - if ((pref_group_len < min_group_len) || (pref_group_len > max_group_len)) - throw new IllegalArgumentException("pref_group_len is incompatible with min and max!"); - - if (max_group_len < min_group_len) - throw new IllegalArgumentException("max_group_len must not be smaller than min_group_len!"); - - this.min_group_len = min_group_len; - this.pref_group_len = pref_group_len; - this.max_group_len = max_group_len; - } - - /** - * Get the maximum group length. - * - * @return the maximum group length, may be <code>zero</code> if - * SSH_MSG_KEX_DH_GEX_REQUEST_OLD should be requested - */ - public int getMax_group_len() - { - return max_group_len; - } - - /** - * Get the minimum group length. - * - * @return minimum group length, may be <code>zero</code> if - * SSH_MSG_KEX_DH_GEX_REQUEST_OLD should be requested - */ - public int getMin_group_len() - { - return min_group_len; - } - - /** - * Get the preferred group length. - * - * @return the preferred group length - */ - public int getPref_group_len() - { - return pref_group_len; - } -} diff --git a/src/com/trilead/ssh2/DebugLogger.java b/src/com/trilead/ssh2/DebugLogger.java deleted file mode 100644 index adf2c8e..0000000 --- a/src/com/trilead/ssh2/DebugLogger.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.trilead.ssh2; - -/** - * An interface which needs to be implemented if you - * want to capture debugging messages. - * - * @see Connection#enableDebugging(boolean, DebugLogger) - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: DebugLogger.java,v 1.1 2008/03/03 07:01:36 cplattne Exp $ - */ -public interface DebugLogger -{ - -/** - * Log a debug message. - * - * @param level 0-99, 99 is a the most verbose level - * @param className the class that generated the message - * @param message the debug message - */ - public void log(int level, String className, String message); -} diff --git a/src/com/trilead/ssh2/DynamicPortForwarder.java b/src/com/trilead/ssh2/DynamicPortForwarder.java deleted file mode 100644 index a15efe7..0000000 --- a/src/com/trilead/ssh2/DynamicPortForwarder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2; - -import java.io.IOException; -import java.net.InetSocketAddress; - -import com.trilead.ssh2.channel.ChannelManager; -import com.trilead.ssh2.channel.DynamicAcceptThread; - -/** - * A <code>DynamicPortForwarder</code> forwards TCP/IP connections to a local - * port via the secure tunnel to another host which is selected via the - * SOCKS protocol. Checkout {@link Connection#createDynamicPortForwarder(int)} - * on how to create one. - * - * @author Kenny Root - * @version $Id: $ - */ -public class DynamicPortForwarder { - ChannelManager cm; - - DynamicAcceptThread dat; - - DynamicPortForwarder(ChannelManager cm, int local_port) - throws IOException - { - this.cm = cm; - - dat = new DynamicAcceptThread(cm, local_port); - dat.setDaemon(true); - dat.start(); - } - - DynamicPortForwarder(ChannelManager cm, InetSocketAddress addr) throws IOException { - this.cm = cm; - - dat = new DynamicAcceptThread(cm, addr); - dat.setDaemon(true); - dat.start(); - } - - /** - * Stop TCP/IP forwarding of newly arriving connections. - * - * @throws IOException - */ - public void close() throws IOException - { - dat.stopWorking(); - } -} diff --git a/src/com/trilead/ssh2/HTTPProxyData.java b/src/com/trilead/ssh2/HTTPProxyData.java deleted file mode 100644 index 2edffe6..0000000 --- a/src/com/trilead/ssh2/HTTPProxyData.java +++ /dev/null @@ -1,83 +0,0 @@ - -package com.trilead.ssh2; - -/** - * A <code>HTTPProxyData</code> object is used to specify the needed connection data - * to connect through a HTTP proxy. - * - * @see Connection#setProxyData(ProxyData) - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: HTTPProxyData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public class HTTPProxyData implements ProxyData -{ - public final String proxyHost; - public final int proxyPort; - public final String proxyUser; - public final String proxyPass; - public final String[] requestHeaderLines; - - /** - * Same as calling {@link #HTTPProxyData(String, int, String, String) HTTPProxyData(proxyHost, proxyPort, <code>null</code>, <code>null</code>)} - * - * @param proxyHost Proxy hostname. - * @param proxyPort Proxy port. - */ - public HTTPProxyData(String proxyHost, int proxyPort) - { - this(proxyHost, proxyPort, null, null); - } - - /** - * Same as calling {@link #HTTPProxyData(String, int, String, String, String[]) HTTPProxyData(proxyHost, proxyPort, <code>null</code>, <code>null</code>, <code>null</code>)} - * - * @param proxyHost Proxy hostname. - * @param proxyPort Proxy port. - * @param proxyUser Username for basic authentication (<code>null</code> if no authentication is needed). - * @param proxyPass Password for basic authentication (<code>null</code> if no authentication is needed). - */ - public HTTPProxyData(String proxyHost, int proxyPort, String proxyUser, String proxyPass) - { - this(proxyHost, proxyPort, proxyUser, proxyPass, null); - } - - /** - * Connection data for a HTTP proxy. It is possible to specify a username and password - * if the proxy requires basic authentication. Also, additional request header lines can - * be specified (e.g., "User-Agent: CERN-LineMode/2.15 libwww/2.17b3"). - * <p> - * Please note: if you want to use basic authentication, then both <code>proxyUser</code> - * and <code>proxyPass</code> must be non-null. - * <p> - * Here is an example: - * <p> - * <code> - * new HTTPProxyData("192.168.1.1", "3128", "proxyuser", "secret", new String[] {"User-Agent: TrileadBasedClient/1.0", "X-My-Proxy-Option: something"}); - * </code> - * - * @param proxyHost Proxy hostname. - * @param proxyPort Proxy port. - * @param proxyUser Username for basic authentication (<code>null</code> if no authentication is needed). - * @param proxyPass Password for basic authentication (<code>null</code> if no authentication is needed). - * @param requestHeaderLines An array with additional request header lines (without end-of-line markers) - * that have to be sent to the server. May be <code>null</code>. - */ - - public HTTPProxyData(String proxyHost, int proxyPort, String proxyUser, String proxyPass, - String[] requestHeaderLines) - { - if (proxyHost == null) - throw new IllegalArgumentException("proxyHost must be non-null"); - - if (proxyPort < 0) - throw new IllegalArgumentException("proxyPort must be non-negative"); - - this.proxyHost = proxyHost; - this.proxyPort = proxyPort; - this.proxyUser = proxyUser; - this.proxyPass = proxyPass; - this.requestHeaderLines = requestHeaderLines; - } -} diff --git a/src/com/trilead/ssh2/HTTPProxyException.java b/src/com/trilead/ssh2/HTTPProxyException.java deleted file mode 100644 index 4687dd1..0000000 --- a/src/com/trilead/ssh2/HTTPProxyException.java +++ /dev/null @@ -1,29 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.IOException; - -/** - * May be thrown upon connect() if a HTTP proxy is being used. - * - * @see Connection#connect() - * @see Connection#setProxyData(ProxyData) - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: HTTPProxyException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public class HTTPProxyException extends IOException -{ - private static final long serialVersionUID = 2241537397104426186L; - - public final String httpResponse; - public final int httpErrorCode; - - public HTTPProxyException(String httpResponse, int httpErrorCode) - { - super("HTTP Proxy Error (" + httpErrorCode + " " + httpResponse + ")"); - this.httpResponse = httpResponse; - this.httpErrorCode = httpErrorCode; - } -} diff --git a/src/com/trilead/ssh2/InteractiveCallback.java b/src/com/trilead/ssh2/InteractiveCallback.java deleted file mode 100644 index 3b83417..0000000 --- a/src/com/trilead/ssh2/InteractiveCallback.java +++ /dev/null @@ -1,55 +0,0 @@ - -package com.trilead.ssh2; - -/** - * An <code>InteractiveCallback</code> is used to respond to challenges sent - * by the server if authentication mode "keyboard-interactive" is selected. - * - * @see Connection#authenticateWithKeyboardInteractive(String, - * String[], InteractiveCallback) - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: InteractiveCallback.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public interface InteractiveCallback -{ - /** - * This callback interface is used during a "keyboard-interactive" - * authentication. Every time the server sends a set of challenges (however, - * most often just one challenge at a time), this callback function will be - * called to give your application a chance to talk to the user and to - * determine the response(s). - * <p> - * Some copy-paste information from the standard: a command line interface - * (CLI) client SHOULD print the name and instruction (if non-empty), adding - * newlines. Then for each prompt in turn, the client SHOULD display the - * prompt and read the user input. The name and instruction fields MAY be - * empty strings, the client MUST be prepared to handle this correctly. The - * prompt field(s) MUST NOT be empty strings. - * <p> - * Please refer to draft-ietf-secsh-auth-kbdinteract-XX.txt for the details. - * <p> - * Note: clients SHOULD use control character filtering as discussed in - * RFC4251 to avoid attacks by including - * terminal control characters in the fields to be displayed. - * - * @param name - * the name String sent by the server. - * @param instruction - * the instruction String sent by the server. - * @param numPrompts - * number of prompts - may be zero (in this case, you should just - * return a String array of length zero). - * @param prompt - * an array (length <code>numPrompts</code>) of Strings - * @param echo - * an array (length <code>numPrompts</code>) of booleans. For - * each prompt, the corresponding echo field indicates whether or - * not the user input should be echoed as characters are typed. - * @return an array of reponses - the array size must match the parameter - * <code>numPrompts</code>. - */ - public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) - throws Exception; -} diff --git a/src/com/trilead/ssh2/KnownHosts.java b/src/com/trilead/ssh2/KnownHosts.java deleted file mode 100644 index ec022ff..0000000 --- a/src/com/trilead/ssh2/KnownHosts.java +++ /dev/null @@ -1,844 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.BufferedReader; -import java.io.CharArrayReader; -import java.io.CharArrayWriter; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Vector; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import com.trilead.ssh2.crypto.Base64; -import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.ECDSASHA2Verify; -import com.trilead.ssh2.signature.RSASHA1Verify; - - -/** - * The <code>KnownHosts</code> class is a handy tool to verify received server hostkeys - * based on the information in <code>known_hosts</code> files (the ones used by OpenSSH). - * <p> - * It offers basically an in-memory database for known_hosts entries, as well as some - * helper functions. Entries from a <code>known_hosts</code> file can be loaded at construction time. - * It is also possible to add more keys later (e.g., one can parse different - * <code>known_hosts<code> files). - * <p> - * It is a thread safe implementation, therefore, you need only to instantiate one - * <code>KnownHosts</code> for your whole application. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: KnownHosts.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ - -public class KnownHosts -{ - public static final int HOSTKEY_IS_OK = 0; - public static final int HOSTKEY_IS_NEW = 1; - public static final int HOSTKEY_HAS_CHANGED = 2; - - private class KnownHostsEntry - { - String[] patterns; - PublicKey key; - - KnownHostsEntry(String[] patterns, PublicKey key) - { - this.patterns = patterns; - this.key = key; - } - } - - private LinkedList<KnownHostsEntry> publicKeys = new LinkedList<KnownHostsEntry>(); - - public KnownHosts() - { - } - - public KnownHosts(char[] knownHostsData) throws IOException - { - initialize(knownHostsData); - } - - public KnownHosts(File knownHosts) throws IOException - { - initialize(knownHosts); - } - - /** - * Adds a single public key entry to the database. Note: this will NOT add the public key - * to any physical file (e.g., "~/.ssh/known_hosts") - use <code>addHostkeyToFile()</code> for that purpose. - * This method is designed to be used in a {@link ServerHostKeyVerifier}. - * - * @param hostnames a list of hostname patterns - at least one most be specified. Check out the - * OpenSSH sshd man page for a description of the pattern matching algorithm. - * @param serverHostKeyAlgorithm as passed to the {@link ServerHostKeyVerifier}. - * @param serverHostKey as passed to the {@link ServerHostKeyVerifier}. - * @throws IOException - */ - public void addHostkey(String hostnames[], String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException - { - if (hostnames == null) - throw new IllegalArgumentException("hostnames may not be null"); - - if ("ssh-rsa".equals(serverHostKeyAlgorithm)) - { - RSAPublicKey rpk = RSASHA1Verify.decodeSSHRSAPublicKey(serverHostKey); - - synchronized (publicKeys) - { - publicKeys.add(new KnownHostsEntry(hostnames, rpk)); - } - } - else if ("ssh-dss".equals(serverHostKeyAlgorithm)) - { - DSAPublicKey dpk = DSASHA1Verify.decodeSSHDSAPublicKey(serverHostKey); - - synchronized (publicKeys) - { - publicKeys.add(new KnownHostsEntry(hostnames, dpk)); - } - } - else if (serverHostKeyAlgorithm.startsWith(ECDSASHA2Verify.ECDSA_SHA2_PREFIX)) - { - ECPublicKey epk = ECDSASHA2Verify.decodeSSHECDSAPublicKey(serverHostKey); - - synchronized (publicKeys) { - publicKeys.add(new KnownHostsEntry(hostnames, epk)); - } - } - else - throw new IOException("Unknwon host key type (" + serverHostKeyAlgorithm + ")"); - } - - /** - * Parses the given known_hosts data and adds entries to the database. - * - * @param knownHostsData - * @throws IOException - */ - public void addHostkeys(char[] knownHostsData) throws IOException - { - initialize(knownHostsData); - } - - /** - * Parses the given known_hosts file and adds entries to the database. - * - * @param knownHosts - * @throws IOException - */ - public void addHostkeys(File knownHosts) throws IOException - { - initialize(knownHosts); - } - - /** - * Generate the hashed representation of the given hostname. Useful for adding entries - * with hashed hostnames to a known_hosts file. (see -H option of OpenSSH key-gen). - * - * @param hostname - * @return the hashed representation, e.g., "|1|cDhrv7zwEUV3k71CEPHnhHZezhA=|Xo+2y6rUXo2OIWRAYhBOIijbJMA=" - */ - public static final String createHashedHostname(String hostname) - { - MessageDigest sha1; - try { - sha1 = MessageDigest.getInstance("SHA1"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("VM doesn't support SHA1", e); - } - - byte[] salt = new byte[sha1.getDigestLength()]; - - new SecureRandom().nextBytes(salt); - - byte[] hash = hmacSha1Hash(salt, hostname); - - String base64_salt = new String(Base64.encode(salt)); - String base64_hash = new String(Base64.encode(hash)); - - return new String("|1|" + base64_salt + "|" + base64_hash); - } - - private static final byte[] hmacSha1Hash(byte[] salt, String hostname) - { - Mac hmac; - try { - hmac = Mac.getInstance("HmacSHA1"); - if (salt.length != hmac.getMacLength()) - throw new IllegalArgumentException("Salt has wrong length (" + salt.length + ")"); - hmac.init(new SecretKeySpec(salt, "HmacSHA1")); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Unable to HMAC-SHA1", e); - } catch (InvalidKeyException e) { - throw new RuntimeException("Unable to create SecretKey", e); - } - - try - { - hmac.update(hostname.getBytes("ISO-8859-1")); - }catch(UnsupportedEncodingException ignore) - { - /* Actually, ISO-8859-1 is supported by all correct - * Java implementations. But... you never know. */ - hmac.update(hostname.getBytes()); - } - - return hmac.doFinal(); - } - - private final boolean checkHashed(String entry, String hostname) - { - if (entry.startsWith("|1|") == false) - return false; - - int delim_idx = entry.indexOf('|', 3); - - if (delim_idx == -1) - return false; - - String salt_base64 = entry.substring(3, delim_idx); - String hash_base64 = entry.substring(delim_idx + 1); - - byte[] salt = null; - byte[] hash = null; - - try - { - salt = Base64.decode(salt_base64.toCharArray()); - hash = Base64.decode(hash_base64.toCharArray()); - } - catch (IOException e) - { - return false; - } - - try { - MessageDigest sha1 = MessageDigest.getInstance("SHA1"); - if (salt.length != sha1.getDigestLength()) - return false; - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("VM does not support SHA1", e); - } - - byte[] dig = hmacSha1Hash(salt, hostname); - - for (int i = 0; i < dig.length; i++) - if (dig[i] != hash[i]) - return false; - - return true; - } - - private int checkKey(String remoteHostname, PublicKey remoteKey) - { - int result = HOSTKEY_IS_NEW; - - synchronized (publicKeys) - { - Iterator<KnownHostsEntry> i = publicKeys.iterator(); - - while (i.hasNext()) - { - KnownHostsEntry ke = i.next(); - - if (hostnameMatches(ke.patterns, remoteHostname) == false) - continue; - - boolean res = matchKeys(ke.key, remoteKey); - - if (res == true) - return HOSTKEY_IS_OK; - - result = HOSTKEY_HAS_CHANGED; - } - } - return result; - } - - private Vector<PublicKey> getAllKeys(String hostname) - { - Vector<PublicKey> keys = new Vector<PublicKey>(); - - synchronized (publicKeys) - { - Iterator<KnownHostsEntry> i = publicKeys.iterator(); - - while (i.hasNext()) - { - KnownHostsEntry ke = i.next(); - - if (hostnameMatches(ke.patterns, hostname) == false) - continue; - - keys.addElement(ke.key); - } - } - - return keys; - } - - /** - * Try to find the preferred order of hostkey algorithms for the given hostname. - * Based on the type of hostkey that is present in the internal database - * (i.e., either <code>ssh-rsa</code> or <code>ssh-dss</code>) - * an ordered list of hostkey algorithms is returned which can be passed - * to <code>Connection.setServerHostKeyAlgorithms</code>. - * - * @param hostname - * @return <code>null</code> if no key for the given hostname is present or - * there are keys of multiple types present for the given hostname. Otherwise, - * an array with hostkey algorithms is returned (i.e., an array of length 2). - */ - public String[] getPreferredServerHostkeyAlgorithmOrder(String hostname) - { - String[] algos = recommendHostkeyAlgorithms(hostname); - - if (algos != null) - return algos; - - InetAddress[] ipAdresses = null; - - try - { - ipAdresses = InetAddress.getAllByName(hostname); - } - catch (UnknownHostException e) - { - return null; - } - - for (int i = 0; i < ipAdresses.length; i++) - { - algos = recommendHostkeyAlgorithms(ipAdresses[i].getHostAddress()); - - if (algos != null) - return algos; - } - - return null; - } - - private final boolean hostnameMatches(String[] hostpatterns, String hostname) - { - boolean isMatch = false; - boolean negate = false; - - hostname = hostname.toLowerCase(Locale.US); - - for (int k = 0; k < hostpatterns.length; k++) - { - if (hostpatterns[k] == null) - continue; - - String pattern = null; - - /* In contrast to OpenSSH we also allow negated hash entries (as well as hashed - * entries in lines with multiple entries). - */ - - if ((hostpatterns[k].length() > 0) && (hostpatterns[k].charAt(0) == '!')) - { - pattern = hostpatterns[k].substring(1); - negate = true; - } - else - { - pattern = hostpatterns[k]; - negate = false; - } - - /* Optimize, no need to check this entry */ - - if ((isMatch) && (negate == false)) - continue; - - /* Now compare */ - - if (pattern.charAt(0) == '|') - { - if (checkHashed(pattern, hostname)) - { - if (negate) - return false; - isMatch = true; - } - } - else - { - pattern = pattern.toLowerCase(Locale.US); - - if ((pattern.indexOf('?') != -1) || (pattern.indexOf('*') != -1)) - { - if (pseudoRegex(pattern.toCharArray(), 0, hostname.toCharArray(), 0)) - { - if (negate) - return false; - isMatch = true; - } - } - else if (pattern.compareTo(hostname) == 0) - { - if (negate) - return false; - isMatch = true; - } - } - } - - return isMatch; - } - - private void initialize(char[] knownHostsData) throws IOException - { - BufferedReader br = new BufferedReader(new CharArrayReader(knownHostsData)); - - while (true) - { - String line = br.readLine(); - - if (line == null) - break; - - line = line.trim(); - - if (line.startsWith("#")) - continue; - - String[] arr = line.split(" "); - - if (arr.length >= 3) - { - if ((arr[1].compareTo("ssh-rsa") == 0) || (arr[1].compareTo("ssh-dss") == 0)) - { - String[] hostnames = arr[0].split(","); - - byte[] msg = Base64.decode(arr[2].toCharArray()); - - addHostkey(hostnames, arr[1], msg); - } - } - } - } - - private void initialize(File knownHosts) throws IOException - { - char[] buff = new char[512]; - - CharArrayWriter cw = new CharArrayWriter(); - - knownHosts.createNewFile(); - - FileReader fr = new FileReader(knownHosts); - - while (true) - { - int len = fr.read(buff); - if (len < 0) - break; - cw.write(buff, 0, len); - } - - fr.close(); - - initialize(cw.toCharArray()); - } - - private final boolean matchKeys(PublicKey key1, PublicKey key2) - { - return key1.equals(key2); - } - - private final boolean pseudoRegex(char[] pattern, int i, char[] match, int j) - { - /* This matching logic is equivalent to the one present in OpenSSH 4.1 */ - - while (true) - { - /* Are we at the end of the pattern? */ - - if (pattern.length == i) - return (match.length == j); - - if (pattern[i] == '*') - { - i++; - - if (pattern.length == i) - return true; - - if ((pattern[i] != '*') && (pattern[i] != '?')) - { - while (true) - { - if ((pattern[i] == match[j]) && pseudoRegex(pattern, i + 1, match, j + 1)) - return true; - j++; - if (match.length == j) - return false; - } - } - - while (true) - { - if (pseudoRegex(pattern, i, match, j)) - return true; - j++; - if (match.length == j) - return false; - } - } - - if (match.length == j) - return false; - - if ((pattern[i] != '?') && (pattern[i] != match[j])) - return false; - - i++; - j++; - } - } - - private String[] recommendHostkeyAlgorithms(String hostname) - { - String preferredAlgo = null; - - Vector<PublicKey> keys = getAllKeys(hostname); - - for (int i = 0; i < keys.size(); i++) - { - String thisAlgo = null; - - if (keys.elementAt(i) instanceof RSAPublicKey) - thisAlgo = "ssh-rsa"; - else if (keys.elementAt(i) instanceof DSAPublicKey) - thisAlgo = "ssh-dss"; - else - continue; - - if (preferredAlgo != null) - { - /* If we find different key types, then return null */ - - if (preferredAlgo.compareTo(thisAlgo) != 0) - return null; - - /* OK, we found the same algo again, optimize */ - - continue; - } - } - - /* If we did not find anything that we know of, return null */ - - if (preferredAlgo == null) - return null; - - /* Now put the preferred algo to the start of the array. - * You may ask yourself why we do it that way - basically, we could just - * return only the preferred algorithm: since we have a saved key of that - * type (sent earlier from the remote host), then that should work out. - * However, imagine that the server is (for whatever reasons) not offering - * that type of hostkey anymore (e.g., "ssh-rsa" was disabled and - * now "ssh-dss" is being used). If we then do not let the server send us - * a fresh key of the new type, then we shoot ourself into the foot: - * the connection cannot be established and hence the user cannot decide - * if he/she wants to accept the new key. - */ - - if (preferredAlgo.equals("ssh-rsa")) - return new String[] { "ssh-rsa", "ssh-dss" }; - - return new String[] { "ssh-dss", "ssh-rsa" }; - } - - /** - * Checks the internal hostkey database for the given hostkey. - * If no matching key can be found, then the hostname is resolved to an IP address - * and the search is repeated using that IP address. - * - * @param hostname the server's hostname, will be matched with all hostname patterns - * @param serverHostKeyAlgorithm type of hostkey, either <code>ssh-rsa</code> or <code>ssh-dss</code> - * @param serverHostKey the key blob - * @return <ul> - * <li><code>HOSTKEY_IS_OK</code>: the given hostkey matches an entry for the given hostname</li> - * <li><code>HOSTKEY_IS_NEW</code>: no entries found for this hostname and this type of hostkey</li> - * <li><code>HOSTKEY_HAS_CHANGED</code>: hostname is known, but with another key of the same type - * (man-in-the-middle attack?)</li> - * </ul> - * @throws IOException if the supplied key blob cannot be parsed or does not match the given hostkey type. - */ - public int verifyHostkey(String hostname, String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException - { - PublicKey remoteKey = null; - - if ("ssh-rsa".equals(serverHostKeyAlgorithm)) - { - remoteKey = RSASHA1Verify.decodeSSHRSAPublicKey(serverHostKey); - } - else if ("ssh-dss".equals(serverHostKeyAlgorithm)) - { - remoteKey = DSASHA1Verify.decodeSSHDSAPublicKey(serverHostKey); - } - else if (serverHostKeyAlgorithm.startsWith("ecdsa-sha2-")) - { - remoteKey = ECDSASHA2Verify.decodeSSHECDSAPublicKey(serverHostKey); - } - else - throw new IllegalArgumentException("Unknown hostkey type " + serverHostKeyAlgorithm); - - int result = checkKey(hostname, remoteKey); - - if (result == HOSTKEY_IS_OK) - return result; - - InetAddress[] ipAdresses = null; - - try - { - ipAdresses = InetAddress.getAllByName(hostname); - } - catch (UnknownHostException e) - { - return result; - } - - for (int i = 0; i < ipAdresses.length; i++) - { - int newresult = checkKey(ipAdresses[i].getHostAddress(), remoteKey); - - if (newresult == HOSTKEY_IS_OK) - return newresult; - - if (newresult == HOSTKEY_HAS_CHANGED) - result = HOSTKEY_HAS_CHANGED; - } - - return result; - } - - /** - * Adds a single public key entry to the a known_hosts file. - * This method is designed to be used in a {@link ServerHostKeyVerifier}. - * - * @param knownHosts the file where the publickey entry will be appended. - * @param hostnames a list of hostname patterns - at least one most be specified. Check out the - * OpenSSH sshd man page for a description of the pattern matching algorithm. - * @param serverHostKeyAlgorithm as passed to the {@link ServerHostKeyVerifier}. - * @param serverHostKey as passed to the {@link ServerHostKeyVerifier}. - * @throws IOException - */ - public final static void addHostkeyToFile(File knownHosts, String[] hostnames, String serverHostKeyAlgorithm, - byte[] serverHostKey) throws IOException - { - if ((hostnames == null) || (hostnames.length == 0)) - throw new IllegalArgumentException("Need at least one hostname specification"); - - if ((serverHostKeyAlgorithm == null) || (serverHostKey == null)) - throw new IllegalArgumentException(); - - CharArrayWriter writer = new CharArrayWriter(); - - for (int i = 0; i < hostnames.length; i++) - { - if (i != 0) - writer.write(','); - writer.write(hostnames[i]); - } - - writer.write(' '); - writer.write(serverHostKeyAlgorithm); - writer.write(' '); - writer.write(Base64.encode(serverHostKey)); - writer.write("\n"); - - char[] entry = writer.toCharArray(); - - RandomAccessFile raf = new RandomAccessFile(knownHosts, "rw"); - - long len = raf.length(); - - if (len > 0) - { - raf.seek(len - 1); - int last = raf.read(); - if (last != '\n') - raf.write('\n'); - } - - raf.write(new String(entry).getBytes("ISO-8859-1")); - raf.close(); - } - - /** - * Generates a "raw" fingerprint of a hostkey. - * - * @param type either "md5" or "sha1" - * @param keyType either "ssh-rsa" or "ssh-dss" - * @param hostkey the hostkey - * @return the raw fingerprint - */ - static final private byte[] rawFingerPrint(String type, String keyType, byte[] hostkey) - { - MessageDigest dig = null; - - try { - if ("md5".equals(type)) - { - dig = MessageDigest.getInstance("MD5"); - } - else if ("sha1".equals(type)) - { - dig = MessageDigest.getInstance("SHA1"); - } - else - { - throw new IllegalArgumentException("Unknown hash type " + type); - } - } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("Unknown hash type " + type); - } - - if (keyType.startsWith("ecdsa-sha2-")) - { - } - else if ("ssh-rsa".equals(keyType)) - { - } - else if ("ssh-dss".equals(keyType)) - { - } - else - throw new IllegalArgumentException("Unknown key type " + keyType); - - if (hostkey == null) - throw new IllegalArgumentException("hostkey is null"); - - dig.update(hostkey); - return dig.digest(); - } - - /** - * Convert a raw fingerprint to hex representation (XX:YY:ZZ...). - * @param fingerprint raw fingerprint - * @return the hex representation - */ - static final private String rawToHexFingerprint(byte[] fingerprint) - { - final char[] alpha = "0123456789abcdef".toCharArray(); - - StringBuffer sb = new StringBuffer(); - - for (int i = 0; i < fingerprint.length; i++) - { - if (i != 0) - sb.append(':'); - int b = fingerprint[i] & 0xff; - sb.append(alpha[b >> 4]); - sb.append(alpha[b & 15]); - } - - return sb.toString(); - } - - /** - * Convert a raw fingerprint to bubblebabble representation. - * @param raw raw fingerprint - * @return the bubblebabble representation - */ - static final private String rawToBubblebabbleFingerprint(byte[] raw) - { - final char[] v = "aeiouy".toCharArray(); - final char[] c = "bcdfghklmnprstvzx".toCharArray(); - - StringBuffer sb = new StringBuffer(); - - int seed = 1; - - int rounds = (raw.length / 2) + 1; - - sb.append('x'); - - for (int i = 0; i < rounds; i++) - { - if (((i + 1) < rounds) || ((raw.length) % 2 != 0)) - { - sb.append(v[(((raw[2 * i] >> 6) & 3) + seed) % 6]); - sb.append(c[(raw[2 * i] >> 2) & 15]); - sb.append(v[((raw[2 * i] & 3) + (seed / 6)) % 6]); - - if ((i + 1) < rounds) - { - sb.append(c[(((raw[(2 * i) + 1])) >> 4) & 15]); - sb.append('-'); - sb.append(c[(((raw[(2 * i) + 1]))) & 15]); - // As long as seed >= 0, seed will be >= 0 afterwards - seed = ((seed * 5) + (((raw[2 * i] & 0xff) * 7) + (raw[(2 * i) + 1] & 0xff))) % 36; - } - } - else - { - sb.append(v[seed % 6]); // seed >= 0, therefore index positive - sb.append('x'); - sb.append(v[seed / 6]); - } - } - - sb.append('x'); - - return sb.toString(); - } - - /** - * Convert a ssh2 key-blob into a human readable hex fingerprint. - * Generated fingerprints are identical to those generated by OpenSSH. - * <p> - * Example fingerprint: d0:cb:76:19:99:5a:03:fc:73:10:70:93:f2:44:63:47. - - * @param keytype either "ssh-rsa" or "ssh-dss" - * @param publickey key blob - * @return Hex fingerprint - */ - public final static String createHexFingerprint(String keytype, byte[] publickey) - { - byte[] raw = rawFingerPrint("md5", keytype, publickey); - return rawToHexFingerprint(raw); - } - - /** - * Convert a ssh2 key-blob into a human readable bubblebabble fingerprint. - * The used bubblebabble algorithm (taken from OpenSSH) generates fingerprints - * that are easier to remember for humans. - * <p> - * Example fingerprint: xofoc-bubuz-cazin-zufyl-pivuk-biduk-tacib-pybur-gonar-hotat-lyxux. - * - * @param keytype either "ssh-rsa" or "ssh-dss" - * @param publickey key data - * @return Bubblebabble fingerprint - */ - public final static String createBubblebabbleFingerprint(String keytype, byte[] publickey) - { - byte[] raw = rawFingerPrint("sha1", keytype, publickey); - return rawToBubblebabbleFingerprint(raw); - } -} diff --git a/src/com/trilead/ssh2/LocalPortForwarder.java b/src/com/trilead/ssh2/LocalPortForwarder.java deleted file mode 100644 index 96fa082..0000000 --- a/src/com/trilead/ssh2/LocalPortForwarder.java +++ /dev/null @@ -1,63 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.IOException; -import java.net.InetSocketAddress; - -import com.trilead.ssh2.channel.ChannelManager; -import com.trilead.ssh2.channel.LocalAcceptThread; - - -/** - * A <code>LocalPortForwarder</code> forwards TCP/IP connections to a local - * port via the secure tunnel to another host (which may or may not be identical - * to the remote SSH-2 server). Checkout {@link Connection#createLocalPortForwarder(int, String, int)} - * on how to create one. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: LocalPortForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class LocalPortForwarder -{ - ChannelManager cm; - - String host_to_connect; - - int port_to_connect; - - LocalAcceptThread lat; - - LocalPortForwarder(ChannelManager cm, int local_port, String host_to_connect, int port_to_connect) - throws IOException - { - this.cm = cm; - this.host_to_connect = host_to_connect; - this.port_to_connect = port_to_connect; - - lat = new LocalAcceptThread(cm, local_port, host_to_connect, port_to_connect); - lat.setDaemon(true); - lat.start(); - } - - LocalPortForwarder(ChannelManager cm, InetSocketAddress addr, String host_to_connect, int port_to_connect) - throws IOException - { - this.cm = cm; - this.host_to_connect = host_to_connect; - this.port_to_connect = port_to_connect; - - lat = new LocalAcceptThread(cm, addr, host_to_connect, port_to_connect); - lat.setDaemon(true); - lat.start(); - } - - /** - * Stop TCP/IP forwarding of newly arriving connections. - * - * @throws IOException - */ - public void close() throws IOException - { - lat.stopWorking(); - } -} diff --git a/src/com/trilead/ssh2/LocalStreamForwarder.java b/src/com/trilead/ssh2/LocalStreamForwarder.java deleted file mode 100644 index 7899367..0000000 --- a/src/com/trilead/ssh2/LocalStreamForwarder.java +++ /dev/null @@ -1,78 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import com.trilead.ssh2.channel.Channel; -import com.trilead.ssh2.channel.ChannelManager; -import com.trilead.ssh2.channel.LocalAcceptThread; - - -/** - * A <code>LocalStreamForwarder</code> forwards an Input- and Outputstream - * pair via the secure tunnel to another host (which may or may not be identical - * to the remote SSH-2 server). - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: LocalStreamForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class LocalStreamForwarder -{ - ChannelManager cm; - - String host_to_connect; - int port_to_connect; - LocalAcceptThread lat; - - Channel cn; - - LocalStreamForwarder(ChannelManager cm, String host_to_connect, int port_to_connect) throws IOException - { - this.cm = cm; - this.host_to_connect = host_to_connect; - this.port_to_connect = port_to_connect; - - cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, "127.0.0.1", 0); - } - - /** - * @return An <code>InputStream</code> object. - * @throws IOException - */ - public InputStream getInputStream() throws IOException - { - return cn.getStdoutStream(); - } - - /** - * Get the OutputStream. Please be aware that the implementation MAY use an - * internal buffer. To make sure that the buffered data is sent over the - * tunnel, you have to call the <code>flush</code> method of the - * <code>OutputStream</code>. To signal EOF, please use the - * <code>close</code> method of the <code>OutputStream</code>. - * - * @return An <code>OutputStream</code> object. - * @throws IOException - */ - public OutputStream getOutputStream() throws IOException - { - return cn.getStdinStream(); - } - - /** - * Close the underlying SSH forwarding channel and free up resources. - * You can also use this method to force the shutdown of the underlying - * forwarding channel. Pending output (OutputStream not flushed) will NOT - * be sent. Pending input (InputStream) can still be read. If the shutdown - * operation is already in progress (initiated from either side), then this - * call is a no-op. - * - * @throws IOException - */ - public void close() throws IOException - { - cm.closeChannel(cn, "Closed due to user request.", true); - } -} diff --git a/src/com/trilead/ssh2/ProxyData.java b/src/com/trilead/ssh2/ProxyData.java deleted file mode 100644 index 059a6e3..0000000 --- a/src/com/trilead/ssh2/ProxyData.java +++ /dev/null @@ -1,15 +0,0 @@ - -package com.trilead.ssh2; - -/** - * An abstract marker interface implemented by all proxy data implementations. - * - * @see HTTPProxyData - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ProxyData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public abstract interface ProxyData -{ -} diff --git a/src/com/trilead/ssh2/SCPClient.java b/src/com/trilead/ssh2/SCPClient.java deleted file mode 100644 index b692750..0000000 --- a/src/com/trilead/ssh2/SCPClient.java +++ /dev/null @@ -1,729 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * A very basic <code>SCPClient</code> that can be used to copy files from/to - * the SSH-2 server. On the server side, the "scp" program must be in the PATH. - * <p> - * This scp client is thread safe - you can download (and upload) different sets - * of files concurrently without any troubles. The <code>SCPClient</code> is - * actually mapping every request to a distinct {@link Session}. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: SCPClient.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ - -public class SCPClient -{ - Connection conn; - - class LenNamePair - { - long length; - String filename; - } - - public SCPClient(Connection conn) - { - if (conn == null) - throw new IllegalArgumentException("Cannot accept null argument!"); - this.conn = conn; - } - - private void readResponse(InputStream is) throws IOException - { - int c = is.read(); - - if (c == 0) - return; - - if (c == -1) - throw new IOException("Remote scp terminated unexpectedly."); - - if ((c != 1) && (c != 2)) - throw new IOException("Remote scp sent illegal error code."); - - if (c == 2) - throw new IOException("Remote scp terminated with error."); - - String err = receiveLine(is); - throw new IOException("Remote scp terminated with error (" + err + ")."); - } - - private String receiveLine(InputStream is) throws IOException - { - StringBuffer sb = new StringBuffer(30); - - while (true) - { - /* - * This is a random limit - if your path names are longer, then - * adjust it - */ - - if (sb.length() > 8192) - throw new IOException("Remote scp sent a too long line"); - - int c = is.read(); - - if (c < 0) - throw new IOException("Remote scp terminated unexpectedly."); - - if (c == '\n') - break; - - sb.append((char) c); - - } - return sb.toString(); - } - - private LenNamePair parseCLine(String line) throws IOException - { - /* Minimum line: "xxxx y z" ---> 8 chars */ - - long len; - - if (line.length() < 8) - throw new IOException("Malformed C line sent by remote SCP binary, line too short."); - - if ((line.charAt(4) != ' ') || (line.charAt(5) == ' ')) - throw new IOException("Malformed C line sent by remote SCP binary."); - - int length_name_sep = line.indexOf(' ', 5); - - if (length_name_sep == -1) - throw new IOException("Malformed C line sent by remote SCP binary."); - - String length_substring = line.substring(5, length_name_sep); - String name_substring = line.substring(length_name_sep + 1); - - if ((length_substring.length() <= 0) || (name_substring.length() <= 0)) - throw new IOException("Malformed C line sent by remote SCP binary."); - - if ((6 + length_substring.length() + name_substring.length()) != line.length()) - throw new IOException("Malformed C line sent by remote SCP binary."); - - try - { - len = Long.parseLong(length_substring); - } - catch (NumberFormatException e) - { - throw new IOException("Malformed C line sent by remote SCP binary, cannot parse file length."); - } - - if (len < 0) - throw new IOException("Malformed C line sent by remote SCP binary, illegal file length."); - - LenNamePair lnp = new LenNamePair(); - lnp.length = len; - lnp.filename = name_substring; - - return lnp; - } - - private void sendBytes(Session sess, byte[] data, String fileName, String mode) throws IOException - { - OutputStream os = sess.getStdin(); - InputStream is = new BufferedInputStream(sess.getStdout(), 512); - - readResponse(is); - - String cline = "C" + mode + " " + data.length + " " + fileName + "\n"; - - os.write(cline.getBytes("ISO-8859-1")); - os.flush(); - - readResponse(is); - - os.write(data, 0, data.length); - os.write(0); - os.flush(); - - readResponse(is); - - os.write("E\n".getBytes("ISO-8859-1")); - os.flush(); - } - - private void sendFiles(Session sess, String[] files, String[] remoteFiles, String mode) throws IOException - { - byte[] buffer = new byte[8192]; - - OutputStream os = new BufferedOutputStream(sess.getStdin(), 40000); - InputStream is = new BufferedInputStream(sess.getStdout(), 512); - - readResponse(is); - - for (int i = 0; i < files.length; i++) - { - File f = new File(files[i]); - long remain = f.length(); - - String remoteName; - - if ((remoteFiles != null) && (remoteFiles.length > i) && (remoteFiles[i] != null)) - remoteName = remoteFiles[i]; - else - remoteName = f.getName(); - - String cline = "C" + mode + " " + remain + " " + remoteName + "\n"; - - os.write(cline.getBytes("ISO-8859-1")); - os.flush(); - - readResponse(is); - - FileInputStream fis = null; - - try - { - fis = new FileInputStream(f); - - while (remain > 0) - { - int trans; - if (remain > buffer.length) - trans = buffer.length; - else - trans = (int) remain; - - if (fis.read(buffer, 0, trans) != trans) - throw new IOException("Cannot read enough from local file " + files[i]); - - os.write(buffer, 0, trans); - - remain -= trans; - } - } - finally - { - if (fis != null) - fis.close(); - } - - os.write(0); - os.flush(); - - readResponse(is); - } - - os.write("E\n".getBytes("ISO-8859-1")); - os.flush(); - } - - private void receiveFiles(Session sess, OutputStream[] targets) throws IOException - { - byte[] buffer = new byte[8192]; - - OutputStream os = new BufferedOutputStream(sess.getStdin(), 512); - InputStream is = new BufferedInputStream(sess.getStdout(), 40000); - - os.write(0x0); - os.flush(); - - for (int i = 0; i < targets.length; i++) - { - LenNamePair lnp = null; - - while (true) - { - int c = is.read(); - if (c < 0) - throw new IOException("Remote scp terminated unexpectedly."); - - String line = receiveLine(is); - - if (c == 'T') - { - /* Ignore modification times */ - - continue; - } - - if ((c == 1) || (c == 2)) - throw new IOException("Remote SCP error: " + line); - - if (c == 'C') - { - lnp = parseCLine(line); - break; - - } - throw new IOException("Remote SCP error: " + ((char) c) + line); - } - - os.write(0x0); - os.flush(); - - long remain = lnp.length; - - while (remain > 0) - { - int trans; - if (remain > buffer.length) - trans = buffer.length; - else - trans = (int) remain; - - int this_time_received = is.read(buffer, 0, trans); - - if (this_time_received < 0) - { - throw new IOException("Remote scp terminated connection unexpectedly"); - } - - targets[i].write(buffer, 0, this_time_received); - - remain -= this_time_received; - } - - readResponse(is); - - os.write(0x0); - os.flush(); - } - } - - private void receiveFiles(Session sess, String[] files, String target) throws IOException - { - byte[] buffer = new byte[8192]; - - OutputStream os = new BufferedOutputStream(sess.getStdin(), 512); - InputStream is = new BufferedInputStream(sess.getStdout(), 40000); - - os.write(0x0); - os.flush(); - - for (int i = 0; i < files.length; i++) - { - LenNamePair lnp = null; - - while (true) - { - int c = is.read(); - if (c < 0) - throw new IOException("Remote scp terminated unexpectedly."); - - String line = receiveLine(is); - - if (c == 'T') - { - /* Ignore modification times */ - - continue; - } - - if ((c == 1) || (c == 2)) - throw new IOException("Remote SCP error: " + line); - - if (c == 'C') - { - lnp = parseCLine(line); - break; - - } - throw new IOException("Remote SCP error: " + ((char) c) + line); - } - - os.write(0x0); - os.flush(); - - File f = new File(target + File.separatorChar + lnp.filename); - FileOutputStream fop = null; - - try - { - fop = new FileOutputStream(f); - - long remain = lnp.length; - - while (remain > 0) - { - int trans; - if (remain > buffer.length) - trans = buffer.length; - else - trans = (int) remain; - - int this_time_received = is.read(buffer, 0, trans); - - if (this_time_received < 0) - { - throw new IOException("Remote scp terminated connection unexpectedly"); - } - - fop.write(buffer, 0, this_time_received); - - remain -= this_time_received; - } - } - finally - { - if (fop != null) - fop.close(); - } - - readResponse(is); - - os.write(0x0); - os.flush(); - } - } - - /** - * Copy a local file to a remote directory, uses mode 0600 when creating the - * file on the remote side. - * - * @param localFile - * Path and name of local file. - * @param remoteTargetDirectory - * Remote target directory. Use an empty string to specify the - * default directory. - * - * @throws IOException - */ - public void put(String localFile, String remoteTargetDirectory) throws IOException - { - put(new String[] { localFile }, remoteTargetDirectory, "0600"); - } - - /** - * Copy a set of local files to a remote directory, uses mode 0600 when - * creating files on the remote side. - * - * @param localFiles - * Paths and names of local file names. - * @param remoteTargetDirectory - * Remote target directory. Use an empty string to specify the - * default directory. - * - * @throws IOException - */ - - public void put(String[] localFiles, String remoteTargetDirectory) throws IOException - { - put(localFiles, remoteTargetDirectory, "0600"); - } - - /** - * Copy a local file to a remote directory, uses the specified mode when - * creating the file on the remote side. - * - * @param localFile - * Path and name of local file. - * @param remoteTargetDirectory - * Remote target directory. Use an empty string to specify the - * default directory. - * @param mode - * a four digit string (e.g., 0644, see "man chmod", "man open") - * @throws IOException - */ - public void put(String localFile, String remoteTargetDirectory, String mode) throws IOException - { - put(new String[] { localFile }, remoteTargetDirectory, mode); - } - - /** - * Copy a local file to a remote directory, uses the specified mode and - * remote filename when creating the file on the remote side. - * - * @param localFile - * Path and name of local file. - * @param remoteFileName - * The name of the file which will be created in the remote - * target directory. - * @param remoteTargetDirectory - * Remote target directory. Use an empty string to specify the - * default directory. - * @param mode - * a four digit string (e.g., 0644, see "man chmod", "man open") - * @throws IOException - */ - public void put(String localFile, String remoteFileName, String remoteTargetDirectory, String mode) - throws IOException - { - put(new String[] { localFile }, new String[] { remoteFileName }, remoteTargetDirectory, mode); - } - - /** - * Create a remote file and copy the contents of the passed byte array into - * it. Uses mode 0600 for creating the remote file. - * - * @param data - * the data to be copied into the remote file. - * @param remoteFileName - * The name of the file which will be created in the remote - * target directory. - * @param remoteTargetDirectory - * Remote target directory. Use an empty string to specify the - * default directory. - * @throws IOException - */ - - public void put(byte[] data, String remoteFileName, String remoteTargetDirectory) throws IOException - { - put(data, remoteFileName, remoteTargetDirectory, "0600"); - } - - /** - * Create a remote file and copy the contents of the passed byte array into - * it. The method use the specified mode when creating the file on the - * remote side. - * - * @param data - * the data to be copied into the remote file. - * @param remoteFileName - * The name of the file which will be created in the remote - * target directory. - * @param remoteTargetDirectory - * Remote target directory. Use an empty string to specify the - * default directory. - * @param mode - * a four digit string (e.g., 0644, see "man chmod", "man open") - * @throws IOException - */ - public void put(byte[] data, String remoteFileName, String remoteTargetDirectory, String mode) throws IOException - { - Session sess = null; - - if ((remoteFileName == null) || (remoteTargetDirectory == null) || (mode == null)) - throw new IllegalArgumentException("Null argument."); - - if (mode.length() != 4) - throw new IllegalArgumentException("Invalid mode."); - - for (int i = 0; i < mode.length(); i++) - if (Character.isDigit(mode.charAt(i)) == false) - throw new IllegalArgumentException("Invalid mode."); - - remoteTargetDirectory = remoteTargetDirectory.trim(); - remoteTargetDirectory = (remoteTargetDirectory.length() > 0) ? remoteTargetDirectory : "."; - - String cmd = "scp -t -d " + remoteTargetDirectory; - - try - { - sess = conn.openSession(); - sess.execCommand(cmd); - sendBytes(sess, data, remoteFileName, mode); - } - catch (IOException e) - { - throw (IOException) new IOException("Error during SCP transfer.").initCause(e); - } - finally - { - if (sess != null) - sess.close(); - } - } - - /** - * Copy a set of local files to a remote directory, uses the specified mode - * when creating the files on the remote side. - * - * @param localFiles - * Paths and names of the local files. - * @param remoteTargetDirectory - * Remote target directory. Use an empty string to specify the - * default directory. - * @param mode - * a four digit string (e.g., 0644, see "man chmod", "man open") - * @throws IOException - */ - public void put(String[] localFiles, String remoteTargetDirectory, String mode) throws IOException - { - put(localFiles, null, remoteTargetDirectory, mode); - } - - public void put(String[] localFiles, String[] remoteFiles, String remoteTargetDirectory, String mode) - throws IOException - { - Session sess = null; - - /* - * remoteFiles may be null, indicating that the local filenames shall be - * used - */ - - if ((localFiles == null) || (remoteTargetDirectory == null) || (mode == null)) - throw new IllegalArgumentException("Null argument."); - - if (mode.length() != 4) - throw new IllegalArgumentException("Invalid mode."); - - for (int i = 0; i < mode.length(); i++) - if (Character.isDigit(mode.charAt(i)) == false) - throw new IllegalArgumentException("Invalid mode."); - - if (localFiles.length == 0) - return; - - remoteTargetDirectory = remoteTargetDirectory.trim(); - remoteTargetDirectory = (remoteTargetDirectory.length() > 0) ? remoteTargetDirectory : "."; - - String cmd = "scp -t -d " + remoteTargetDirectory; - - for (int i = 0; i < localFiles.length; i++) - { - if (localFiles[i] == null) - throw new IllegalArgumentException("Cannot accept null filename."); - } - - try - { - sess = conn.openSession(); - sess.execCommand(cmd); - sendFiles(sess, localFiles, remoteFiles, mode); - } - catch (IOException e) - { - throw (IOException) new IOException("Error during SCP transfer.").initCause(e); - } - finally - { - if (sess != null) - sess.close(); - } - } - - /** - * Download a file from the remote server to a local directory. - * - * @param remoteFile - * Path and name of the remote file. - * @param localTargetDirectory - * Local directory to put the downloaded file. - * - * @throws IOException - */ - public void get(String remoteFile, String localTargetDirectory) throws IOException - { - get(new String[] { remoteFile }, localTargetDirectory); - } - - /** - * Download a file from the remote server and pipe its contents into an - * <code>OutputStream</code>. Please note that, to enable flexible usage - * of this method, the <code>OutputStream</code> will not be closed nor - * flushed. - * - * @param remoteFile - * Path and name of the remote file. - * @param target - * OutputStream where the contents of the file will be sent to. - * @throws IOException - */ - public void get(String remoteFile, OutputStream target) throws IOException - { - get(new String[] { remoteFile }, new OutputStream[] { target }); - } - - private void get(String remoteFiles[], OutputStream[] targets) throws IOException - { - Session sess = null; - - if ((remoteFiles == null) || (targets == null)) - throw new IllegalArgumentException("Null argument."); - - if (remoteFiles.length != targets.length) - throw new IllegalArgumentException("Length of arguments does not match."); - - if (remoteFiles.length == 0) - return; - - String cmd = "scp -f"; - - for (int i = 0; i < remoteFiles.length; i++) - { - if (remoteFiles[i] == null) - throw new IllegalArgumentException("Cannot accept null filename."); - - String tmp = remoteFiles[i].trim(); - - if (tmp.length() == 0) - throw new IllegalArgumentException("Cannot accept empty filename."); - - cmd += (" " + tmp); - } - - try - { - sess = conn.openSession(); - sess.execCommand(cmd); - receiveFiles(sess, targets); - } - catch (IOException e) - { - throw (IOException) new IOException("Error during SCP transfer.").initCause(e); - } - finally - { - if (sess != null) - sess.close(); - } - } - - /** - * Download a set of files from the remote server to a local directory. - * - * @param remoteFiles - * Paths and names of the remote files. - * @param localTargetDirectory - * Local directory to put the downloaded files. - * - * @throws IOException - */ - public void get(String remoteFiles[], String localTargetDirectory) throws IOException - { - Session sess = null; - - if ((remoteFiles == null) || (localTargetDirectory == null)) - throw new IllegalArgumentException("Null argument."); - - if (remoteFiles.length == 0) - return; - - String cmd = "scp -f"; - - for (int i = 0; i < remoteFiles.length; i++) - { - if (remoteFiles[i] == null) - throw new IllegalArgumentException("Cannot accept null filename."); - - String tmp = remoteFiles[i].trim(); - - if (tmp.length() == 0) - throw new IllegalArgumentException("Cannot accept empty filename."); - - cmd += (" " + tmp); - } - - try - { - sess = conn.openSession(); - sess.execCommand(cmd); - receiveFiles(sess, remoteFiles, localTargetDirectory); - } - catch (IOException e) - { - throw (IOException) new IOException("Error during SCP transfer.").initCause(e); - } - finally - { - if (sess != null) - sess.close(); - } - } -} diff --git a/src/com/trilead/ssh2/SFTPException.java b/src/com/trilead/ssh2/SFTPException.java deleted file mode 100644 index d97723f..0000000 --- a/src/com/trilead/ssh2/SFTPException.java +++ /dev/null @@ -1,91 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.IOException; - -import com.trilead.ssh2.sftp.ErrorCodes; - - -/** - * Used in combination with the SFTPv3Client. This exception wraps - * error messages sent by the SFTP server. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: SFTPException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public class SFTPException extends IOException -{ - private static final long serialVersionUID = 578654644222421811L; - - private final String sftpErrorMessage; - private final int sftpErrorCode; - - private static String constructMessage(String s, int errorCode) - { - String[] detail = ErrorCodes.getDescription(errorCode); - - if (detail == null) - return s + " (UNKNOW SFTP ERROR CODE)"; - - return s + " (" + detail[0] + ": " + detail[1] + ")"; - } - - SFTPException(String msg, int errorCode) - { - super(constructMessage(msg, errorCode)); - sftpErrorMessage = msg; - sftpErrorCode = errorCode; - } - - /** - * Get the error message sent by the server. Often, this - * message does not help a lot (e.g., "failure"). - * - * @return the plain string as sent by the server. - */ - public String getServerErrorMessage() - { - return sftpErrorMessage; - } - - /** - * Get the error code sent by the server. - * - * @return an error code as defined in the SFTP specs. - */ - public int getServerErrorCode() - { - return sftpErrorCode; - } - - /** - * Get the symbolic name of the error code as given in the SFTP specs. - * - * @return e.g., "SSH_FX_INVALID_FILENAME". - */ - public String getServerErrorCodeSymbol() - { - String[] detail = ErrorCodes.getDescription(sftpErrorCode); - - if (detail == null) - return "UNKNOW SFTP ERROR CODE " + sftpErrorCode; - - return detail[0]; - } - - /** - * Get the description of the error code as given in the SFTP specs. - * - * @return e.g., "The filename is not valid." - */ - public String getServerErrorCodeVerbose() - { - String[] detail = ErrorCodes.getDescription(sftpErrorCode); - - if (detail == null) - return "The error code " + sftpErrorCode + " is unknown."; - - return detail[1]; - } -} diff --git a/src/com/trilead/ssh2/SFTPv3Client.java b/src/com/trilead/ssh2/SFTPv3Client.java deleted file mode 100644 index 06796e9..0000000 --- a/src/com/trilead/ssh2/SFTPv3Client.java +++ /dev/null @@ -1,1388 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Vector; - -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.packets.TypesWriter; -import com.trilead.ssh2.sftp.AttribFlags; -import com.trilead.ssh2.sftp.ErrorCodes; -import com.trilead.ssh2.sftp.Packet; - - -/** - * A <code>SFTPv3Client</code> represents a SFTP (protocol version 3) - * client connection tunnelled over a SSH-2 connection. This is a very simple - * (synchronous) implementation. - * <p> - * Basically, most methods in this class map directly to one of - * the packet types described in draft-ietf-secsh-filexfer-02.txt. - * <p> - * Note: this is experimental code. - * <p> - * Error handling: the methods of this class throw IOExceptions. However, unless - * there is catastrophic failure, exceptions of the type {@link SFTPv3Client} will - * be thrown (a subclass of IOException). Therefore, you can implement more verbose - * behavior by checking if a thrown exception if of this type. If yes, then you - * can cast the exception and access detailed information about the failure. - * <p> - * Notes about file names, directory names and paths, copy-pasted - * from the specs: - * <ul> - * <li>SFTP v3 represents file names as strings. File names are - * assumed to use the slash ('/') character as a directory separator.</li> - * <li>File names starting with a slash are "absolute", and are relative to - * the root of the file system. Names starting with any other character - * are relative to the user's default directory (home directory).</li> - * <li>Servers SHOULD interpret a path name component ".." as referring to - * the parent directory, and "." as referring to the current directory. - * If the server implementation limits access to certain parts of the - * file system, it must be extra careful in parsing file names when - * enforcing such restrictions. There have been numerous reported - * security bugs where a ".." in a path name has allowed access outside - * the intended area.</li> - * <li>An empty path name is valid, and it refers to the user's default - * directory (usually the user's home directory).</li> - * </ul> - * <p> - * If you are still not tired then please go on and read the comment for - * {@link #setCharset(String)}. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: SFTPv3Client.java,v 1.3 2008/04/01 12:38:09 cplattne Exp $ - */ -public class SFTPv3Client -{ - final Connection conn; - final Session sess; - final PrintStream debug; - - boolean flag_closed = false; - - InputStream is; - OutputStream os; - - int protocol_version = 0; - HashMap server_extensions = new HashMap(); - - int next_request_id = 1000; - - String charsetName = null; - - /** - * Create a SFTP v3 client. - * - * @param conn The underlying SSH-2 connection to be used. - * @param debug - * @throws IOException - * - * @deprecated this constructor (debug version) will disappear in the future, - * use {@link #SFTPv3Client(Connection)} instead. - */ - public SFTPv3Client(Connection conn, PrintStream debug) throws IOException - { - if (conn == null) - throw new IllegalArgumentException("Cannot accept null argument!"); - - this.conn = conn; - this.debug = debug; - - if (debug != null) - debug.println("Opening session and starting SFTP subsystem."); - - sess = conn.openSession(); - sess.startSubSystem("sftp"); - - is = sess.getStdout(); - os = new BufferedOutputStream(sess.getStdin(), 2048); - - if ((is == null) || (os == null)) - throw new IOException("There is a problem with the streams of the underlying channel."); - - init(); - } - - /** - * Create a SFTP v3 client. - * - * @param conn The underlying SSH-2 connection to be used. - * @throws IOException - */ - public SFTPv3Client(Connection conn) throws IOException - { - this(conn, null); - } - - /** - * Set the charset used to convert between Java Unicode Strings and byte encodings - * used by the server for paths and file names. Unfortunately, the SFTP v3 draft - * says NOTHING about such conversions (well, with the exception of error messages - * which have to be in UTF-8). Newer drafts specify to use UTF-8 for file names - * (if I remember correctly). However, a quick test using OpenSSH serving a EXT-3 - * filesystem has shown that UTF-8 seems to be a bad choice for SFTP v3 (tested with - * filenames containing german umlauts). "windows-1252" seems to work better for Europe. - * Luckily, "windows-1252" is the platform default in my case =). - * <p> - * If you don't set anything, then the platform default will be used (this is the default - * behavior). - * - * @see #getCharset() - * - * @param charset the name of the charset to be used or <code>null</code> to use the platform's - * default encoding. - * @throws IOException - */ - public void setCharset(String charset) throws IOException - { - if (charset == null) - { - charsetName = charset; - return; - } - - try - { - Charset.forName(charset); - } - catch (Exception e) - { - throw (IOException) new IOException("This charset is not supported").initCause(e); - } - charsetName = charset; - } - - /** - * The currently used charset for filename encoding/decoding. - * - * @see #setCharset(String) - * - * @return The name of the charset (<code>null</code> if the platform's default charset is being used) - */ - public String getCharset() - { - return charsetName; - } - - private final void checkHandleValidAndOpen(SFTPv3FileHandle handle) throws IOException - { - if (handle.client != this) - throw new IOException("The file handle was created with another SFTPv3FileHandle instance."); - - if (handle.isClosed == true) - throw new IOException("The file handle is closed."); - } - - private final void sendMessage(int type, int requestId, byte[] msg, int off, int len) throws IOException - { - int msglen = len + 1; - - if (type != Packet.SSH_FXP_INIT) - msglen += 4; - - os.write(msglen >> 24); - os.write(msglen >> 16); - os.write(msglen >> 8); - os.write(msglen); - os.write(type); - - if (type != Packet.SSH_FXP_INIT) - { - os.write(requestId >> 24); - os.write(requestId >> 16); - os.write(requestId >> 8); - os.write(requestId); - } - - os.write(msg, off, len); - os.flush(); - } - - private final void sendMessage(int type, int requestId, byte[] msg) throws IOException - { - sendMessage(type, requestId, msg, 0, msg.length); - } - - private final void readBytes(byte[] buff, int pos, int len) throws IOException - { - while (len > 0) - { - int count = is.read(buff, pos, len); - if (count < 0) - throw new IOException("Unexpected end of sftp stream."); - if ((count == 0) || (count > len)) - throw new IOException("Underlying stream implementation is bogus!"); - len -= count; - pos += count; - } - } - - /** - * Read a message and guarantee that the <b>contents</b> is not larger than - * <code>maxlen</code> bytes. - * <p> - * Note: receiveMessage(34000) actually means that the message may be up to 34004 - * bytes (the length attribute preceeding the contents is 4 bytes). - * - * @param maxlen - * @return the message contents - * @throws IOException - */ - private final byte[] receiveMessage(int maxlen) throws IOException - { - byte[] msglen = new byte[4]; - - readBytes(msglen, 0, 4); - - int len = (((msglen[0] & 0xff) << 24) | ((msglen[1] & 0xff) << 16) | ((msglen[2] & 0xff) << 8) | (msglen[3] & 0xff)); - - if ((len > maxlen) || (len <= 0)) - throw new IOException("Illegal sftp packet len: " + len); - - byte[] msg = new byte[len]; - - readBytes(msg, 0, len); - - return msg; - } - - private final int generateNextRequestID() - { - synchronized (this) - { - return next_request_id++; - } - } - - private final void closeHandle(byte[] handle) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(handle, 0, handle.length); - - sendMessage(Packet.SSH_FXP_CLOSE, req_id, tw.getBytes()); - - expectStatusOKMessage(req_id); - } - - private SFTPv3FileAttributes readAttrs(TypesReader tr) throws IOException - { - /* - * uint32 flags - * uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE - * uint32 uid present only if flag SSH_FILEXFER_ATTR_V3_UIDGID - * uint32 gid present only if flag SSH_FILEXFER_ATTR_V3_UIDGID - * uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS - * uint32 atime present only if flag SSH_FILEXFER_ATTR_V3_ACMODTIME - * uint32 mtime present only if flag SSH_FILEXFER_ATTR_V3_ACMODTIME - * uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED - * string extended_type - * string extended_data - * ... more extended data (extended_type - extended_data pairs), - * so that number of pairs equals extended_count - */ - - SFTPv3FileAttributes fa = new SFTPv3FileAttributes(); - - int flags = tr.readUINT32(); - - if ((flags & AttribFlags.SSH_FILEXFER_ATTR_SIZE) != 0) - { - if (debug != null) - debug.println("SSH_FILEXFER_ATTR_SIZE"); - fa.size = new Long(tr.readUINT64()); - } - - if ((flags & AttribFlags.SSH_FILEXFER_ATTR_V3_UIDGID) != 0) - { - if (debug != null) - debug.println("SSH_FILEXFER_ATTR_V3_UIDGID"); - fa.uid = new Integer(tr.readUINT32()); - fa.gid = new Integer(tr.readUINT32()); - } - - if ((flags & AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) - { - if (debug != null) - debug.println("SSH_FILEXFER_ATTR_PERMISSIONS"); - fa.permissions = new Integer(tr.readUINT32()); - } - - if ((flags & AttribFlags.SSH_FILEXFER_ATTR_V3_ACMODTIME) != 0) - { - if (debug != null) - debug.println("SSH_FILEXFER_ATTR_V3_ACMODTIME"); - fa.atime = new Long(((long)tr.readUINT32()) & 0xffffffffl); - fa.mtime = new Long(((long)tr.readUINT32()) & 0xffffffffl); - - } - - if ((flags & AttribFlags.SSH_FILEXFER_ATTR_EXTENDED) != 0) - { - int count = tr.readUINT32(); - - if (debug != null) - debug.println("SSH_FILEXFER_ATTR_EXTENDED (" + count + ")"); - - /* Read it anyway to detect corrupt packets */ - - while (count > 0) - { - tr.readByteString(); - tr.readByteString(); - count--; - } - } - - return fa; - } - - /** - * Retrieve the file attributes of an open file. - * - * @param handle a SFTPv3FileHandle handle. - * @return a SFTPv3FileAttributes object. - * @throws IOException - */ - public SFTPv3FileAttributes fstat(SFTPv3FileHandle handle) throws IOException - { - checkHandleValidAndOpen(handle); - - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(handle.fileHandle, 0, handle.fileHandle.length); - - if (debug != null) - { - debug.println("Sending SSH_FXP_FSTAT..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_FSTAT, req_id, tw.getBytes()); - - byte[] resp = receiveMessage(34000); - - if (debug != null) - { - debug.println("Got REPLY."); - debug.flush(); - } - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t == Packet.SSH_FXP_ATTRS) - { - return readAttrs(tr); - } - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - - throw new SFTPException(tr.readString(), errorCode); - } - - private SFTPv3FileAttributes statBoth(String path, int statMethod) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(path, charsetName); - - if (debug != null) - { - debug.println("Sending SSH_FXP_STAT/SSH_FXP_LSTAT..."); - debug.flush(); - } - - sendMessage(statMethod, req_id, tw.getBytes()); - - byte[] resp = receiveMessage(34000); - - if (debug != null) - { - debug.println("Got REPLY."); - debug.flush(); - } - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t == Packet.SSH_FXP_ATTRS) - { - return readAttrs(tr); - } - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - - throw new SFTPException(tr.readString(), errorCode); - } - - /** - * Retrieve the file attributes of a file. This method - * follows symbolic links on the server. - * - * @see #lstat(String) - * - * @param path See the {@link SFTPv3Client comment} for the class for more details. - * @return a SFTPv3FileAttributes object. - * @throws IOException - */ - public SFTPv3FileAttributes stat(String path) throws IOException - { - return statBoth(path, Packet.SSH_FXP_STAT); - } - - /** - * Retrieve the file attributes of a file. This method - * does NOT follow symbolic links on the server. - * - * @see #stat(String) - * - * @param path See the {@link SFTPv3Client comment} for the class for more details. - * @return a SFTPv3FileAttributes object. - * @throws IOException - */ - public SFTPv3FileAttributes lstat(String path) throws IOException - { - return statBoth(path, Packet.SSH_FXP_LSTAT); - } - - /** - * Read the target of a symbolic link. - * - * @param path See the {@link SFTPv3Client comment} for the class for more details. - * @return The target of the link. - * @throws IOException - */ - public String readLink(String path) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(path, charsetName); - - if (debug != null) - { - debug.println("Sending SSH_FXP_READLINK..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_READLINK, req_id, tw.getBytes()); - - byte[] resp = receiveMessage(34000); - - if (debug != null) - { - debug.println("Got REPLY."); - debug.flush(); - } - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t == Packet.SSH_FXP_NAME) - { - int count = tr.readUINT32(); - - if (count != 1) - throw new IOException("The server sent an invalid SSH_FXP_NAME packet."); - - return tr.readString(charsetName); - } - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - - throw new SFTPException(tr.readString(), errorCode); - } - - private void expectStatusOKMessage(int id) throws IOException - { - byte[] resp = receiveMessage(34000); - - if (debug != null) - { - debug.println("Got REPLY."); - debug.flush(); - } - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != id) - throw new IOException("The server sent an invalid id field."); - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - - if (errorCode == ErrorCodes.SSH_FX_OK) - return; - - throw new SFTPException(tr.readString(), errorCode); - } - - /** - * Modify the attributes of a file. Used for operations such as changing - * the ownership, permissions or access times, as well as for truncating a file. - * - * @param path See the {@link SFTPv3Client comment} for the class for more details. - * @param attr A SFTPv3FileAttributes object. Specifies the modifications to be - * made to the attributes of the file. Empty fields will be ignored. - * @throws IOException - */ - public void setstat(String path, SFTPv3FileAttributes attr) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(path, charsetName); - tw.writeBytes(createAttrs(attr)); - - if (debug != null) - { - debug.println("Sending SSH_FXP_SETSTAT..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_SETSTAT, req_id, tw.getBytes()); - - expectStatusOKMessage(req_id); - } - - /** - * Modify the attributes of a file. Used for operations such as changing - * the ownership, permissions or access times, as well as for truncating a file. - * - * @param handle a SFTPv3FileHandle handle - * @param attr A SFTPv3FileAttributes object. Specifies the modifications to be - * made to the attributes of the file. Empty fields will be ignored. - * @throws IOException - */ - public void fsetstat(SFTPv3FileHandle handle, SFTPv3FileAttributes attr) throws IOException - { - checkHandleValidAndOpen(handle); - - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(handle.fileHandle, 0, handle.fileHandle.length); - tw.writeBytes(createAttrs(attr)); - - if (debug != null) - { - debug.println("Sending SSH_FXP_FSETSTAT..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_FSETSTAT, req_id, tw.getBytes()); - - expectStatusOKMessage(req_id); - } - - /** - * Create a symbolic link on the server. Creates a link "src" that points - * to "target". - * - * @param src See the {@link SFTPv3Client comment} for the class for more details. - * @param target See the {@link SFTPv3Client comment} for the class for more details. - * @throws IOException - */ - public void createSymlink(String src, String target) throws IOException - { - int req_id = generateNextRequestID(); - - /* Either I am too stupid to understand the SFTP draft - * or the OpenSSH guys changed the semantics of src and target. - */ - - TypesWriter tw = new TypesWriter(); - tw.writeString(target, charsetName); - tw.writeString(src, charsetName); - - if (debug != null) - { - debug.println("Sending SSH_FXP_SYMLINK..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_SYMLINK, req_id, tw.getBytes()); - - expectStatusOKMessage(req_id); - } - - /** - * Have the server canonicalize any given path name to an absolute path. - * This is useful for converting path names containing ".." components or - * relative pathnames without a leading slash into absolute paths. - * - * @param path See the {@link SFTPv3Client comment} for the class for more details. - * @return An absolute path. - * @throws IOException - */ - public String canonicalPath(String path) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(path, charsetName); - - if (debug != null) - { - debug.println("Sending SSH_FXP_REALPATH..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_REALPATH, req_id, tw.getBytes()); - - byte[] resp = receiveMessage(34000); - - if (debug != null) - { - debug.println("Got REPLY."); - debug.flush(); - } - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t == Packet.SSH_FXP_NAME) - { - int count = tr.readUINT32(); - - if (count != 1) - throw new IOException("The server sent an invalid SSH_FXP_NAME packet."); - - return tr.readString(charsetName); - } - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - - throw new SFTPException(tr.readString(), errorCode); - } - - private final Vector scanDirectory(byte[] handle) throws IOException - { - Vector files = new Vector(); - - while (true) - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(handle, 0, handle.length); - - if (debug != null) - { - debug.println("Sending SSH_FXP_READDIR..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_READDIR, req_id, tw.getBytes()); - - /* Some servers send here a packet with size > 34000 */ - /* To whom it may concern: please learn to read the specs. */ - - byte[] resp = receiveMessage(65536); - - if (debug != null) - { - debug.println("Got REPLY."); - debug.flush(); - } - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t == Packet.SSH_FXP_NAME) - { - int count = tr.readUINT32(); - - if (debug != null) - debug.println("Parsing " + count + " name entries..."); - - while (count > 0) - { - SFTPv3DirectoryEntry dirEnt = new SFTPv3DirectoryEntry(); - - dirEnt.filename = tr.readString(charsetName); - dirEnt.longEntry = tr.readString(charsetName); - - dirEnt.attributes = readAttrs(tr); - files.addElement(dirEnt); - - if (debug != null) - debug.println("File: '" + dirEnt.filename + "'"); - count--; - } - continue; - } - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - - if (errorCode == ErrorCodes.SSH_FX_EOF) - return files; - - throw new SFTPException(tr.readString(), errorCode); - } - } - - private final byte[] openDirectory(String path) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(path, charsetName); - - if (debug != null) - { - debug.println("Sending SSH_FXP_OPENDIR..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_OPENDIR, req_id, tw.getBytes()); - - byte[] resp = receiveMessage(34000); - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t == Packet.SSH_FXP_HANDLE) - { - if (debug != null) - { - debug.println("Got SSH_FXP_HANDLE."); - debug.flush(); - } - - byte[] handle = tr.readByteString(); - return handle; - } - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - String errorMessage = tr.readString(); - - throw new SFTPException(errorMessage, errorCode); - } - - private final String expandString(byte[] b, int off, int len) - { - StringBuffer sb = new StringBuffer(); - - for (int i = 0; i < len; i++) - { - int c = b[off + i] & 0xff; - - if ((c >= 32) && (c <= 126)) - { - sb.append((char) c); - } - else - { - sb.append("{0x" + Integer.toHexString(c) + "}"); - } - } - - return sb.toString(); - } - - private void init() throws IOException - { - /* Send SSH_FXP_INIT (version 3) */ - - final int client_version = 3; - - if (debug != null) - debug.println("Sending SSH_FXP_INIT (" + client_version + ")..."); - - TypesWriter tw = new TypesWriter(); - tw.writeUINT32(client_version); - sendMessage(Packet.SSH_FXP_INIT, 0, tw.getBytes()); - - /* Receive SSH_FXP_VERSION */ - - if (debug != null) - debug.println("Waiting for SSH_FXP_VERSION..."); - - TypesReader tr = new TypesReader(receiveMessage(34000)); /* Should be enough for any reasonable server */ - - int type = tr.readByte(); - - if (type != Packet.SSH_FXP_VERSION) - { - throw new IOException("The server did not send a SSH_FXP_VERSION packet (got " + type + ")"); - } - - protocol_version = tr.readUINT32(); - - if (debug != null) - debug.println("SSH_FXP_VERSION: protocol_version = " + protocol_version); - - if (protocol_version != 3) - throw new IOException("Server version " + protocol_version + " is currently not supported"); - - /* Read and save extensions (if any) for later use */ - - while (tr.remain() != 0) - { - String name = tr.readString(); - byte[] value = tr.readByteString(); - server_extensions.put(name, value); - - if (debug != null) - debug.println("SSH_FXP_VERSION: extension: " + name + " = '" + expandString(value, 0, value.length) - + "'"); - } - } - - /** - * Returns the negotiated SFTP protocol version between the client and the server. - * - * @return SFTP protocol version, i.e., "3". - * - */ - public int getProtocolVersion() - { - return protocol_version; - } - - /** - * Close this SFTP session. NEVER forget to call this method to free up - * resources - even if you got an exception from one of the other methods. - * Sometimes these other methods may throw an exception, saying that the - * underlying channel is closed (this can happen, e.g., if the other server - * sent a close message.) However, as long as you have not called the - * <code>close()</code> method, you are likely wasting resources. - * - */ - public void close() - { - sess.close(); - } - - /** - * List the contents of a directory. - * - * @param dirName See the {@link SFTPv3Client comment} for the class for more details. - * @return A Vector containing {@link SFTPv3DirectoryEntry} objects. - * @throws IOException - */ - public Vector ls(String dirName) throws IOException - { - byte[] handle = openDirectory(dirName); - Vector result = scanDirectory(handle); - closeHandle(handle); - return result; - } - - /** - * Create a new directory. - * - * @param dirName See the {@link SFTPv3Client comment} for the class for more details. - * @param posixPermissions the permissions for this directory, e.g., "0700" (remember that - * this is octal noation). The server will likely apply a umask. - * - * @throws IOException - */ - public void mkdir(String dirName, int posixPermissions) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(dirName, charsetName); - tw.writeUINT32(AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS); - tw.writeUINT32(posixPermissions); - - sendMessage(Packet.SSH_FXP_MKDIR, req_id, tw.getBytes()); - - expectStatusOKMessage(req_id); - } - - /** - * Remove a file. - * - * @param fileName See the {@link SFTPv3Client comment} for the class for more details. - * @throws IOException - */ - public void rm(String fileName) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(fileName, charsetName); - - sendMessage(Packet.SSH_FXP_REMOVE, req_id, tw.getBytes()); - - expectStatusOKMessage(req_id); - } - - /** - * Remove an empty directory. - * - * @param dirName See the {@link SFTPv3Client comment} for the class for more details. - * @throws IOException - */ - public void rmdir(String dirName) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(dirName, charsetName); - - sendMessage(Packet.SSH_FXP_RMDIR, req_id, tw.getBytes()); - - expectStatusOKMessage(req_id); - } - - /** - * Move a file or directory. - * - * @param oldPath See the {@link SFTPv3Client comment} for the class for more details. - * @param newPath See the {@link SFTPv3Client comment} for the class for more details. - * @throws IOException - */ - public void mv(String oldPath, String newPath) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(oldPath, charsetName); - tw.writeString(newPath, charsetName); - - sendMessage(Packet.SSH_FXP_RENAME, req_id, tw.getBytes()); - - expectStatusOKMessage(req_id); - } - - /** - * Open a file for reading. - * - * @param fileName See the {@link SFTPv3Client comment} for the class for more details. - * @return a SFTPv3FileHandle handle - * @throws IOException - */ - public SFTPv3FileHandle openFileRO(String fileName) throws IOException - { - return openFile(fileName, 0x00000001, null); // SSH_FXF_READ - } - - /** - * Open a file for reading and writing. - * - * @param fileName See the {@link SFTPv3Client comment} for the class for more details. - * @return a SFTPv3FileHandle handle - * @throws IOException - */ - public SFTPv3FileHandle openFileRW(String fileName) throws IOException - { - return openFile(fileName, 0x00000003, null); // SSH_FXF_READ | SSH_FXF_WRITE - } - - // Append is broken (already in the specification, because there is no way to - // send a write operation (what offset to use??)) - // public SFTPv3FileHandle openFileRWAppend(String fileName) throws IOException - // { - // return openFile(fileName, 0x00000007, null); // SSH_FXF_READ | SSH_FXF_WRITE | SSH_FXF_APPEND - // } - - /** - * Create a file and open it for reading and writing. - * Same as {@link #createFile(String, SFTPv3FileAttributes) createFile(fileName, null)}. - * - * @param fileName See the {@link SFTPv3Client comment} for the class for more details. - * @return a SFTPv3FileHandle handle - * @throws IOException - */ - public SFTPv3FileHandle createFile(String fileName) throws IOException - { - return createFile(fileName, null); - } - - /** - * Create a file and open it for reading and writing. - * You can specify the default attributes of the file (the server may or may - * not respect your wishes). - * - * @param fileName See the {@link SFTPv3Client comment} for the class for more details. - * @param attr may be <code>null</code> to use server defaults. Probably only - * the <code>uid</code>, <code>gid</code> and <code>permissions</code> - * (remember the server may apply a umask) entries of the {@link SFTPv3FileHandle} - * structure make sense. You need only to set those fields where you want - * to override the server's defaults. - * @return a SFTPv3FileHandle handle - * @throws IOException - */ - public SFTPv3FileHandle createFile(String fileName, SFTPv3FileAttributes attr) throws IOException - { - return openFile(fileName, 0x00000008 | 0x00000003, attr); // SSH_FXF_CREAT | SSH_FXF_READ | SSH_FXF_WRITE - } - - /** - * Create a file (truncate it if it already exists) and open it for reading and writing. - * Same as {@link #createFileTruncate(String, SFTPv3FileAttributes) createFileTruncate(fileName, null)}. - * - * @param fileName See the {@link SFTPv3Client comment} for the class for more details. - * @return a SFTPv3FileHandle handle - * @throws IOException - */ - public SFTPv3FileHandle createFileTruncate(String fileName) throws IOException - { - return createFileTruncate(fileName, null); - } - - /** - * reate a file (truncate it if it already exists) and open it for reading and writing. - * You can specify the default attributes of the file (the server may or may - * not respect your wishes). - * - * @param fileName See the {@link SFTPv3Client comment} for the class for more details. - * @param attr may be <code>null</code> to use server defaults. Probably only - * the <code>uid</code>, <code>gid</code> and <code>permissions</code> - * (remember the server may apply a umask) entries of the {@link SFTPv3FileHandle} - * structure make sense. You need only to set those fields where you want - * to override the server's defaults. - * @return a SFTPv3FileHandle handle - * @throws IOException - */ - public SFTPv3FileHandle createFileTruncate(String fileName, SFTPv3FileAttributes attr) throws IOException - { - return openFile(fileName, 0x00000018 | 0x00000003, attr); // SSH_FXF_CREAT | SSH_FXF_TRUNC | SSH_FXF_READ | SSH_FXF_WRITE - } - - private byte[] createAttrs(SFTPv3FileAttributes attr) - { - TypesWriter tw = new TypesWriter(); - - int attrFlags = 0; - - if (attr == null) - { - tw.writeUINT32(0); - } - else - { - if (attr.size != null) - attrFlags = attrFlags | AttribFlags.SSH_FILEXFER_ATTR_SIZE; - - if ((attr.uid != null) && (attr.gid != null)) - attrFlags = attrFlags | AttribFlags.SSH_FILEXFER_ATTR_V3_UIDGID; - - if (attr.permissions != null) - attrFlags = attrFlags | AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS; - - if ((attr.atime != null) && (attr.mtime != null)) - attrFlags = attrFlags | AttribFlags.SSH_FILEXFER_ATTR_V3_ACMODTIME; - - tw.writeUINT32(attrFlags); - - if (attr.size != null) - tw.writeUINT64(attr.size.longValue()); - - if ((attr.uid != null) && (attr.gid != null)) - { - tw.writeUINT32(attr.uid.intValue()); - tw.writeUINT32(attr.gid.intValue()); - } - - if (attr.permissions != null) - tw.writeUINT32(attr.permissions.intValue()); - - if ((attr.atime != null) && (attr.mtime != null)) - { - tw.writeUINT32(attr.atime.intValue()); - tw.writeUINT32(attr.mtime.intValue()); - } - } - - return tw.getBytes(); - } - - private SFTPv3FileHandle openFile(String fileName, int flags, SFTPv3FileAttributes attr) throws IOException - { - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(fileName, charsetName); - tw.writeUINT32(flags); - tw.writeBytes(createAttrs(attr)); - - if (debug != null) - { - debug.println("Sending SSH_FXP_OPEN..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_OPEN, req_id, tw.getBytes()); - - byte[] resp = receiveMessage(34000); - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t == Packet.SSH_FXP_HANDLE) - { - if (debug != null) - { - debug.println("Got SSH_FXP_HANDLE."); - debug.flush(); - } - - return new SFTPv3FileHandle(this, tr.readByteString()); - } - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - String errorMessage = tr.readString(); - - throw new SFTPException(errorMessage, errorCode); - } - - /** - * Read bytes from a file. No more than 32768 bytes may be read at once. - * Be aware that the semantics of read() are different than for Java streams. - * <p> - * <ul> - * <li>The server will read as many bytes as it can from the file (up to <code>len</code>), - * and return them.</li> - * <li>If EOF is encountered before reading any data, <code>-1</code> is returned. - * <li>If an error occurs, an exception is thrown</li>. - * <li>For normal disk files, it is guaranteed that the server will return the specified - * number of bytes, or up to end of file. For, e.g., device files this may return - * fewer bytes than requested.</li> - * </ul> - * - * @param handle a SFTPv3FileHandle handle - * @param fileOffset offset (in bytes) in the file - * @param dst the destination byte array - * @param dstoff offset in the destination byte array - * @param len how many bytes to read, 0 < len <= 32768 bytes - * @return the number of bytes that could be read, may be less than requested if - * the end of the file is reached, -1 is returned in case of <code>EOF</code> - * @throws IOException - */ - public int read(SFTPv3FileHandle handle, long fileOffset, byte[] dst, int dstoff, int len) throws IOException - { - checkHandleValidAndOpen(handle); - - if ((len > 32768) || (len <= 0)) - throw new IllegalArgumentException("invalid len argument"); - - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(handle.fileHandle, 0, handle.fileHandle.length); - tw.writeUINT64(fileOffset); - tw.writeUINT32(len); - - if (debug != null) - { - debug.println("Sending SSH_FXP_READ..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_READ, req_id, tw.getBytes()); - - byte[] resp = receiveMessage(34000); - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t == Packet.SSH_FXP_DATA) - { - if (debug != null) - { - debug.println("Got SSH_FXP_DATA..."); - debug.flush(); - } - - int readLen = tr.readUINT32(); - - if ((readLen < 0) || (readLen > len)) - throw new IOException("The server sent an invalid length field."); - - tr.readBytes(dst, dstoff, readLen); - - return readLen; - } - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - - if (errorCode == ErrorCodes.SSH_FX_EOF) - { - if (debug != null) - { - debug.println("Got SSH_FX_EOF."); - debug.flush(); - } - - return -1; - } - - String errorMessage = tr.readString(); - - throw new SFTPException(errorMessage, errorCode); - } - - /** - * Write bytes to a file. If <code>len</code> > 32768, then the write operation will - * be split into multiple writes. - * - * @param handle a SFTPv3FileHandle handle. - * @param fileOffset offset (in bytes) in the file. - * @param src the source byte array. - * @param srcoff offset in the source byte array. - * @param len how many bytes to write. - * @throws IOException - */ - public void write(SFTPv3FileHandle handle, long fileOffset, byte[] src, int srcoff, int len) throws IOException - { - checkHandleValidAndOpen(handle); - - while (len > 0) - { - int writeRequestLen = len; - - if (writeRequestLen > 32768) - writeRequestLen = 32768; - - int req_id = generateNextRequestID(); - - TypesWriter tw = new TypesWriter(); - tw.writeString(handle.fileHandle, 0, handle.fileHandle.length); - tw.writeUINT64(fileOffset); - tw.writeString(src, srcoff, writeRequestLen); - - if (debug != null) - { - debug.println("Sending SSH_FXP_WRITE..."); - debug.flush(); - } - - sendMessage(Packet.SSH_FXP_WRITE, req_id, tw.getBytes()); - - fileOffset += writeRequestLen; - - srcoff += writeRequestLen; - len -= writeRequestLen; - - byte[] resp = receiveMessage(34000); - - TypesReader tr = new TypesReader(resp); - - int t = tr.readByte(); - - int rep_id = tr.readUINT32(); - if (rep_id != req_id) - throw new IOException("The server sent an invalid id field."); - - if (t != Packet.SSH_FXP_STATUS) - throw new IOException("The SFTP server sent an unexpected packet type (" + t + ")"); - - int errorCode = tr.readUINT32(); - - if (errorCode == ErrorCodes.SSH_FX_OK) - continue; - - String errorMessage = tr.readString(); - - throw new SFTPException(errorMessage, errorCode); - } - } - - /** - * Close a file. - * - * @param handle a SFTPv3FileHandle handle - * @throws IOException - */ - public void closeFile(SFTPv3FileHandle handle) throws IOException - { - if (handle == null) - throw new IllegalArgumentException("the handle argument may not be null"); - - try - { - if (handle.isClosed == false) - { - closeHandle(handle.fileHandle); - } - } - finally - { - handle.isClosed = true; - } - } -} diff --git a/src/com/trilead/ssh2/SFTPv3DirectoryEntry.java b/src/com/trilead/ssh2/SFTPv3DirectoryEntry.java deleted file mode 100644 index 669ba87..0000000 --- a/src/com/trilead/ssh2/SFTPv3DirectoryEntry.java +++ /dev/null @@ -1,38 +0,0 @@ - -package com.trilead.ssh2; - -/** - * A <code>SFTPv3DirectoryEntry</code> as returned by {@link SFTPv3Client#ls(String)}. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: SFTPv3DirectoryEntry.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public class SFTPv3DirectoryEntry -{ - /** - * A relative name within the directory, without any path components. - */ - public String filename; - - /** - * An expanded format for the file name, similar to what is returned by - * "ls -l" on Un*x systems. - * <p> - * The format of this field is unspecified by the SFTP v3 protocol. - * It MUST be suitable for use in the output of a directory listing - * command (in fact, the recommended operation for a directory listing - * command is to simply display this data). However, clients SHOULD NOT - * attempt to parse the longname field for file attributes; they SHOULD - * use the attrs field instead. - * <p> - * The recommended format for the longname field is as follows:<br> - * <code>-rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer</code> - */ - public String longEntry; - - /** - * The attributes of this entry. - */ - public SFTPv3FileAttributes attributes; -} diff --git a/src/com/trilead/ssh2/SFTPv3FileAttributes.java b/src/com/trilead/ssh2/SFTPv3FileAttributes.java deleted file mode 100644 index 7b1d321..0000000 --- a/src/com/trilead/ssh2/SFTPv3FileAttributes.java +++ /dev/null @@ -1,145 +0,0 @@ - -package com.trilead.ssh2; - -/** - * A <code>SFTPv3FileAttributes</code> object represents detail information - * about a file on the server. Not all fields may/must be present. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: SFTPv3FileAttributes.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ - -public class SFTPv3FileAttributes -{ - /** - * The SIZE attribute. <code>NULL</code> if not present. - */ - public Long size = null; - - /** - * The UID attribute. <code>NULL</code> if not present. - */ - public Integer uid = null; - - /** - * The GID attribute. <code>NULL</code> if not present. - */ - public Integer gid = null; - - /** - * The POSIX permissions. <code>NULL</code> if not present. - * <p> - * Here is a list: - * <p> - * <pre>Note: these numbers are all OCTAL. - * - * S_IFMT 0170000 bitmask for the file type bitfields - * S_IFSOCK 0140000 socket - * S_IFLNK 0120000 symbolic link - * S_IFREG 0100000 regular file - * S_IFBLK 0060000 block device - * S_IFDIR 0040000 directory - * S_IFCHR 0020000 character device - * S_IFIFO 0010000 fifo - * S_ISUID 0004000 set UID bit - * S_ISGID 0002000 set GID bit - * S_ISVTX 0001000 sticky bit - * - * S_IRWXU 00700 mask for file owner permissions - * S_IRUSR 00400 owner has read permission - * S_IWUSR 00200 owner has write permission - * S_IXUSR 00100 owner has execute permission - * S_IRWXG 00070 mask for group permissions - * S_IRGRP 00040 group has read permission - * S_IWGRP 00020 group has write permission - * S_IXGRP 00010 group has execute permission - * S_IRWXO 00007 mask for permissions for others (not in group) - * S_IROTH 00004 others have read permission - * S_IWOTH 00002 others have write permisson - * S_IXOTH 00001 others have execute permission - * </pre> - */ - public Integer permissions = null; - - /** - * The ATIME attribute. Represented as seconds from Jan 1, 1970 in UTC. - * <code>NULL</code> if not present. - */ - public Long atime = null; - - /** - * The MTIME attribute. Represented as seconds from Jan 1, 1970 in UTC. - * <code>NULL</code> if not present. - */ - public Long mtime = null; - - /** - * Checks if this entry is a directory. - * - * @return Returns true if permissions are available and they indicate - * that this entry represents a directory. - */ - public boolean isDirectory() - { - if (permissions == null) - return false; - - return ((permissions.intValue() & 0040000) != 0); - } - - /** - * Checks if this entry is a regular file. - * - * @return Returns true if permissions are available and they indicate - * that this entry represents a regular file. - */ - public boolean isRegularFile() - { - if (permissions == null) - return false; - - return ((permissions.intValue() & 0100000) != 0); - } - - /** - * Checks if this entry is a a symlink. - * - * @return Returns true if permissions are available and they indicate - * that this entry represents a symlink. - */ - public boolean isSymlink() - { - if (permissions == null) - return false; - - return ((permissions.intValue() & 0120000) != 0); - } - - /** - * Turn the POSIX permissions into a 7 digit octal representation. - * Note: the returned value is first masked with <code>0177777</code>. - * - * @return <code>NULL</code> if permissions are not available. - */ - public String getOctalPermissions() - { - if (permissions == null) - return null; - - String res = Integer.toString(permissions.intValue() & 0177777, 8); - - StringBuffer sb = new StringBuffer(); - - int leadingZeros = 7 - res.length(); - - while (leadingZeros > 0) - { - sb.append('0'); - leadingZeros--; - } - - sb.append(res); - - return sb.toString(); - } -} diff --git a/src/com/trilead/ssh2/SFTPv3FileHandle.java b/src/com/trilead/ssh2/SFTPv3FileHandle.java deleted file mode 100644 index 9b3dbb6..0000000 --- a/src/com/trilead/ssh2/SFTPv3FileHandle.java +++ /dev/null @@ -1,45 +0,0 @@ - -package com.trilead.ssh2; - -/** - * A <code>SFTPv3FileHandle</code>. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: SFTPv3FileHandle.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public class SFTPv3FileHandle -{ - final SFTPv3Client client; - final byte[] fileHandle; - boolean isClosed = false; - - /* The constructor is NOT public */ - - SFTPv3FileHandle(SFTPv3Client client, byte[] h) - { - this.client = client; - this.fileHandle = h; - } - - /** - * Get the SFTPv3Client instance which created this handle. - * - * @return A SFTPv3Client instance. - */ - public SFTPv3Client getClient() - { - return client; - } - - /** - * Check if this handle was closed with the {@link SFTPv3Client#closeFile(SFTPv3FileHandle)} method - * of the <code>SFTPv3Client</code> instance which created the handle. - * - * @return if the handle is closed. - */ - public boolean isClosed() - { - return isClosed; - } -} diff --git a/src/com/trilead/ssh2/ServerHostKeyVerifier.java b/src/com/trilead/ssh2/ServerHostKeyVerifier.java deleted file mode 100644 index ac65955..0000000 --- a/src/com/trilead/ssh2/ServerHostKeyVerifier.java +++ /dev/null @@ -1,31 +0,0 @@ - -package com.trilead.ssh2; - -/** - * A callback interface used to implement a client specific method of checking - * server host keys. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ServerHostKeyVerifier.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public interface ServerHostKeyVerifier -{ - /** - * The actual verifier method, it will be called by the key exchange code - * on EVERY key exchange - this can happen several times during the lifetime - * of a connection. - * <p> - * Note: SSH-2 servers are allowed to change their hostkey at ANY time. - * - * @param hostname the hostname used to create the {@link Connection} object - * @param port the remote TCP port - * @param serverHostKeyAlgorithm the public key algorithm (<code>ssh-rsa</code> or <code>ssh-dss</code>) - * @param serverHostKey the server's public key blob - * @return if the client wants to accept the server's host key - if not, the - * connection will be closed. - * @throws Exception Will be wrapped with an IOException, extended version of returning false =) - */ - public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) - throws Exception; -} diff --git a/src/com/trilead/ssh2/Session.java b/src/com/trilead/ssh2/Session.java deleted file mode 100644 index bf3c7e0..0000000 --- a/src/com/trilead/ssh2/Session.java +++ /dev/null @@ -1,530 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SecureRandom; - -import com.trilead.ssh2.channel.Channel; -import com.trilead.ssh2.channel.ChannelManager; -import com.trilead.ssh2.channel.X11ServerData; - - -/** - * A <code>Session</code> is a remote execution of a program. "Program" means - * in this context either a shell, an application or a system command. The - * program may or may not have a tty. Only one single program can be started on - * a session. However, multiple sessions can be active simultaneously. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Session.java,v 1.2 2008/03/03 07:01:36 cplattne Exp $ - */ -public class Session -{ - ChannelManager cm; - Channel cn; - - boolean flag_pty_requested = false; - boolean flag_x11_requested = false; - boolean flag_execution_started = false; - boolean flag_closed = false; - - String x11FakeCookie = null; - - final SecureRandom rnd; - - Session(ChannelManager cm, SecureRandom rnd) throws IOException - { - this.cm = cm; - this.cn = cm.openSessionChannel(); - this.rnd = rnd; - } - - /** - * Basically just a wrapper for lazy people - identical to calling - * <code>requestPTY("dumb", 0, 0, 0, 0, null)</code>. - * - * @throws IOException - */ - public void requestDumbPTY() throws IOException - { - requestPTY("dumb", 0, 0, 0, 0, null); - } - - /** - * Basically just another wrapper for lazy people - identical to calling - * <code>requestPTY(term, 0, 0, 0, 0, null)</code>. - * - * @throws IOException - */ - public void requestPTY(String term) throws IOException - { - requestPTY(term, 0, 0, 0, 0, null); - } - - /** - * Allocate a pseudo-terminal for this session. - * <p> - * This method may only be called before a program or shell is started in - * this session. - * <p> - * Different aspects can be specified: - * <p> - * <ul> - * <li>The TERM environment variable value (e.g., vt100)</li> - * <li>The terminal's dimensions.</li> - * <li>The encoded terminal modes.</li> - * </ul> - * Zero dimension parameters are ignored. The character/row dimensions - * override the pixel dimensions (when nonzero). Pixel dimensions refer to - * the drawable area of the window. The dimension parameters are only - * informational. The encoding of terminal modes (parameter - * <code>terminal_modes</code>) is described in RFC4254. - * - * @param term - * The TERM environment variable value (e.g., vt100) - * @param term_width_characters - * terminal width, characters (e.g., 80) - * @param term_height_characters - * terminal height, rows (e.g., 24) - * @param term_width_pixels - * terminal width, pixels (e.g., 640) - * @param term_height_pixels - * terminal height, pixels (e.g., 480) - * @param terminal_modes - * encoded terminal modes (may be <code>null</code>) - * @throws IOException - */ - public void requestPTY(String term, int term_width_characters, int term_height_characters, int term_width_pixels, - int term_height_pixels, byte[] terminal_modes) throws IOException - { - if (term == null) - throw new IllegalArgumentException("TERM cannot be null."); - - if ((terminal_modes != null) && (terminal_modes.length > 0)) - { - if (terminal_modes[terminal_modes.length - 1] != 0) - throw new IOException("Illegal terminal modes description, does not end in zero byte"); - } - else - terminal_modes = new byte[] { 0 }; - - synchronized (this) - { - /* The following is just a nicer error, we would catch it anyway later in the channel code */ - if (flag_closed) - throw new IOException("This session is closed."); - - if (flag_pty_requested) - throw new IOException("A PTY was already requested."); - - if (flag_execution_started) - throw new IOException( - "Cannot request PTY at this stage anymore, a remote execution has already started."); - - flag_pty_requested = true; - } - - cm.requestPTY(cn, term, term_width_characters, term_height_characters, term_width_pixels, term_height_pixels, - terminal_modes); - } - - /** - * Inform other side of connection that our PTY has resized. - * <p> - * Zero dimension parameters are ignored. The character/row dimensions - * override the pixel dimensions (when nonzero). Pixel dimensions refer to - * the drawable area of the window. The dimension parameters are only - * informational. - * - * @param term_width_characters - * terminal width, characters (e.g., 80) - * @param term_height_characters - * terminal height, rows (e.g., 24) - * @param term_width_pixels - * terminal width, pixels (e.g., 640) - * @param term_height_pixels - * terminal height, pixels (e.g., 480) - * @throws IOException - */ - public void resizePTY(int term_width_characters, int term_height_characters, int term_width_pixels, - int term_height_pixels) throws IOException { - synchronized (this) - { - /* The following is just a nicer error, we would catch it anyway later in the channel code */ - if (flag_closed) - throw new IOException("This session is closed."); - } - - cm.resizePTY(cn, term_width_characters, term_height_characters, term_width_pixels, term_height_pixels); - } - - /** - * Request X11 forwarding for the current session. - * <p> - * You have to supply the name and port of your X-server. - * <p> - * This method may only be called before a program or shell is started in - * this session. - * - * @param hostname the hostname of the real (target) X11 server (e.g., 127.0.0.1) - * @param port the port of the real (target) X11 server (e.g., 6010) - * @param cookie if non-null, then present this cookie to the real X11 server - * @param singleConnection if true, then the server is instructed to only forward one single - * connection, no more connections shall be forwarded after first, or after the session - * channel has been closed - * @throws IOException - */ - public void requestX11Forwarding(String hostname, int port, byte[] cookie, boolean singleConnection) - throws IOException - { - if (hostname == null) - throw new IllegalArgumentException("hostname argument may not be null"); - - synchronized (this) - { - /* The following is just a nicer error, we would catch it anyway later in the channel code */ - if (flag_closed) - throw new IOException("This session is closed."); - - if (flag_x11_requested) - throw new IOException("X11 forwarding was already requested."); - - if (flag_execution_started) - throw new IOException( - "Cannot request X11 forwarding at this stage anymore, a remote execution has already started."); - - flag_x11_requested = true; - } - - /* X11ServerData - used to store data about the target X11 server */ - - X11ServerData x11data = new X11ServerData(); - - x11data.hostname = hostname; - x11data.port = port; - x11data.x11_magic_cookie = cookie; /* if non-null, then present this cookie to the real X11 server */ - - /* Generate fake cookie - this one is used between remote clients and our proxy */ - - byte[] fakeCookie = new byte[16]; - String hexEncodedFakeCookie; - - /* Make sure that this fake cookie is unique for this connection */ - - while (true) - { - rnd.nextBytes(fakeCookie); - - /* Generate also hex representation of fake cookie */ - - StringBuffer tmp = new StringBuffer(32); - for (int i = 0; i < fakeCookie.length; i++) - { - String digit2 = Integer.toHexString(fakeCookie[i] & 0xff); - tmp.append((digit2.length() == 2) ? digit2 : "0" + digit2); - } - hexEncodedFakeCookie = tmp.toString(); - - /* Well, yes, chances are low, but we want to be on the safe side */ - - if (cm.checkX11Cookie(hexEncodedFakeCookie) == null) - break; - } - - /* Ask for X11 forwarding */ - - cm.requestX11(cn, singleConnection, "MIT-MAGIC-COOKIE-1", hexEncodedFakeCookie, 0); - - /* OK, that went fine, get ready to accept X11 connections... */ - /* ... but only if the user has not called close() in the meantime =) */ - - synchronized (this) - { - if (flag_closed == false) - { - this.x11FakeCookie = hexEncodedFakeCookie; - cm.registerX11Cookie(hexEncodedFakeCookie, x11data); - } - } - - /* Now it is safe to start remote X11 programs */ - } - - /** - * Execute a command on the remote machine. - * - * @param cmd - * The command to execute on the remote host. - * @throws IOException - */ - public void execCommand(String cmd) throws IOException - { - if (cmd == null) - throw new IllegalArgumentException("cmd argument may not be null"); - - synchronized (this) - { - /* The following is just a nicer error, we would catch it anyway later in the channel code */ - if (flag_closed) - throw new IOException("This session is closed."); - - if (flag_execution_started) - throw new IOException("A remote execution has already started."); - - flag_execution_started = true; - } - - cm.requestExecCommand(cn, cmd); - } - - /** - * Start a shell on the remote machine. - * - * @throws IOException - */ - public void startShell() throws IOException - { - synchronized (this) - { - /* The following is just a nicer error, we would catch it anyway later in the channel code */ - if (flag_closed) - throw new IOException("This session is closed."); - - if (flag_execution_started) - throw new IOException("A remote execution has already started."); - - flag_execution_started = true; - } - - cm.requestShell(cn); - } - - /** - * Start a subsystem on the remote machine. - * Unless you know what you are doing, you will never need this. - * - * @param name the name of the subsystem. - * @throws IOException - */ - public void startSubSystem(String name) throws IOException - { - if (name == null) - throw new IllegalArgumentException("name argument may not be null"); - - synchronized (this) - { - /* The following is just a nicer error, we would catch it anyway later in the channel code */ - if (flag_closed) - throw new IOException("This session is closed."); - - if (flag_execution_started) - throw new IOException("A remote execution has already started."); - - flag_execution_started = true; - } - - cm.requestSubSystem(cn, name); - } - - /** - * This method can be used to perform end-to-end session (i.e., SSH channel) - * testing. It sends a 'ping' message to the server and waits for the 'pong' - * from the server. - * <p> - * Implementation details: this method sends a SSH_MSG_CHANNEL_REQUEST request - * ('trilead-ping') to the server and waits for the SSH_MSG_CHANNEL_FAILURE reply - * packet. - * - * @throws IOException in case of any problem or when the session is closed - */ - public void ping() throws IOException - { - synchronized (this) - { - /* - * The following is just a nicer error, we would catch it anyway - * later in the channel code - */ - if (flag_closed) - throw new IOException("This session is closed."); - } - - cm.requestChannelTrileadPing(cn); - } - - /** - * Request authentication agent forwarding. - * @param agent object that implements the callbacks - * - * @throws IOException in case of any problem or when the session is closed - */ - public synchronized boolean requestAuthAgentForwarding(AuthAgentCallback agent) throws IOException - { - synchronized (this) - { - /* - * The following is just a nicer error, we would catch it anyway - * later in the channel code - */ - if (flag_closed) - throw new IOException("This session is closed."); - } - - return cm.requestChannelAgentForwarding(cn, agent); - } - - public InputStream getStdout() - { - return cn.getStdoutStream(); - } - - public InputStream getStderr() - { - return cn.getStderrStream(); - } - - public OutputStream getStdin() - { - return cn.getStdinStream(); - } - - /** - * This method blocks until there is more data available on either the - * stdout or stderr InputStream of this <code>Session</code>. Very useful - * if you do not want to use two parallel threads for reading from the two - * InputStreams. One can also specify a timeout. NOTE: do NOT call this - * method if you use concurrent threads that operate on either of the two - * InputStreams of this <code>Session</code> (otherwise this method may - * block, even though more data is available). - * - * @param timeout - * The (non-negative) timeout in <code>ms</code>. <code>0</code> means no - * timeout, the call may block forever. - * @return - * <ul> - * <li><code>0</code> if no more data will arrive.</li> - * <li><code>1</code> if more data is available.</li> - * <li><code>-1</code> if a timeout occurred.</li> - * </ul> - * - * @throws IOException - * @deprecated This method has been replaced with a much more powerful wait-for-condition - * interface and therefore acts only as a wrapper. - * - */ - public int waitUntilDataAvailable(long timeout) throws IOException - { - if (timeout < 0) - throw new IllegalArgumentException("timeout must not be negative!"); - - int conditions = cm.waitForCondition(cn, timeout, ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA - | ChannelCondition.EOF); - - if ((conditions & ChannelCondition.TIMEOUT) != 0) - return -1; - - if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) != 0) - return 1; - - /* Here we do not need to check separately for CLOSED, since CLOSED implies EOF */ - - if ((conditions & ChannelCondition.EOF) != 0) - return 0; - - throw new IllegalStateException("Unexpected condition result (" + conditions + ")"); - } - - /** - * This method blocks until certain conditions hold true on the underlying SSH-2 channel. - * <p> - * This method returns as soon as one of the following happens: - * <ul> - * <li>at least of the specified conditions (see {@link ChannelCondition}) holds true</li> - * <li>timeout > 0 and a timeout occured (TIMEOUT will be set in result conditions)</a> - * <li>the underlying channel was closed (CLOSED will be set in result conditions)</a> - * </ul> - * <p> - * In any case, the result value contains ALL current conditions, which may be more - * than the specified condition set (i.e., never use the "==" operator to test for conditions - * in the bitmask, see also comments in {@link ChannelCondition}). - * <p> - * Note: do NOT call this method if you want to wait for STDOUT_DATA or STDERR_DATA and - * there are concurrent threads (e.g., StreamGobblers) that operate on either of the two - * InputStreams of this <code>Session</code> (otherwise this method may - * block, even though more data is available in the StreamGobblers). - * - * @param condition_set a bitmask based on {@link ChannelCondition} values - * @param timeout non-negative timeout in ms, <code>0</code> means no timeout - * @return all bitmask specifying all current conditions that are true - */ - - public int waitForCondition(int condition_set, long timeout) - { - if (timeout < 0) - throw new IllegalArgumentException("timeout must be non-negative!"); - - return cm.waitForCondition(cn, timeout, condition_set); - } - - /** - * Get the exit code/status from the remote command - if available. Be - * careful - not all server implementations return this value. It is - * generally a good idea to call this method only when all data from the - * remote side has been consumed (see also the <code<WaitForCondition</code> method). - * - * @return An <code>Integer</code> holding the exit code, or - * <code>null</code> if no exit code is (yet) available. - */ - public Integer getExitStatus() - { - return cn.getExitStatus(); - } - - /** - * Get the name of the signal by which the process on the remote side was - * stopped - if available and applicable. Be careful - not all server - * implementations return this value. - * - * @return An <code>String</code> holding the name of the signal, or - * <code>null</code> if the process exited normally or is still - * running (or if the server forgot to send this information). - */ - public String getExitSignal() - { - return cn.getExitSignal(); - } - - /** - * Close this session. NEVER forget to call this method to free up resources - - * even if you got an exception from one of the other methods (or when - * getting an Exception on the Input- or OutputStreams). Sometimes these other - * methods may throw an exception, saying that the underlying channel is - * closed (this can happen, e.g., if the other server sent a close message.) - * However, as long as you have not called the <code>close()</code> - * method, you may be wasting (local) resources. - * - */ - public void close() - { - synchronized (this) - { - if (flag_closed) - return; - - flag_closed = true; - - if (x11FakeCookie != null) - cm.unRegisterX11Cookie(x11FakeCookie, true); - - try - { - cm.closeChannel(cn, "Closed due to user request", true); - } - catch (IOException ignored) - { - } - } - } -} diff --git a/src/com/trilead/ssh2/StreamGobbler.java b/src/com/trilead/ssh2/StreamGobbler.java deleted file mode 100644 index e93c388..0000000 --- a/src/com/trilead/ssh2/StreamGobbler.java +++ /dev/null @@ -1,229 +0,0 @@ - -package com.trilead.ssh2; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A <code>StreamGobbler</code> is an InputStream that uses an internal worker - * thread to constantly consume input from another InputStream. It uses a buffer - * to store the consumed data. The buffer size is automatically adjusted, if needed. - * <p> - * This class is sometimes very convenient - if you wrap a session's STDOUT and STDERR - * InputStreams with instances of this class, then you don't have to bother about - * the shared window of STDOUT and STDERR in the low level SSH-2 protocol, - * since all arriving data will be immediatelly consumed by the worker threads. - * Also, as a side effect, the streams will be buffered (e.g., single byte - * read() operations are faster). - * <p> - * Other SSH for Java libraries include this functionality by default in - * their STDOUT and STDERR InputStream implementations, however, please be aware - * that this approach has also a downside: - * <p> - * If you do not call the StreamGobbler's <code>read()</code> method often enough - * and the peer is constantly sending huge amounts of data, then you will sooner or later - * encounter a low memory situation due to the aggregated data (well, it also depends on the Java heap size). - * Joe Average will like this class anyway - a paranoid programmer would never use such an approach. - * <p> - * The term "StreamGobbler" was taken from an article called "When Runtime.exec() won't", - * see http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: StreamGobbler.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public class StreamGobbler extends InputStream -{ - class GobblerThread extends Thread - { - public void run() - { - byte[] buff = new byte[8192]; - - while (true) - { - try - { - int avail = is.read(buff); - - synchronized (synchronizer) - { - if (avail <= 0) - { - isEOF = true; - synchronizer.notifyAll(); - break; - } - - int space_available = buffer.length - write_pos; - - if (space_available < avail) - { - /* compact/resize buffer */ - - int unread_size = write_pos - read_pos; - int need_space = unread_size + avail; - - byte[] new_buffer = buffer; - - if (need_space > buffer.length) - { - int inc = need_space / 3; - inc = (inc < 256) ? 256 : inc; - inc = (inc > 8192) ? 8192 : inc; - new_buffer = new byte[need_space + inc]; - } - - if (unread_size > 0) - System.arraycopy(buffer, read_pos, new_buffer, 0, unread_size); - - buffer = new_buffer; - - read_pos = 0; - write_pos = unread_size; - } - - System.arraycopy(buff, 0, buffer, write_pos, avail); - write_pos += avail; - - synchronizer.notifyAll(); - } - } - catch (IOException e) - { - synchronized (synchronizer) - { - exception = e; - synchronizer.notifyAll(); - break; - } - } - } - } - } - - private InputStream is; - private GobblerThread t; - - private Object synchronizer = new Object(); - - private boolean isEOF = false; - private boolean isClosed = false; - private IOException exception = null; - - private byte[] buffer = new byte[2048]; - private int read_pos = 0; - private int write_pos = 0; - - public StreamGobbler(InputStream is) - { - this.is = is; - t = new GobblerThread(); - t.setDaemon(true); - t.start(); - } - - public int read() throws IOException - { - synchronized (synchronizer) - { - if (isClosed) - throw new IOException("This StreamGobbler is closed."); - - while (read_pos == write_pos) - { - if (exception != null) - throw exception; - - if (isEOF) - return -1; - - try - { - synchronizer.wait(); - } - catch (InterruptedException e) - { - } - } - - int b = buffer[read_pos++] & 0xff; - - return b; - } - } - - public int available() throws IOException - { - synchronized (synchronizer) - { - if (isClosed) - throw new IOException("This StreamGobbler is closed."); - - return write_pos - read_pos; - } - } - - public int read(byte[] b) throws IOException - { - return read(b, 0, b.length); - } - - public void close() throws IOException - { - synchronized (synchronizer) - { - if (isClosed) - return; - isClosed = true; - isEOF = true; - synchronizer.notifyAll(); - is.close(); - } - } - - public int read(byte[] b, int off, int len) throws IOException - { - if (b == null) - throw new NullPointerException(); - - if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) - throw new IndexOutOfBoundsException(); - - if (len == 0) - return 0; - - synchronized (synchronizer) - { - if (isClosed) - throw new IOException("This StreamGobbler is closed."); - - while (read_pos == write_pos) - { - if (exception != null) - throw exception; - - if (isEOF) - return -1; - - try - { - synchronizer.wait(); - } - catch (InterruptedException e) - { - } - } - - int avail = write_pos - read_pos; - - avail = (avail > len) ? len : avail; - - System.arraycopy(buffer, read_pos, b, off, avail); - - read_pos += avail; - - return avail; - } - } -} diff --git a/src/com/trilead/ssh2/auth/AuthenticationManager.java b/src/com/trilead/ssh2/auth/AuthenticationManager.java deleted file mode 100644 index e551495..0000000 --- a/src/com/trilead/ssh2/auth/AuthenticationManager.java +++ /dev/null @@ -1,466 +0,0 @@ - -package com.trilead.ssh2.auth; - -import java.io.IOException; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.SecureRandom; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.util.Vector; - -import com.trilead.ssh2.InteractiveCallback; -import com.trilead.ssh2.crypto.PEMDecoder; -import com.trilead.ssh2.packets.PacketServiceAccept; -import com.trilead.ssh2.packets.PacketServiceRequest; -import com.trilead.ssh2.packets.PacketUserauthBanner; -import com.trilead.ssh2.packets.PacketUserauthFailure; -import com.trilead.ssh2.packets.PacketUserauthInfoRequest; -import com.trilead.ssh2.packets.PacketUserauthInfoResponse; -import com.trilead.ssh2.packets.PacketUserauthRequestInteractive; -import com.trilead.ssh2.packets.PacketUserauthRequestNone; -import com.trilead.ssh2.packets.PacketUserauthRequestPassword; -import com.trilead.ssh2.packets.PacketUserauthRequestPublicKey; -import com.trilead.ssh2.packets.Packets; -import com.trilead.ssh2.packets.TypesWriter; -import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.ECDSASHA2Verify; -import com.trilead.ssh2.signature.RSASHA1Verify; -import com.trilead.ssh2.transport.MessageHandler; -import com.trilead.ssh2.transport.TransportManager; - - -/** - * AuthenticationManager. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: AuthenticationManager.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public class AuthenticationManager implements MessageHandler -{ - TransportManager tm; - - Vector packets = new Vector(); - boolean connectionClosed = false; - - String banner; - - String[] remainingMethods = new String[0]; - boolean isPartialSuccess = false; - - boolean authenticated = false; - boolean initDone = false; - - public AuthenticationManager(TransportManager tm) - { - this.tm = tm; - } - - boolean methodPossible(String methName) - { - if (remainingMethods == null) - return false; - - for (int i = 0; i < remainingMethods.length; i++) - { - if (remainingMethods[i].compareTo(methName) == 0) - return true; - } - return false; - } - - byte[] deQueue() throws IOException - { - synchronized (packets) - { - while (packets.size() == 0) - { - if (connectionClosed) - throw (IOException) new IOException("The connection is closed.").initCause(tm - .getReasonClosedCause()); - - try - { - packets.wait(); - } - catch (InterruptedException ign) - { - } - } - /* This sequence works with J2ME */ - byte[] res = (byte[]) packets.firstElement(); - packets.removeElementAt(0); - return res; - } - } - - byte[] getNextMessage() throws IOException - { - while (true) - { - byte[] msg = deQueue(); - - if (msg[0] != Packets.SSH_MSG_USERAUTH_BANNER) - return msg; - - PacketUserauthBanner sb = new PacketUserauthBanner(msg, 0, msg.length); - - banner = sb.getBanner(); - } - } - - public String[] getRemainingMethods(String user) throws IOException - { - initialize(user); - return remainingMethods; - } - - public boolean getPartialSuccess() - { - return isPartialSuccess; - } - - private boolean initialize(String user) throws IOException - { - if (initDone == false) - { - tm.registerMessageHandler(this, 0, 255); - - PacketServiceRequest sr = new PacketServiceRequest("ssh-userauth"); - tm.sendMessage(sr.getPayload()); - - PacketUserauthRequestNone urn = new PacketUserauthRequestNone("ssh-connection", user); - tm.sendMessage(urn.getPayload()); - - byte[] msg = getNextMessage(); - new PacketServiceAccept(msg, 0, msg.length); - msg = getNextMessage(); - - initDone = true; - - if (msg[0] == Packets.SSH_MSG_USERAUTH_SUCCESS) - { - authenticated = true; - tm.removeMessageHandler(this, 0, 255); - return true; - } - - if (msg[0] == Packets.SSH_MSG_USERAUTH_FAILURE) - { - PacketUserauthFailure puf = new PacketUserauthFailure(msg, 0, msg.length); - - remainingMethods = puf.getAuthThatCanContinue(); - isPartialSuccess = puf.isPartialSuccess(); - return false; - } - - throw new IOException("Unexpected SSH message (type " + msg[0] + ")"); - } - return authenticated; - } - - public boolean authenticatePublicKey(String user, char[] PEMPrivateKey, String password, SecureRandom rnd) - throws IOException - { - KeyPair pair = PEMDecoder.decode(PEMPrivateKey, password); - - return authenticatePublicKey(user, pair, rnd); - } - - public boolean authenticatePublicKey(String user, KeyPair pair, SecureRandom rnd) - throws IOException - { - PrivateKey key = pair.getPrivate(); - - try - { - initialize(user); - - if (methodPossible("publickey") == false) - throw new IOException("Authentication method publickey not supported by the server at this stage."); - - if (key instanceof DSAPrivateKey) - { - DSAPrivateKey pk = (DSAPrivateKey) key; - - byte[] pk_enc = DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pair.getPublic()); - - TypesWriter tw = new TypesWriter(); - - byte[] H = tm.getSessionIdentifier(); - - tw.writeString(H, 0, H.length); - tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); - tw.writeString(user); - tw.writeString("ssh-connection"); - tw.writeString("publickey"); - tw.writeBoolean(true); - tw.writeString("ssh-dss"); - tw.writeString(pk_enc, 0, pk_enc.length); - - byte[] msg = tw.getBytes(); - - byte[] ds = DSASHA1Verify.generateSignature(msg, pk, rnd); - - byte[] ds_enc = DSASHA1Verify.encodeSSHDSASignature(ds); - - PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user, - "ssh-dss", pk_enc, ds_enc); - tm.sendMessage(ua.getPayload()); - } - else if (key instanceof RSAPrivateKey) - { - RSAPrivateKey pk = (RSAPrivateKey) key; - - byte[] pk_enc = RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pair.getPublic()); - - TypesWriter tw = new TypesWriter(); - { - byte[] H = tm.getSessionIdentifier(); - - tw.writeString(H, 0, H.length); - tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); - tw.writeString(user); - tw.writeString("ssh-connection"); - tw.writeString("publickey"); - tw.writeBoolean(true); - tw.writeString("ssh-rsa"); - tw.writeString(pk_enc, 0, pk_enc.length); - } - - byte[] msg = tw.getBytes(); - - byte[] ds = RSASHA1Verify.generateSignature(msg, pk); - - byte[] rsa_sig_enc = RSASHA1Verify.encodeSSHRSASignature(ds); - - PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user, - "ssh-rsa", pk_enc, rsa_sig_enc); - - tm.sendMessage(ua.getPayload()); - } - else if (key instanceof ECPrivateKey) - { - ECPrivateKey pk = (ECPrivateKey) key; - final String algo = ECDSASHA2Verify.ECDSA_SHA2_PREFIX - + ECDSASHA2Verify.getCurveName(pk.getParams()); - - byte[] pk_enc = ECDSASHA2Verify.encodeSSHECDSAPublicKey((ECPublicKey) pair.getPublic()); - - TypesWriter tw = new TypesWriter(); - { - byte[] H = tm.getSessionIdentifier(); - - tw.writeString(H, 0, H.length); - tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); - tw.writeString(user); - tw.writeString("ssh-connection"); - tw.writeString("publickey"); - tw.writeBoolean(true); - tw.writeString(algo); - tw.writeString(pk_enc, 0, pk_enc.length); - } - - byte[] msg = tw.getBytes(); - - byte[] ds = ECDSASHA2Verify.generateSignature(msg, pk); - - byte[] ec_sig_enc = ECDSASHA2Verify.encodeSSHECDSASignature(ds, pk.getParams()); - - PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey("ssh-connection", user, - algo, pk_enc, ec_sig_enc); - - tm.sendMessage(ua.getPayload()); - } - else - { - throw new IOException("Unknown private key type returned by the PEM decoder."); - } - - byte[] ar = getNextMessage(); - if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS) - { - authenticated = true; - tm.removeMessageHandler(this, 0, 255); - return true; - } - - if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE) - { - PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length); - - remainingMethods = puf.getAuthThatCanContinue(); - isPartialSuccess = puf.isPartialSuccess(); - - return false; - } - - throw new IOException("Unexpected SSH message (type " + ar[0] + ")"); - - } - catch (IOException e) - { -e.printStackTrace(); - tm.close(e, false); - throw (IOException) new IOException("Publickey authentication failed.").initCause(e); - } - } - - public boolean authenticateNone(String user) throws IOException - { - try - { - initialize(user); - return authenticated; - } - catch (IOException e) - { - tm.close(e, false); - throw (IOException) new IOException("None authentication failed.").initCause(e); - } - } - - public boolean authenticatePassword(String user, String pass) throws IOException - { - try - { - initialize(user); - - if (methodPossible("password") == false) - throw new IOException("Authentication method password not supported by the server at this stage."); - - PacketUserauthRequestPassword ua = new PacketUserauthRequestPassword("ssh-connection", user, pass); - tm.sendMessage(ua.getPayload()); - - byte[] ar = getNextMessage(); - - if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS) - { - authenticated = true; - tm.removeMessageHandler(this, 0, 255); - return true; - } - - if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE) - { - PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length); - - remainingMethods = puf.getAuthThatCanContinue(); - isPartialSuccess = puf.isPartialSuccess(); - - return false; - } - - throw new IOException("Unexpected SSH message (type " + ar[0] + ")"); - - } - catch (IOException e) - { - tm.close(e, false); - throw (IOException) new IOException("Password authentication failed.").initCause(e); - } - } - - public boolean authenticateInteractive(String user, String[] submethods, InteractiveCallback cb) throws IOException - { - try - { - initialize(user); - - if (methodPossible("keyboard-interactive") == false) - throw new IOException( - "Authentication method keyboard-interactive not supported by the server at this stage."); - - if (submethods == null) - submethods = new String[0]; - - PacketUserauthRequestInteractive ua = new PacketUserauthRequestInteractive("ssh-connection", user, - submethods); - - tm.sendMessage(ua.getPayload()); - - while (true) - { - byte[] ar = getNextMessage(); - - if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS) - { - authenticated = true; - tm.removeMessageHandler(this, 0, 255); - return true; - } - - if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE) - { - PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length); - - remainingMethods = puf.getAuthThatCanContinue(); - isPartialSuccess = puf.isPartialSuccess(); - - return false; - } - - if (ar[0] == Packets.SSH_MSG_USERAUTH_INFO_REQUEST) - { - PacketUserauthInfoRequest pui = new PacketUserauthInfoRequest(ar, 0, ar.length); - - String[] responses; - - try - { - responses = cb.replyToChallenge(pui.getName(), pui.getInstruction(), pui.getNumPrompts(), pui - .getPrompt(), pui.getEcho()); - } - catch (Exception e) - { - throw (IOException) new IOException("Exception in callback.").initCause(e); - } - - if (responses == null) - throw new IOException("Your callback may not return NULL!"); - - PacketUserauthInfoResponse puir = new PacketUserauthInfoResponse(responses); - tm.sendMessage(puir.getPayload()); - - continue; - } - - throw new IOException("Unexpected SSH message (type " + ar[0] + ")"); - } - } - catch (IOException e) - { - tm.close(e, false); - throw (IOException) new IOException("Keyboard-interactive authentication failed.").initCause(e); - } - } - - public void handleMessage(byte[] msg, int msglen) throws IOException - { - synchronized (packets) - { - if (msg == null) - { - connectionClosed = true; - } - else - { - byte[] tmp = new byte[msglen]; - System.arraycopy(msg, 0, tmp, 0, msglen); - packets.addElement(tmp); - } - - packets.notifyAll(); - - if (packets.size() > 5) - { - connectionClosed = true; - throw new IOException("Error, peer is flooding us with authentication packets."); - } - } - } -} diff --git a/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java b/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java deleted file mode 100644 index c6831e6..0000000 --- a/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java +++ /dev/null @@ -1,579 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.DSAPrivateKeySpec; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.util.Map; -import java.util.Map.Entry; - -import com.trilead.ssh2.AuthAgentCallback; -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.packets.TypesWriter; -import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.ECDSASHA2Verify; -import com.trilead.ssh2.signature.RSASHA1Verify; - -/** - * AuthAgentForwardThread. - * - * @author Kenny Root - * @version $Id$ - */ -public class AuthAgentForwardThread extends Thread implements IChannelWorkerThread -{ - private static final byte[] SSH_AGENT_FAILURE = {0, 0, 0, 1, 5}; // 5 - private static final byte[] SSH_AGENT_SUCCESS = {0, 0, 0, 1, 6}; // 6 - - private static final int SSH2_AGENTC_REQUEST_IDENTITIES = 11; - private static final int SSH2_AGENT_IDENTITIES_ANSWER = 12; - - private static final int SSH2_AGENTC_SIGN_REQUEST = 13; - private static final int SSH2_AGENT_SIGN_RESPONSE = 14; - - private static final int SSH2_AGENTC_ADD_IDENTITY = 17; - private static final int SSH2_AGENTC_REMOVE_IDENTITY = 18; - private static final int SSH2_AGENTC_REMOVE_ALL_IDENTITIES = 19; - -// private static final int SSH_AGENTC_ADD_SMARTCARD_KEY = 20; -// private static final int SSH_AGENTC_REMOVE_SMARTCARD_KEY = 21; - - private static final int SSH_AGENTC_LOCK = 22; - private static final int SSH_AGENTC_UNLOCK = 23; - - private static final int SSH2_AGENTC_ADD_ID_CONSTRAINED = 25; -// private static final int SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED = 26; - - // Constraints for adding keys - private static final int SSH_AGENT_CONSTRAIN_LIFETIME = 1; - private static final int SSH_AGENT_CONSTRAIN_CONFIRM = 2; - - // Flags for signature requests -// private static final int SSH_AGENT_OLD_SIGNATURE = 1; - - private static final Logger log = Logger.getLogger(RemoteAcceptThread.class); - - AuthAgentCallback authAgent; - OutputStream os; - InputStream is; - Channel c; - - byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE]; - - public AuthAgentForwardThread(Channel c, AuthAgentCallback authAgent) - { - this.c = c; - this.authAgent = authAgent; - - if (log.isEnabled()) - log.log(20, "AuthAgentForwardThread started"); - } - - @Override - public void run() - { - try - { - c.cm.registerThread(this); - } - catch (IOException e) - { - stopWorking(); - return; - } - - try - { - c.cm.sendOpenConfirmation(c); - - is = c.getStdoutStream(); - os = c.getStdinStream(); - - int totalSize = 4; - int readSoFar = 0; - - while (true) { - int len; - - try - { - len = is.read(buffer, readSoFar, buffer.length - readSoFar); - } - catch (IOException e) - { - stopWorking(); - return; - } - - if (len <= 0) - break; - - readSoFar += len; - - if (readSoFar >= 4) { - TypesReader tr = new TypesReader(buffer, 0, 4); - totalSize = tr.readUINT32() + 4; - } - - if (totalSize == readSoFar) { - TypesReader tr = new TypesReader(buffer, 4, readSoFar - 4); - int messageType = tr.readByte(); - - switch (messageType) { - case SSH2_AGENTC_REQUEST_IDENTITIES: - sendIdentities(); - break; - case SSH2_AGENTC_ADD_IDENTITY: - addIdentity(tr, false); - break; - case SSH2_AGENTC_ADD_ID_CONSTRAINED: - addIdentity(tr, true); - break; - case SSH2_AGENTC_REMOVE_IDENTITY: - removeIdentity(tr); - break; - case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: - removeAllIdentities(tr); - break; - case SSH2_AGENTC_SIGN_REQUEST: - processSignRequest(tr); - break; - case SSH_AGENTC_LOCK: - processLockRequest(tr); - break; - case SSH_AGENTC_UNLOCK: - processUnlockRequest(tr); - break; - default: - os.write(SSH_AGENT_FAILURE); - break; - } - - readSoFar = 0; - } - } - - c.cm.closeChannel(c, "EOF on both streams reached.", true); - } - catch (IOException e) - { - log.log(50, "IOException in agent forwarder: " + e.getMessage()); - - try - { - is.close(); - } - catch (IOException e1) - { - } - - try - { - os.close(); - } - catch (IOException e2) - { - } - - try - { - c.cm.closeChannel(c, "IOException in agent forwarder (" + e.getMessage() + ")", true); - } - catch (IOException e3) - { - } - } - } - - public void stopWorking() { - try - { - /* This will lead to an IOException in the is.read() call */ - is.close(); - } - catch (IOException e) - { - } - } - - /** - * @return whether the agent is locked - */ - private boolean failWhenLocked() throws IOException - { - if (authAgent.isAgentLocked()) { - os.write(SSH_AGENT_FAILURE); - return true; - } else - return false; - } - - private void sendIdentities() throws IOException - { - Map<String,byte[]> keys = null; - - TypesWriter tw = new TypesWriter(); - tw.writeByte(SSH2_AGENT_IDENTITIES_ANSWER); - int numKeys = 0; - - if (!authAgent.isAgentLocked()) - keys = authAgent.retrieveIdentities(); - - if (keys != null) - numKeys = keys.size(); - - tw.writeUINT32(numKeys); - - if (keys != null) { - for (Entry<String,byte[]> entry : keys.entrySet()) { - byte[] keyBytes = entry.getValue(); - tw.writeString(keyBytes, 0, keyBytes.length); - tw.writeString(entry.getKey()); - } - } - - sendPacket(tw.getBytes()); - } - - /** - * @param tr - */ - private void addIdentity(TypesReader tr, boolean checkConstraints) { - try - { - if (failWhenLocked()) - return; - - String type = tr.readString(); - - String comment; - String keyType; - KeySpec pubSpec; - KeySpec privSpec; - - if (type.equals("ssh-rsa")) { - keyType = "RSA"; - - BigInteger n = tr.readMPINT(); - BigInteger e = tr.readMPINT(); - BigInteger d = tr.readMPINT(); - BigInteger iqmp = tr.readMPINT(); - BigInteger p = tr.readMPINT(); - BigInteger q = tr.readMPINT(); - comment = tr.readString(); - - // Derive the extra values Java needs. - BigInteger dmp1 = d.mod(p.subtract(BigInteger.ONE)); - BigInteger dmq1 = d.mod(q.subtract(BigInteger.ONE)); - - pubSpec = new RSAPublicKeySpec(n, e); - privSpec = new RSAPrivateCrtKeySpec(n, e, d, p, q, dmp1, dmq1, iqmp); - } else if (type.equals("ssh-dss")) { - keyType = "DSA"; - - BigInteger p = tr.readMPINT(); - BigInteger q = tr.readMPINT(); - BigInteger g = tr.readMPINT(); - BigInteger y = tr.readMPINT(); - BigInteger x = tr.readMPINT(); - comment = tr.readString(); - - pubSpec = new DSAPublicKeySpec(y, p, q, g); - privSpec = new DSAPrivateKeySpec(x, p, q, g); - } else if (type.equals("ecdsa-sha2-nistp256")) { - keyType = "EC"; - - String curveName = tr.readString(); - byte[] groupBytes = tr.readByteString(); - BigInteger exponent = tr.readMPINT(); - comment = tr.readString(); - - if (!"nistp256".equals(curveName)) { - log.log(2, "Invalid curve name for ecdsa-sha2-nistp256: " + curveName); - os.write(SSH_AGENT_FAILURE); - return; - } - - ECParameterSpec nistp256 = ECDSASHA2Verify.EllipticCurves.nistp256; - ECPoint group = ECDSASHA2Verify.decodeECPoint(groupBytes, nistp256.getCurve()); - if (group == null) { - // TODO log error - os.write(SSH_AGENT_FAILURE); - return; - } - - pubSpec = new ECPublicKeySpec(group, nistp256); - privSpec = new ECPrivateKeySpec(exponent, nistp256); - } else { - log.log(2, "Unknown key type: " + type); - os.write(SSH_AGENT_FAILURE); - return; - } - - PublicKey pubKey; - PrivateKey privKey; - try { - KeyFactory kf = KeyFactory.getInstance(keyType); - pubKey = kf.generatePublic(pubSpec); - privKey = kf.generatePrivate(privSpec); - } catch (NoSuchAlgorithmException ex) { - // TODO: log error - os.write(SSH_AGENT_FAILURE); - return; - } catch (InvalidKeySpecException ex) { - // TODO: log error - os.write(SSH_AGENT_FAILURE); - return; - } - - KeyPair pair = new KeyPair(pubKey, privKey); - - boolean confirmUse = false; - int lifetime = 0; - - if (checkConstraints) { - while (tr.remain() > 0) { - int constraint = tr.readByte(); - if (constraint == SSH_AGENT_CONSTRAIN_CONFIRM) - confirmUse = true; - else if (constraint == SSH_AGENT_CONSTRAIN_LIFETIME) - lifetime = tr.readUINT32(); - else { - // Unknown constraint. Bail. - os.write(SSH_AGENT_FAILURE); - return; - } - } - } - - if (authAgent.addIdentity(pair, comment, confirmUse, lifetime)) - os.write(SSH_AGENT_SUCCESS); - else - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tr - */ - private void removeIdentity(TypesReader tr) { - try - { - if (failWhenLocked()) - return; - - byte[] publicKey = tr.readByteString(); - if (authAgent.removeIdentity(publicKey)) - os.write(SSH_AGENT_SUCCESS); - else - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tr - */ - private void removeAllIdentities(TypesReader tr) { - try - { - if (failWhenLocked()) - return; - - if (authAgent.removeAllIdentities()) - os.write(SSH_AGENT_SUCCESS); - else - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - private void processSignRequest(TypesReader tr) - { - try - { - if (failWhenLocked()) - return; - - byte[] publicKeyBytes = tr.readByteString(); - byte[] challenge = tr.readByteString(); - - int flags = tr.readUINT32(); - - if (flags != 0) { - // We don't understand any flags; abort! - os.write(SSH_AGENT_FAILURE); - return; - } - - KeyPair pair = authAgent.getKeyPair(publicKeyBytes); - - if (pair == null) { - os.write(SSH_AGENT_FAILURE); - return; - } - - byte[] response; - - PrivateKey privKey = pair.getPrivate(); - if (privKey instanceof RSAPrivateKey) { - byte[] signature = RSASHA1Verify.generateSignature(challenge, - (RSAPrivateKey) privKey); - response = RSASHA1Verify.encodeSSHRSASignature(signature); - } else if (privKey instanceof DSAPrivateKey) { - byte[] signature = DSASHA1Verify.generateSignature(challenge, - (DSAPrivateKey) privKey, new SecureRandom()); - response = DSASHA1Verify.encodeSSHDSASignature(signature); - } else { - os.write(SSH_AGENT_FAILURE); - return; - } - - TypesWriter tw = new TypesWriter(); - tw.writeByte(SSH2_AGENT_SIGN_RESPONSE); - tw.writeString(response, 0, response.length); - - sendPacket(tw.getBytes()); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tr - */ - private void processLockRequest(TypesReader tr) { - try - { - if (failWhenLocked()) - return; - - String lockPassphrase = tr.readString(); - if (!authAgent.setAgentLock(lockPassphrase)) { - os.write(SSH_AGENT_FAILURE); - return; - } else - os.write(SSH_AGENT_SUCCESS); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tr - */ - private void processUnlockRequest(TypesReader tr) - { - try - { - String unlockPassphrase = tr.readString(); - - if (authAgent.requestAgentUnlock(unlockPassphrase)) - os.write(SSH_AGENT_SUCCESS); - else - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e) - { - try - { - os.write(SSH_AGENT_FAILURE); - } - catch (IOException e1) - { - } - } - } - - /** - * @param tw - * @throws IOException - */ - private void sendPacket(byte[] message) throws IOException - { - TypesWriter packet = new TypesWriter(); - packet.writeUINT32(message.length); - packet.writeBytes(message); - os.write(packet.getBytes()); - } -} diff --git a/src/com/trilead/ssh2/channel/Channel.java b/src/com/trilead/ssh2/channel/Channel.java deleted file mode 100644 index 8365f12..0000000 --- a/src/com/trilead/ssh2/channel/Channel.java +++ /dev/null @@ -1,207 +0,0 @@ - -package com.trilead.ssh2.channel; - -/** - * Channel. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Channel.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class Channel -{ - /* - * OK. Here is an important part of the JVM Specification: - * (http://java.sun.com/docs/books/vmspec/2nd-edition/html/Threads.doc.html#22214) - * - * Any association between locks and variables is purely conventional. - * Locking any lock conceptually flushes all variables from a thread's - * working memory, and unlocking any lock forces the writing out to main - * memory of all variables that the thread has assigned. That a lock may be - * associated with a particular object or a class is purely a convention. - * (...) - * - * If a thread uses a particular shared variable only after locking a - * particular lock and before the corresponding unlocking of that same lock, - * then the thread will read the shared value of that variable from main - * memory after the lock operation, if necessary, and will copy back to main - * memory the value most recently assigned to that variable before the - * unlock operation. - * - * This, in conjunction with the mutual exclusion rules for locks, suffices - * to guarantee that values are correctly transmitted from one thread to - * another through shared variables. - * - * ====> Always keep that in mind when modifying the Channel/ChannelManger - * code. - * - */ - - static final int STATE_OPENING = 1; - static final int STATE_OPEN = 2; - static final int STATE_CLOSED = 4; - - static final int CHANNEL_BUFFER_SIZE = 30000; - - /* - * To achieve correctness, the following rules have to be respected when - * accessing this object: - */ - - // These fields can always be read - final ChannelManager cm; - final ChannelOutputStream stdinStream; - final ChannelInputStream stdoutStream; - final ChannelInputStream stderrStream; - - // These two fields will only be written while the Channel is in state - // STATE_OPENING. - // The code makes sure that the two fields are written out when the state is - // changing to STATE_OPEN. - // Therefore, if you know that the Channel is in state STATE_OPEN, then you - // can read these two fields without synchronizing on the Channel. However, make - // sure that you get the latest values (e.g., flush caches by synchronizing on any - // object). However, to be on the safe side, you can lock the channel. - - int localID = -1; - int remoteID = -1; - - /* - * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE - * msg. - * - * This is a little bit complicated, but we have to do it in that way, since - * we cannot keep a lock on the Channel during the send operation (this - * would block sometimes the receiver thread, and, in extreme cases, can - * lead to a deadlock on both sides of the connection (senders are blocked - * since the receive buffers on the other side are full, and receiver - * threads wait for the senders to finish). It all depends on the - * implementation on the other side. But we cannot make any assumptions, we - * have to assume the worst case. Confused? Just believe me. - */ - - /* - * If you send a message on a channel, then you have to aquire the - * "channelSendLock" and check the "closeMessageSent" flag (this variable - * may only be accessed while holding the "channelSendLock" !!! - * - * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation - * above. - */ - - final Object channelSendLock = new Object(); - boolean closeMessageSent = false; - - /* - * Stop memory fragmentation by allocating this often used buffer. - * May only be used while holding the channelSendLock - */ - - final byte[] msgWindowAdjust = new byte[9]; - - // If you access (read or write) any of the following fields, then you have - // to synchronize on the channel. - - int state = STATE_OPENING; - - boolean closeMessageRecv = false; - - /* This is a stupid implementation. At the moment we can only wait - * for one pending request per channel. - */ - int successCounter = 0; - int failedCounter = 0; - - int localWindow = 0; /* locally, we use a small window, < 2^31 */ - long remoteWindow = 0; /* long for readable 2^32 - 1 window support */ - - int localMaxPacketSize = -1; - int remoteMaxPacketSize = -1; - - final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE]; - final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE]; - - int stdoutReadpos = 0; - int stdoutWritepos = 0; - int stderrReadpos = 0; - int stderrWritepos = 0; - - boolean EOF = false; - - Integer exit_status; - - String exit_signal; - - // we keep the x11 cookie so that this channel can be closed when this - // specific x11 forwarding gets stopped - - String hexX11FakeCookie; - - // reasonClosed is special, since we sometimes need to access it - // while holding the channelSendLock. - // We protect it with a private short term lock. - - private final Object reasonClosedLock = new Object(); - private String reasonClosed = null; - - public Channel(ChannelManager cm) - { - this.cm = cm; - - this.localWindow = CHANNEL_BUFFER_SIZE; - this.localMaxPacketSize = 35000 - 1024; // leave enough slack - - this.stdinStream = new ChannelOutputStream(this); - this.stdoutStream = new ChannelInputStream(this, false); - this.stderrStream = new ChannelInputStream(this, true); - } - - /* Methods to allow access from classes outside of this package */ - - public ChannelInputStream getStderrStream() - { - return stderrStream; - } - - public ChannelOutputStream getStdinStream() - { - return stdinStream; - } - - public ChannelInputStream getStdoutStream() - { - return stdoutStream; - } - - public String getExitSignal() - { - synchronized (this) - { - return exit_signal; - } - } - - public Integer getExitStatus() - { - synchronized (this) - { - return exit_status; - } - } - - public String getReasonClosed() - { - synchronized (reasonClosedLock) - { - return reasonClosed; - } - } - - public void setReasonClosed(String reasonClosed) - { - synchronized (reasonClosedLock) - { - if (this.reasonClosed == null) - this.reasonClosed = reasonClosed; - } - } -} diff --git a/src/com/trilead/ssh2/channel/ChannelInputStream.java b/src/com/trilead/ssh2/channel/ChannelInputStream.java deleted file mode 100644 index f88522c..0000000 --- a/src/com/trilead/ssh2/channel/ChannelInputStream.java +++ /dev/null @@ -1,86 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; - -/** - * ChannelInputStream. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ChannelInputStream.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public final class ChannelInputStream extends InputStream -{ - Channel c; - - boolean isClosed = false; - boolean isEOF = false; - boolean extendedFlag = false; - - ChannelInputStream(Channel c, boolean isExtended) - { - this.c = c; - this.extendedFlag = isExtended; - } - - public int available() throws IOException - { - if (isEOF) - return 0; - - int avail = c.cm.getAvailable(c, extendedFlag); - - /* We must not return -1 on EOF */ - - return (avail > 0) ? avail : 0; - } - - public void close() throws IOException - { - isClosed = true; - } - - public int read(byte[] b, int off, int len) throws IOException - { - if (b == null) - throw new NullPointerException(); - - if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) - throw new IndexOutOfBoundsException(); - - if (len == 0) - return 0; - - if (isEOF) - return -1; - - int ret = c.cm.getChannelData(c, extendedFlag, b, off, len); - - if (ret == -1) - { - isEOF = true; - } - - return ret; - } - - public int read(byte[] b) throws IOException - { - return read(b, 0, b.length); - } - - public int read() throws IOException - { - /* Yes, this stream is pure and unbuffered, a single byte read() is slow */ - - final byte b[] = new byte[1]; - - int ret = read(b, 0, 1); - - if (ret != 1) - return -1; - - return b[0] & 0xff; - } -} diff --git a/src/com/trilead/ssh2/channel/ChannelManager.java b/src/com/trilead/ssh2/channel/ChannelManager.java deleted file mode 100644 index 88beffd..0000000 --- a/src/com/trilead/ssh2/channel/ChannelManager.java +++ /dev/null @@ -1,1756 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Vector; - -import com.trilead.ssh2.AuthAgentCallback; -import com.trilead.ssh2.ChannelCondition; -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.PacketChannelAuthAgentReq; -import com.trilead.ssh2.packets.PacketChannelOpenConfirmation; -import com.trilead.ssh2.packets.PacketChannelOpenFailure; -import com.trilead.ssh2.packets.PacketChannelTrileadPing; -import com.trilead.ssh2.packets.PacketGlobalCancelForwardRequest; -import com.trilead.ssh2.packets.PacketGlobalForwardRequest; -import com.trilead.ssh2.packets.PacketGlobalTrileadPing; -import com.trilead.ssh2.packets.PacketOpenDirectTCPIPChannel; -import com.trilead.ssh2.packets.PacketOpenSessionChannel; -import com.trilead.ssh2.packets.PacketSessionExecCommand; -import com.trilead.ssh2.packets.PacketSessionPtyRequest; -import com.trilead.ssh2.packets.PacketSessionPtyResize; -import com.trilead.ssh2.packets.PacketSessionStartShell; -import com.trilead.ssh2.packets.PacketSessionSubsystemRequest; -import com.trilead.ssh2.packets.PacketSessionX11Request; -import com.trilead.ssh2.packets.Packets; -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.transport.MessageHandler; -import com.trilead.ssh2.transport.TransportManager; - -/** - * ChannelManager. Please read the comments in Channel.java. - * <p> - * Besides the crypto part, this is the core of the library. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ChannelManager.java,v 1.2 2008/03/03 07:01:36 cplattne Exp $ - */ -public class ChannelManager implements MessageHandler -{ - private static final Logger log = Logger.getLogger(ChannelManager.class); - - private HashMap<String, X11ServerData> x11_magic_cookies = new HashMap<String, X11ServerData>(); - - private TransportManager tm; - - private Vector<Channel> channels = new Vector<Channel>(); - private int nextLocalChannel = 100; - private boolean shutdown = false; - private int globalSuccessCounter = 0; - private int globalFailedCounter = 0; - - private HashMap<Integer, RemoteForwardingData> remoteForwardings = new HashMap<Integer, RemoteForwardingData>(); - - private AuthAgentCallback authAgent; - - private Vector<IChannelWorkerThread> listenerThreads = new Vector<IChannelWorkerThread>(); - - private boolean listenerThreadsAllowed = true; - - public ChannelManager(TransportManager tm) - { - this.tm = tm; - tm.registerMessageHandler(this, 80, 100); - } - - private Channel getChannel(int id) - { - synchronized (channels) - { - for (int i = 0; i < channels.size(); i++) - { - Channel c = channels.elementAt(i); - if (c.localID == id) - return c; - } - } - return null; - } - - private void removeChannel(int id) - { - synchronized (channels) - { - for (int i = 0; i < channels.size(); i++) - { - Channel c = channels.elementAt(i); - if (c.localID == id) - { - channels.removeElementAt(i); - break; - } - } - } - } - - private int addChannel(Channel c) - { - synchronized (channels) - { - channels.addElement(c); - return nextLocalChannel++; - } - } - - private void waitUntilChannelOpen(Channel c) throws IOException - { - synchronized (c) - { - while (c.state == Channel.STATE_OPENING) - { - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - } - } - - if (c.state != Channel.STATE_OPEN) - { - removeChannel(c.localID); - - String detail = c.getReasonClosed(); - - if (detail == null) - detail = "state: " + c.state; - - throw new IOException("Could not open channel (" + detail + ")"); - } - } - } - - private final boolean waitForGlobalRequestResult() throws IOException - { - synchronized (channels) - { - while ((globalSuccessCounter == 0) && (globalFailedCounter == 0)) - { - if (shutdown) - { - throw new IOException("The connection is being shutdown"); - } - - try - { - channels.wait(); - } - catch (InterruptedException ignore) - { - } - } - - if ((globalFailedCounter == 0) && (globalSuccessCounter == 1)) - return true; - - if ((globalFailedCounter == 1) && (globalSuccessCounter == 0)) - return false; - - throw new IOException("Illegal state. The server sent " + globalSuccessCounter - + " SSH_MSG_REQUEST_SUCCESS and " + globalFailedCounter + " SSH_MSG_REQUEST_FAILURE messages."); - } - } - - private final boolean waitForChannelRequestResult(Channel c) throws IOException - { - synchronized (c) - { - while ((c.successCounter == 0) && (c.failedCounter == 0)) - { - if (c.state != Channel.STATE_OPEN) - { - String detail = c.getReasonClosed(); - - if (detail == null) - detail = "state: " + c.state; - - throw new IOException("This SSH2 channel is not open (" + detail + ")"); - } - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - } - } - - if ((c.failedCounter == 0) && (c.successCounter == 1)) - return true; - - if ((c.failedCounter == 1) && (c.successCounter == 0)) - return false; - - throw new IOException("Illegal state. The server sent " + c.successCounter - + " SSH_MSG_CHANNEL_SUCCESS and " + c.failedCounter + " SSH_MSG_CHANNEL_FAILURE messages."); - } - } - - public void registerX11Cookie(String hexFakeCookie, X11ServerData data) - { - synchronized (x11_magic_cookies) - { - x11_magic_cookies.put(hexFakeCookie, data); - } - } - - public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels) - { - if (hexFakeCookie == null) - throw new IllegalStateException("hexFakeCookie may not be null"); - - synchronized (x11_magic_cookies) - { - x11_magic_cookies.remove(hexFakeCookie); - } - - if (killChannels == false) - return; - - if (log.isEnabled()) - log.log(50, "Closing all X11 channels for the given fake cookie"); - - Vector<Channel> channel_copy; - - synchronized (channels) - { - channel_copy = (Vector<Channel>) channels.clone(); - } - - for (int i = 0; i < channel_copy.size(); i++) - { - Channel c = channel_copy.elementAt(i); - - synchronized (c) - { - if (hexFakeCookie.equals(c.hexX11FakeCookie) == false) - continue; - } - - try - { - closeChannel(c, "Closing X11 channel since the corresponding session is closing", true); - } - catch (IOException e) - { - } - } - } - - public X11ServerData checkX11Cookie(String hexFakeCookie) - { - synchronized (x11_magic_cookies) - { - if (hexFakeCookie != null) - return x11_magic_cookies.get(hexFakeCookie); - } - return null; - } - - public void closeAllChannels() - { - if (log.isEnabled()) - log.log(50, "Closing all channels"); - - Vector<Channel> channel_copy; - - synchronized (channels) - { - channel_copy = (Vector<Channel>) channels.clone(); - } - - for (int i = 0; i < channel_copy.size(); i++) - { - Channel c = channel_copy.elementAt(i); - try - { - closeChannel(c, "Closing all channels", true); - } - catch (IOException e) - { - } - } - } - - public void closeChannel(Channel c, String reason, boolean force) throws IOException - { - byte msg[] = new byte[5]; - - synchronized (c) - { - if (force) - { - c.state = Channel.STATE_CLOSED; - c.EOF = true; - } - - c.setReasonClosed(reason); - - msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - - c.notifyAll(); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(msg); - c.closeMessageSent = true; - } - - if (log.isEnabled()) - log.log(50, "Sent SSH_MSG_CHANNEL_CLOSE (channel " + c.localID + ")"); - } - - public void sendEOF(Channel c) throws IOException - { - byte[] msg = new byte[5]; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - return; - - msg[0] = Packets.SSH_MSG_CHANNEL_EOF; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(msg); - } - - if (log.isEnabled()) - log.log(50, "Sent EOF (Channel " + c.localID + "/" + c.remoteID + ")"); - } - - public void sendOpenConfirmation(Channel c) throws IOException - { - PacketChannelOpenConfirmation pcoc = null; - - synchronized (c) - { - if (c.state != Channel.STATE_OPENING) - return; - - c.state = Channel.STATE_OPEN; - - pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - return; - tm.sendMessage(pcoc.getPayload()); - } - } - - public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException - { - while (len > 0) - { - int thislen = 0; - byte[] msg; - - synchronized (c) - { - while (true) - { - if (c.state == Channel.STATE_CLOSED) - throw new IOException("SSH channel is closed. (" + c.getReasonClosed() + ")"); - - if (c.state != Channel.STATE_OPEN) - throw new IOException("SSH channel in strange state. (" + c.state + ")"); - - if (c.remoteWindow != 0) - break; - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - } - } - - /* len > 0, no sign extension can happen when comparing */ - - thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow; - - int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9); - - /* The worst case scenario =) a true bottleneck */ - - if (estimatedMaxDataLen <= 0) - { - estimatedMaxDataLen = 1; - } - - if (thislen > estimatedMaxDataLen) - thislen = estimatedMaxDataLen; - - c.remoteWindow -= thislen; - - msg = new byte[1 + 8 + thislen]; - - msg[0] = Packets.SSH_MSG_CHANNEL_DATA; - msg[1] = (byte) (c.remoteID >> 24); - msg[2] = (byte) (c.remoteID >> 16); - msg[3] = (byte) (c.remoteID >> 8); - msg[4] = (byte) (c.remoteID); - msg[5] = (byte) (thislen >> 24); - msg[6] = (byte) (thislen >> 16); - msg[7] = (byte) (thislen >> 8); - msg[8] = (byte) (thislen); - - System.arraycopy(buffer, pos, msg, 9, thislen); - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent == true) - throw new IOException("SSH channel is closed. (" + c.getReasonClosed() + ")"); - - tm.sendMessage(msg); - } - - pos += thislen; - len -= thislen; - } - } - - public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort) - throws IOException - { - RemoteForwardingData rfd = new RemoteForwardingData(); - - rfd.bindAddress = bindAddress; - rfd.bindPort = bindPort; - rfd.targetAddress = targetAddress; - rfd.targetPort = targetPort; - - synchronized (remoteForwardings) - { - Integer key = Integer.valueOf(bindPort); - - if (remoteForwardings.get(key) != null) - { - throw new IOException("There is already a forwarding for remote port " + bindPort); - } - - remoteForwardings.put(key, rfd); - } - - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort); - tm.sendMessage(pgf.getPayload()); - - if (log.isEnabled()) - log.log(50, "Requesting a remote forwarding ('" + bindAddress + "', " + bindPort + ")"); - - try - { - if (waitForGlobalRequestResult() == false) - throw new IOException("The server denied the request (did you enable port forwarding?)"); - } - catch (IOException e) - { - synchronized (remoteForwardings) - { - remoteForwardings.remove(rfd); - } - throw e; - } - - return bindPort; - } - - public void requestCancelGlobalForward(int bindPort) throws IOException - { - RemoteForwardingData rfd = null; - - synchronized (remoteForwardings) - { - rfd = remoteForwardings.get(Integer.valueOf(bindPort)); - - if (rfd == null) - throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort); - } - - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress, - rfd.bindPort); - tm.sendMessage(pgcf.getPayload()); - - if (log.isEnabled()) - log.log(50, "Requesting cancelation of remote forward ('" + rfd.bindAddress + "', " + rfd.bindPort + ")"); - - try - { - if (waitForGlobalRequestResult() == false) - throw new IOException("The server denied the request."); - } - finally - { - synchronized (remoteForwardings) - { - /* Only now we are sure that no more forwarded connections will arrive */ - remoteForwardings.remove(rfd); - } - } - - } - - /** - * @param agent - * @throws IOException - */ - public boolean requestChannelAgentForwarding(Channel c, AuthAgentCallback authAgent) throws IOException { - synchronized (this) - { - if (this.authAgent != null) - throw new IllegalStateException("Auth agent already exists"); - - this.authAgent = authAgent; - } - - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - if (log.isEnabled()) - log.log(50, "Requesting agent forwarding"); - - PacketChannelAuthAgentReq aar = new PacketChannelAuthAgentReq(c.remoteID); - tm.sendMessage(aar.getPayload()); - - if (waitForChannelRequestResult(c) == false) { - authAgent = null; - return false; - } - - return true; - } - - public void registerThread(IChannelWorkerThread thr) throws IOException - { - synchronized (listenerThreads) - { - if (listenerThreadsAllowed == false) - throw new IOException("Too late, this connection is closed."); - listenerThreads.addElement(thr); - } - } - - public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address, - int originator_port) throws IOException - { - Channel c = new Channel(this); - - synchronized (c) - { - c.localID = addChannel(c); - // end of synchronized block forces writing out to main memory - } - - PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow, - c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port); - - tm.sendMessage(dtc.getPayload()); - - waitUntilChannelOpen(c); - - return c; - } - - public Channel openSessionChannel() throws IOException - { - Channel c = new Channel(this); - - synchronized (c) - { - c.localID = addChannel(c); - // end of synchronized block forces the writing out to main memory - } - - if (log.isEnabled()) - log.log(50, "Sending SSH_MSG_CHANNEL_OPEN (Channel " + c.localID + ")"); - - PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize); - tm.sendMessage(smo.getPayload()); - - waitUntilChannelOpen(c); - - return c; - } - - public void requestGlobalTrileadPing() throws IOException - { - synchronized (channels) - { - globalSuccessCounter = globalFailedCounter = 0; - } - - PacketGlobalTrileadPing pgtp = new PacketGlobalTrileadPing(); - - tm.sendMessage(pgtp.getPayload()); - - if (log.isEnabled()) - log.log(50, "Sending SSH_MSG_GLOBAL_REQUEST 'trilead-ping'."); - - try - { - if (waitForGlobalRequestResult() == true) - throw new IOException("Your server is alive - but buggy. " - + "It replied with SSH_MSG_REQUEST_SUCCESS when it actually should not."); - - } - catch (IOException e) - { - throw (IOException) new IOException("The ping request failed.").initCause(e); - } - } - - public void requestChannelTrileadPing(Channel c) throws IOException - { - PacketChannelTrileadPing pctp; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot ping this channel (" + c.getReasonClosed() + ")"); - - pctp = new PacketChannelTrileadPing(c.remoteID); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot ping this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(pctp.getPayload()); - } - - try - { - if (waitForChannelRequestResult(c) == true) - throw new IOException("Your server is alive - but buggy. " - + "It replied with SSH_MSG_SESSION_SUCCESS when it actually should not."); - - } - catch (IOException e) - { - throw (IOException) new IOException("The ping request failed.").initCause(e); - } - } - - public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters, - int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException - { - PacketSessionPtyRequest spr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")"); - - spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters, - term_width_pixels, term_height_pixels, terminal_modes); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request PTY on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(spr.getPayload()); - } - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("PTY request failed").initCause(e); - } - } - - - public void resizePTY(Channel c, int term_width_characters, int term_height_characters, - int term_width_pixels, int term_height_pixels) throws IOException { - PacketSessionPtyResize spr; - - synchronized (c) { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request PTY on this channel (" - + c.getReasonClosed() + ")"); - - spr = new PacketSessionPtyResize(c.remoteID, term_width_characters, term_height_characters, - term_width_pixels, term_height_pixels); - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) { - if (c.closeMessageSent) - throw new IOException("Cannot request PTY on this channel (" - + c.getReasonClosed() + ")"); - tm.sendMessage(spr.getPayload()); - } - } - - - public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol, - String x11AuthenticationCookie, int x11ScreenNumber) throws IOException - { - PacketSessionX11Request psr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")"); - - psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol, - x11AuthenticationCookie, x11ScreenNumber); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request X11 on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(psr.getPayload()); - } - - if (log.isEnabled()) - log.log(50, "Requesting X11 forwarding (Channel " + c.localID + "/" + c.remoteID + ")"); - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("The X11 request failed.").initCause(e); - } - } - - public void requestSubSystem(Channel c, String subSystemName) throws IOException - { - PacketSessionSubsystemRequest ssr; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")"); - - ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot request subsystem on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(ssr.getPayload()); - } - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("The subsystem request failed.").initCause(e); - } - } - - public void requestExecCommand(Channel c, String cmd) throws IOException - { - PacketSessionExecCommand sm; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")"); - - sm = new PacketSessionExecCommand(c.remoteID, true, cmd); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot execute command on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(sm.getPayload()); - } - - if (log.isEnabled()) - log.log(50, "Executing command (channel " + c.localID + ", '" + cmd + "')"); - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("The execute request failed.").initCause(e); - } - } - - public void requestShell(Channel c) throws IOException - { - PacketSessionStartShell sm; - - synchronized (c) - { - if (c.state != Channel.STATE_OPEN) - throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")"); - - sm = new PacketSessionStartShell(c.remoteID, true); - - c.successCounter = c.failedCounter = 0; - } - - synchronized (c.channelSendLock) - { - if (c.closeMessageSent) - throw new IOException("Cannot start shell on this channel (" + c.getReasonClosed() + ")"); - tm.sendMessage(sm.getPayload()); - } - - try - { - if (waitForChannelRequestResult(c) == false) - throw new IOException("The server denied the request."); - } - catch (IOException e) - { - throw (IOException) new IOException("The shell request failed.").initCause(e); - } - } - - public void msgChannelExtendedData(byte[] msg, int msglen) throws IOException - { - if (msglen <= 13) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel " + id); - - if (dataType != Packets.SSH_EXTENDED_DATA_STDERR) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (" + dataType + ")"); - - if (len != (msglen - 13)) - throw new IOException("SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated " + (msglen - 13) - + ", got " + len + ")"); - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel " + id + ", " + len + ")"); - - synchronized (c) - { - if (c.state == Channel.STATE_CLOSED) - return; // ignore - - if (c.state != Channel.STATE_OPEN) - throw new IOException("Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state (" - + c.state + ")"); - - if (c.localWindow < len) - throw new IOException("Remote sent too much data, does not fit into window."); - - c.localWindow -= len; - - System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len); - c.stderrWritepos += len; - - c.notifyAll(); - } - } - - /** - * Wait until for a condition. - * - * @param c - * Channel - * @param timeout - * in ms, 0 means no timeout. - * @param condition_mask - * minimum event mask - * @return all current events - * - */ - public int waitForCondition(Channel c, long timeout, int condition_mask) - { - long end_time = 0; - boolean end_time_set = false; - - synchronized (c) - { - while (true) - { - int current_cond = 0; - - int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; - int stderrAvail = c.stderrWritepos - c.stderrReadpos; - - if (stdoutAvail > 0) - current_cond = current_cond | ChannelCondition.STDOUT_DATA; - - if (stderrAvail > 0) - current_cond = current_cond | ChannelCondition.STDERR_DATA; - - if (c.EOF) - current_cond = current_cond | ChannelCondition.EOF; - - if (c.getExitStatus() != null) - current_cond = current_cond | ChannelCondition.EXIT_STATUS; - - if (c.getExitSignal() != null) - current_cond = current_cond | ChannelCondition.EXIT_SIGNAL; - - if (c.state == Channel.STATE_CLOSED) - return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF; - - if ((current_cond & condition_mask) != 0) - return current_cond; - - if (timeout > 0) - { - if (!end_time_set) - { - end_time = System.currentTimeMillis() + timeout; - end_time_set = true; - } - else - { - timeout = end_time - System.currentTimeMillis(); - - if (timeout <= 0) - return current_cond | ChannelCondition.TIMEOUT; - } - } - - try - { - if (timeout > 0) - c.wait(timeout); - else - c.wait(); - } - catch (InterruptedException e) - { - } - } - } - } - - public int getAvailable(Channel c, boolean extended) throws IOException - { - synchronized (c) - { - int avail; - - if (extended) - avail = c.stderrWritepos - c.stderrReadpos; - else - avail = c.stdoutWritepos - c.stdoutReadpos; - - return ((avail > 0) ? avail : (c.EOF ? -1 : 0)); - } - } - - public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException - { - int copylen = 0; - int increment = 0; - int remoteID = 0; - int localID = 0; - - synchronized (c) - { - int stdoutAvail = 0; - int stderrAvail = 0; - - while (true) - { - /* - * Data available? We have to return remaining data even if the - * channel is already closed. - */ - - stdoutAvail = c.stdoutWritepos - c.stdoutReadpos; - stderrAvail = c.stderrWritepos - c.stderrReadpos; - - if ((!extended) && (stdoutAvail != 0)) - break; - - if ((extended) && (stderrAvail != 0)) - break; - - /* Do not wait if more data will never arrive (EOF or CLOSED) */ - - if ((c.EOF) || (c.state != Channel.STATE_OPEN)) - return -1; - - try - { - c.wait(); - } - catch (InterruptedException ignore) - { - } - } - - /* OK, there is some data. Return it. */ - - if (!extended) - { - copylen = (stdoutAvail > len) ? len : stdoutAvail; - System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen); - c.stdoutReadpos += copylen; - - if (c.stdoutReadpos != c.stdoutWritepos) - - System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos - - c.stdoutReadpos); - - c.stdoutWritepos -= c.stdoutReadpos; - c.stdoutReadpos = 0; - } - else - { - copylen = (stderrAvail > len) ? len : stderrAvail; - System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen); - c.stderrReadpos += copylen; - - if (c.stderrReadpos != c.stderrWritepos) - - System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos - - c.stderrReadpos); - - c.stderrWritepos -= c.stderrReadpos; - c.stderrReadpos = 0; - } - - if (c.state != Channel.STATE_OPEN) - return copylen; - - if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2)) - { - int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, Channel.CHANNEL_BUFFER_SIZE - - c.stderrWritepos); - - increment = minFreeSpace - c.localWindow; - c.localWindow = minFreeSpace; - } - - remoteID = c.remoteID; /* read while holding the lock */ - localID = c.localID; /* read while holding the lock */ - } - - /* - * If a consumer reads stdout and stdin in parallel, we may end up with - * sending two msgWindowAdjust messages. Luckily, it - * does not matter in which order they arrive at the server. - */ - - if (increment > 0) - { - if (log.isEnabled()) - log.log(80, "Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + localID + ", " + increment + ")"); - - synchronized (c.channelSendLock) - { - byte[] msg = c.msgWindowAdjust; - - msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST; - msg[1] = (byte) (remoteID >> 24); - msg[2] = (byte) (remoteID >> 16); - msg[3] = (byte) (remoteID >> 8); - msg[4] = (byte) (remoteID); - msg[5] = (byte) (increment >> 24); - msg[6] = (byte) (increment >> 16); - msg[7] = (byte) (increment >> 8); - msg[8] = (byte) (increment); - - if (c.closeMessageSent == false) - tm.sendMessage(msg); - } - } - - return copylen; - } - - public void msgChannelData(byte[] msg, int msglen) throws IOException - { - if (msglen <= 9) - throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel " + id); - - if (len != (msglen - 9)) - throw new IOException("SSH_MSG_CHANNEL_DATA message has wrong len (calculated " + (msglen - 9) + ", got " - + len + ")"); - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_DATA (channel " + id + ", " + len + ")"); - - synchronized (c) - { - if (c.state == Channel.STATE_CLOSED) - return; // ignore - - if (c.state != Channel.STATE_OPEN) - throw new IOException("Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (" + c.state + ")"); - - if (c.localWindow < len) - throw new IOException("Remote sent too much data, does not fit into window."); - - c.localWindow -= len; - - System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len); - c.stdoutWritepos += len; - - c.notifyAll(); - } - } - - public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException - { - if (msglen != 9) - throw new IOException("SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel " + id); - - synchronized (c) - { - final long huge = 0xFFFFffffL; /* 2^32 - 1 */ - - c.remoteWindow += (windowChange & huge); /* avoid sign extension */ - - /* TODO - is this a good heuristic? */ - - if ((c.remoteWindow > huge)) - c.remoteWindow = huge; - - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel " + id + ", " + windowChange + ")"); - } - - public void msgChannelOpen(byte[] msg, int msglen) throws IOException - { - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - String channelType = tr.readString(); - int remoteID = tr.readUINT32(); /* sender channel */ - int remoteWindow = tr.readUINT32(); /* initial window size */ - int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */ - - if ("x11".equals(channelType)) - { - synchronized (x11_magic_cookies) - { - /* If we did not request X11 forwarding, then simply ignore this bogus request. */ - - if (x11_magic_cookies.size() == 0) - { - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, - Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, "X11 forwarding not activated", ""); - - tm.sendAsynchronousMessage(pcof.getPayload()); - - if (log.isEnabled()) - log.log(20, "Unexpected X11 request, denying it!"); - - return; - } - } - - String remoteOriginatorAddress = tr.readString(); - int remoteOriginatorPort = tr.readUINT32(); - - Channel c = new Channel(this); - - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - } - - /* - * The open confirmation message will be sent from another thread - */ - - RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort); - rxat.setDaemon(true); - rxat.start(); - - return; - } - - if ("forwarded-tcpip".equals(channelType)) - { - String remoteConnectedAddress = tr.readString(); /* address that was connected */ - int remoteConnectedPort = tr.readUINT32(); /* port that was connected */ - String remoteOriginatorAddress = tr.readString(); /* originator IP address */ - int remoteOriginatorPort = tr.readUINT32(); /* originator port */ - - RemoteForwardingData rfd = null; - - synchronized (remoteForwardings) - { - rfd = remoteForwardings.get(Integer.valueOf(remoteConnectedPort)); - } - - if (rfd == null) - { - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, - Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, - "No thanks, unknown port in forwarded-tcpip request", ""); - - /* Always try to be polite. */ - - tm.sendAsynchronousMessage(pcof.getPayload()); - - if (log.isEnabled()) - log.log(20, "Unexpected forwarded-tcpip request, denying it!"); - - return; - } - - Channel c = new Channel(this); - - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - } - - /* - * The open confirmation message will be sent from another thread. - */ - - RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort, - remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort); - - rat.setDaemon(true); - rat.start(); - - return; - } - - if ("auth-agent@openssh.com".equals(channelType)) { - Channel c = new Channel(this); - - synchronized (c) - { - c.remoteID = remoteID; - c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */ - c.remoteMaxPacketSize = remoteMaxPacketSize; - c.localID = addChannel(c); - } - - AuthAgentForwardThread aat = new AuthAgentForwardThread(c, authAgent); - - aat.setDaemon(true); - aat.start(); - - return; - } - - /* Tell the server that we have no idea what it is talking about */ - - PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE, - "Unknown channel type", ""); - - tm.sendAsynchronousMessage(pcof.getPayload()); - - if (log.isEnabled()) - log.log(20, "The peer tried to open an unsupported channel type (" + channelType + ")"); - } - - public void msgChannelRequest(byte[] msg, int msglen) throws IOException - { - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - int id = tr.readUINT32(); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel " + id); - - String type = tr.readString("US-ASCII"); - boolean wantReply = tr.readBoolean(); - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_REQUEST (channel " + id + ", '" + type + "')"); - - if (type.equals("exit-status")) - { - if (wantReply != false) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true"); - - int exit_status = tr.readUINT32(); - - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - synchronized (c) - { - c.exit_status = Integer.valueOf(exit_status); - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got EXIT STATUS (channel " + id + ", status " + exit_status + ")"); - - return; - } - - if (type.equals("exit-signal")) - { - if (wantReply != false) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true"); - - String signame = tr.readString("US-ASCII"); - tr.readBoolean(); - tr.readString(); - tr.readString(); - - if (tr.remain() != 0) - throw new IOException("Badly formatted SSH_MSG_CHANNEL_REQUEST message"); - - synchronized (c) - { - c.exit_signal = signame; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got EXIT SIGNAL (channel " + id + ", signal " + signame + ")"); - - return; - } - - /* We simply ignore unknown channel requests, however, if the server wants a reply, - * then we signal that we have no idea what it is about. - */ - - if (wantReply) - { - byte[] reply = new byte[5]; - - reply[0] = Packets.SSH_MSG_CHANNEL_FAILURE; - reply[1] = (byte) (c.remoteID >> 24); - reply[2] = (byte) (c.remoteID >> 16); - reply[3] = (byte) (c.remoteID >> 8); - reply[4] = (byte) (c.remoteID); - - tm.sendAsynchronousMessage(reply); - } - - if (log.isEnabled()) - log.log(50, "Channel request '" + type + "' is not known, ignoring it"); - } - - public void msgChannelEOF(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_EOF message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel " + id); - - synchronized (c) - { - c.EOF = true; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_EOF (channel " + id + ")"); - } - - public void msgChannelClose(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_CLOSE message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel " + id); - - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("Close requested by remote"); - c.closeMessageRecv = true; - - removeChannel(c.localID); - - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_CLOSE (channel " + id + ")"); - } - - public void msgChannelSuccess(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_SUCCESS message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel " + id); - - synchronized (c) - { - c.successCounter++; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_CHANNEL_SUCCESS (channel " + id + ")"); - } - - public void msgChannelFailure(byte[] msg, int msglen) throws IOException - { - if (msglen != 5) - throw new IOException("SSH_MSG_CHANNEL_FAILURE message has wrong size (" + msglen + ")"); - - int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff); - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel " + id); - - synchronized (c) - { - c.failedCounter++; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_FAILURE (channel " + id + ")"); - } - - public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException - { - PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen); - - Channel c = getChannel(sm.recipientChannelID); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel " - + sm.recipientChannelID); - - synchronized (c) - { - if (c.state != Channel.STATE_OPENING) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel " - + sm.recipientChannelID); - - c.remoteID = sm.senderChannelID; - c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */ - c.remoteMaxPacketSize = sm.maxPacketSize; - c.state = Channel.STATE_OPEN; - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel " + sm.recipientChannelID + " / remote: " - + sm.senderChannelID + ")"); - } - - public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException - { - if (msglen < 5) - throw new IOException("SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (" + msglen + ")"); - - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - int id = tr.readUINT32(); /* sender channel */ - - Channel c = getChannel(id); - - if (c == null) - throw new IOException("Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel " + id); - - int reasonCode = tr.readUINT32(); - String description = tr.readString("UTF-8"); - - String reasonCodeSymbolicName = null; - - switch (reasonCode) - { - case 1: - reasonCodeSymbolicName = "SSH_OPEN_ADMINISTRATIVELY_PROHIBITED"; - break; - case 2: - reasonCodeSymbolicName = "SSH_OPEN_CONNECT_FAILED"; - break; - case 3: - reasonCodeSymbolicName = "SSH_OPEN_UNKNOWN_CHANNEL_TYPE"; - break; - case 4: - reasonCodeSymbolicName = "SSH_OPEN_RESOURCE_SHORTAGE"; - break; - default: - reasonCodeSymbolicName = "UNKNOWN REASON CODE (" + reasonCode + ")"; - } - - StringBuffer descriptionBuffer = new StringBuffer(); - descriptionBuffer.append(description); - - for (int i = 0; i < descriptionBuffer.length(); i++) - { - char cc = descriptionBuffer.charAt(i); - - if ((cc >= 32) && (cc <= 126)) - continue; - descriptionBuffer.setCharAt(i, '\uFFFD'); - } - - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("The server refused to open the channel (" + reasonCodeSymbolicName + ", '" - + descriptionBuffer.toString() + "')"); - c.notifyAll(); - } - - if (log.isEnabled()) - log.log(50, "Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel " + id + ")"); - } - - public void msgGlobalRequest(byte[] msg, int msglen) throws IOException - { - /* Currently we do not support any kind of global request */ - - TypesReader tr = new TypesReader(msg, 0, msglen); - - tr.readByte(); // skip packet type - String requestName = tr.readString(); - boolean wantReply = tr.readBoolean(); - - if (wantReply) - { - byte[] reply_failure = new byte[1]; - reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE; - - tm.sendAsynchronousMessage(reply_failure); - } - - /* We do not clean up the requestName String - that is OK for debug */ - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_GLOBAL_REQUEST (" + requestName + ")"); - } - - public void msgGlobalSuccess() throws IOException - { - synchronized (channels) - { - globalSuccessCounter++; - channels.notifyAll(); - } - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_REQUEST_SUCCESS"); - } - - public void msgGlobalFailure() throws IOException - { - synchronized (channels) - { - globalFailedCounter++; - channels.notifyAll(); - } - - if (log.isEnabled()) - log.log(80, "Got SSH_MSG_REQUEST_FAILURE"); - } - - public void handleMessage(byte[] msg, int msglen) throws IOException - { - if (msg == null) - { - if (log.isEnabled()) - log.log(50, "HandleMessage: got shutdown"); - - synchronized (listenerThreads) - { - for (int i = 0; i < listenerThreads.size(); i++) - { - IChannelWorkerThread lat = listenerThreads.elementAt(i); - lat.stopWorking(); - } - listenerThreadsAllowed = false; - } - - synchronized (channels) - { - shutdown = true; - - for (int i = 0; i < channels.size(); i++) - { - Channel c = channels.elementAt(i); - synchronized (c) - { - c.EOF = true; - c.state = Channel.STATE_CLOSED; - c.setReasonClosed("The connection is being shutdown"); - c.closeMessageRecv = true; /* - * You never know, perhaps - * we are waiting for a - * pending close message - * from the server... - */ - c.notifyAll(); - } - } - /* Works with J2ME */ - channels.setSize(0); - channels.trimToSize(); - channels.notifyAll(); /* Notify global response waiters */ - return; - } - } - - switch (msg[0]) - { - case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION: - msgChannelOpenConfirmation(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST: - msgChannelWindowAdjust(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_DATA: - msgChannelData(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA: - msgChannelExtendedData(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_REQUEST: - msgChannelRequest(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_EOF: - msgChannelEOF(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_OPEN: - msgChannelOpen(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_CLOSE: - msgChannelClose(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_SUCCESS: - msgChannelSuccess(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_FAILURE: - msgChannelFailure(msg, msglen); - break; - case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE: - msgChannelOpenFailure(msg, msglen); - break; - case Packets.SSH_MSG_GLOBAL_REQUEST: - msgGlobalRequest(msg, msglen); - break; - case Packets.SSH_MSG_REQUEST_SUCCESS: - msgGlobalSuccess(); - break; - case Packets.SSH_MSG_REQUEST_FAILURE: - msgGlobalFailure(); - break; - default: - throw new IOException("Cannot handle unknown channel message " + (msg[0] & 0xff)); - } - } -} diff --git a/src/com/trilead/ssh2/channel/ChannelOutputStream.java b/src/com/trilead/ssh2/channel/ChannelOutputStream.java deleted file mode 100644 index c1d56e8..0000000 --- a/src/com/trilead/ssh2/channel/ChannelOutputStream.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * ChannelOutputStream. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ChannelOutputStream.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public final class ChannelOutputStream extends OutputStream -{ - Channel c; - - private byte[] writeBuffer; - - boolean isClosed = false; - - ChannelOutputStream(Channel c) - { - this.c = c; - writeBuffer = new byte[1]; - } - - public void write(int b) throws IOException - { - writeBuffer[0] = (byte) b; - - write(writeBuffer, 0, 1); - } - - public void close() throws IOException - { - if (isClosed == false) - { - isClosed = true; - c.cm.sendEOF(c); - } - } - - public void flush() throws IOException - { - if (isClosed) - throw new IOException("This OutputStream is closed."); - - /* This is a no-op, since this stream is unbuffered */ - } - - public void write(byte[] b, int off, int len) throws IOException - { - if (isClosed) - throw new IOException("This OutputStream is closed."); - - if (b == null) - throw new NullPointerException(); - - if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) - throw new IndexOutOfBoundsException(); - - if (len == 0) - return; - - c.cm.sendData(c, b, off, len); - } - - public void write(byte[] b) throws IOException - { - write(b, 0, b.length); - } -} diff --git a/src/com/trilead/ssh2/channel/DynamicAcceptThread.java b/src/com/trilead/ssh2/channel/DynamicAcceptThread.java deleted file mode 100644 index ef3a3d0..0000000 --- a/src/com/trilead/ssh2/channel/DynamicAcceptThread.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.io.PushbackInputStream; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.NoRouteToHostException; -import java.net.ServerSocket; -import java.net.Socket; - -import net.sourceforge.jsocks.Proxy; -import net.sourceforge.jsocks.ProxyMessage; -import net.sourceforge.jsocks.Socks4Message; -import net.sourceforge.jsocks.Socks5Message; -import net.sourceforge.jsocks.SocksException; -import net.sourceforge.jsocks.server.ServerAuthenticator; -import net.sourceforge.jsocks.server.ServerAuthenticatorNone; - -/** - * DynamicAcceptThread. - * - * @author Kenny Root - * @version $Id$ - */ -public class DynamicAcceptThread extends Thread implements IChannelWorkerThread { - private ChannelManager cm; - private ServerSocket ss; - - class DynamicAcceptRunnable implements Runnable { - private static final int idleTimeout = 180000; //3 minutes - - private ServerAuthenticator auth; - private Socket sock; - private InputStream in; - private OutputStream out; - private ProxyMessage msg; - - public DynamicAcceptRunnable(ServerAuthenticator auth, Socket sock) { - this.auth = auth; - this.sock = sock; - - setName("DynamicAcceptRunnable"); - } - - public void run() { - try { - startSession(); - } catch (IOException ioe) { - int error_code = Proxy.SOCKS_FAILURE; - - if (ioe instanceof SocksException) - error_code = ((SocksException) ioe).errCode; - else if (ioe instanceof NoRouteToHostException) - error_code = Proxy.SOCKS_HOST_UNREACHABLE; - else if (ioe instanceof ConnectException) - error_code = Proxy.SOCKS_CONNECTION_REFUSED; - else if (ioe instanceof InterruptedIOException) - error_code = Proxy.SOCKS_TTL_EXPIRE; - - if (error_code > Proxy.SOCKS_ADDR_NOT_SUPPORTED - || error_code < 0) { - error_code = Proxy.SOCKS_FAILURE; - } - - sendErrorMessage(error_code); - } finally { - if (auth != null) - auth.endSession(); - } - } - - private ProxyMessage readMsg(InputStream in) throws IOException { - PushbackInputStream push_in; - if (in instanceof PushbackInputStream) - push_in = (PushbackInputStream) in; - else - push_in = new PushbackInputStream(in); - - int version = push_in.read(); - push_in.unread(version); - - ProxyMessage msg; - - if (version == 5) { - msg = new Socks5Message(push_in, false); - } else if (version == 4) { - msg = new Socks4Message(push_in, false); - } else { - throw new SocksException(Proxy.SOCKS_FAILURE); - } - return msg; - } - - private void sendErrorMessage(int error_code) { - ProxyMessage err_msg; - if (msg instanceof Socks4Message) - err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED); - else - err_msg = new Socks5Message(error_code); - try { - err_msg.write(out); - } catch (IOException ioe) { - } - } - - private void handleRequest(ProxyMessage msg) throws IOException { - if (!auth.checkRequest(msg)) - throw new SocksException(Proxy.SOCKS_FAILURE); - - switch (msg.command) { - case Proxy.SOCKS_CMD_CONNECT: - onConnect(msg); - break; - default: - throw new SocksException(Proxy.SOCKS_CMD_NOT_SUPPORTED); - } - } - - private void startSession() throws IOException { - sock.setSoTimeout(idleTimeout); - - try { - auth = auth.startSession(sock); - } catch (IOException ioe) { - System.out.println("Could not start SOCKS session"); - ioe.printStackTrace(); - auth = null; - return; - } - - if (auth == null) { // Authentication failed - System.out.println("SOCKS auth failed"); - return; - } - - in = auth.getInputStream(); - out = auth.getOutputStream(); - - msg = readMsg(in); - handleRequest(msg); - } - - private void onConnect(ProxyMessage msg) throws IOException { - ProxyMessage response = null; - Channel cn = null; - StreamForwarder r2l = null; - StreamForwarder l2r = null; - - if (msg instanceof Socks5Message) { - response = new Socks5Message(Proxy.SOCKS_SUCCESS, (InetAddress)null, 0); - } else { - response = new Socks4Message(Socks4Message.REPLY_OK, (InetAddress)null, 0); - } - response.write(out); - - String destHost = msg.host; - if (msg.ip != null) - destHost = msg.ip.getHostAddress(); - - try { - /* - * This may fail, e.g., if the remote port is closed (in - * optimistic terms: not open yet) - */ - - cn = cm.openDirectTCPIPChannel(destHost, msg.port, - "127.0.0.1", 0); - - } catch (IOException e) { - /* - * Simply close the local socket and wait for the next incoming - * connection - */ - - try { - sock.close(); - } catch (IOException ignore) { - } - - return; - } - - try { - r2l = new StreamForwarder(cn, null, sock, cn.stdoutStream, out, "RemoteToLocal"); - l2r = new StreamForwarder(cn, r2l, sock, in, cn.stdinStream, "LocalToRemote"); - } catch (IOException e) { - try { - /* - * This message is only visible during debugging, since we - * discard the channel immediatelly - */ - cn.cm.closeChannel(cn, - "Weird error during creation of StreamForwarder (" - + e.getMessage() + ")", true); - } catch (IOException ignore) { - } - - return; - } - - r2l.setDaemon(true); - l2r.setDaemon(true); - r2l.start(); - l2r.start(); - } - } - - public DynamicAcceptThread(ChannelManager cm, int local_port) - throws IOException { - this.cm = cm; - - setName("DynamicAcceptThread"); - - ss = new ServerSocket(local_port); - } - - public DynamicAcceptThread(ChannelManager cm, InetSocketAddress localAddress) - throws IOException { - this.cm = cm; - - ss = new ServerSocket(); - ss.bind(localAddress); - } - - @Override - public void run() { - try { - cm.registerThread(this); - } catch (IOException e) { - stopWorking(); - return; - } - - while (true) { - Socket sock = null; - - try { - sock = ss.accept(); - } catch (IOException e) { - stopWorking(); - return; - } - - DynamicAcceptRunnable dar = new DynamicAcceptRunnable(new ServerAuthenticatorNone(), sock); - Thread t = new Thread(dar); - t.setDaemon(true); - t.start(); - } - } - - /* - * (non-Javadoc) - * - * @see com.trilead.ssh2.channel.IChannelWorkerThread#stopWorking() - */ - public void stopWorking() { - try { - /* This will lead to an IOException in the ss.accept() call */ - ss.close(); - } catch (IOException e) { - } - } -} diff --git a/src/com/trilead/ssh2/channel/IChannelWorkerThread.java b/src/com/trilead/ssh2/channel/IChannelWorkerThread.java deleted file mode 100644 index bce9b1b..0000000 --- a/src/com/trilead/ssh2/channel/IChannelWorkerThread.java +++ /dev/null @@ -1,13 +0,0 @@ - -package com.trilead.ssh2.channel; - -/** - * IChannelWorkerThread. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: IChannelWorkerThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -interface IChannelWorkerThread -{ - public void stopWorking(); -} diff --git a/src/com/trilead/ssh2/channel/LocalAcceptThread.java b/src/com/trilead/ssh2/channel/LocalAcceptThread.java deleted file mode 100644 index 0d1bb35..0000000 --- a/src/com/trilead/ssh2/channel/LocalAcceptThread.java +++ /dev/null @@ -1,135 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; - -/** - * LocalAcceptThread. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: LocalAcceptThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class LocalAcceptThread extends Thread implements IChannelWorkerThread -{ - ChannelManager cm; - String host_to_connect; - int port_to_connect; - - final ServerSocket ss; - - public LocalAcceptThread(ChannelManager cm, int local_port, String host_to_connect, int port_to_connect) - throws IOException - { - this.cm = cm; - this.host_to_connect = host_to_connect; - this.port_to_connect = port_to_connect; - - ss = new ServerSocket(local_port); - } - - public LocalAcceptThread(ChannelManager cm, InetSocketAddress localAddress, String host_to_connect, - int port_to_connect) throws IOException - { - this.cm = cm; - this.host_to_connect = host_to_connect; - this.port_to_connect = port_to_connect; - - ss = new ServerSocket(); - ss.bind(localAddress); - } - - public void run() - { - try - { - cm.registerThread(this); - } - catch (IOException e) - { - stopWorking(); - return; - } - - while (true) - { - Socket s = null; - - try - { - s = ss.accept(); - } - catch (IOException e) - { - stopWorking(); - return; - } - - Channel cn = null; - StreamForwarder r2l = null; - StreamForwarder l2r = null; - - try - { - /* This may fail, e.g., if the remote port is closed (in optimistic terms: not open yet) */ - - cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, s.getInetAddress().getHostAddress(), s - .getPort()); - - } - catch (IOException e) - { - /* Simply close the local socket and wait for the next incoming connection */ - - try - { - s.close(); - } - catch (IOException ignore) - { - } - - continue; - } - - try - { - r2l = new StreamForwarder(cn, null, s, cn.stdoutStream, s.getOutputStream(), "RemoteToLocal"); - l2r = new StreamForwarder(cn, r2l, s, s.getInputStream(), cn.stdinStream, "LocalToRemote"); - } - catch (IOException e) - { - try - { - /* This message is only visible during debugging, since we discard the channel immediatelly */ - cn.cm.closeChannel(cn, "Weird error during creation of StreamForwarder (" + e.getMessage() + ")", - true); - } - catch (IOException ignore) - { - } - - continue; - } - - r2l.setDaemon(true); - l2r.setDaemon(true); - r2l.start(); - l2r.start(); - } - } - - public void stopWorking() - { - try - { - /* This will lead to an IOException in the ss.accept() call */ - ss.close(); - } - catch (IOException e) - { - } - } -} diff --git a/src/com/trilead/ssh2/channel/RemoteAcceptThread.java b/src/com/trilead/ssh2/channel/RemoteAcceptThread.java deleted file mode 100644 index 29b02b8..0000000 --- a/src/com/trilead/ssh2/channel/RemoteAcceptThread.java +++ /dev/null @@ -1,103 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.net.Socket; - -import com.trilead.ssh2.log.Logger; - - -/** - * RemoteAcceptThread. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: RemoteAcceptThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class RemoteAcceptThread extends Thread -{ - private static final Logger log = Logger.getLogger(RemoteAcceptThread.class); - - Channel c; - - String remoteConnectedAddress; - int remoteConnectedPort; - String remoteOriginatorAddress; - int remoteOriginatorPort; - String targetAddress; - int targetPort; - - Socket s; - - public RemoteAcceptThread(Channel c, String remoteConnectedAddress, int remoteConnectedPort, - String remoteOriginatorAddress, int remoteOriginatorPort, String targetAddress, int targetPort) - { - this.c = c; - this.remoteConnectedAddress = remoteConnectedAddress; - this.remoteConnectedPort = remoteConnectedPort; - this.remoteOriginatorAddress = remoteOriginatorAddress; - this.remoteOriginatorPort = remoteOriginatorPort; - this.targetAddress = targetAddress; - this.targetPort = targetPort; - - if (log.isEnabled()) - log.log(20, "RemoteAcceptThread: " + remoteConnectedAddress + "/" + remoteConnectedPort + ", R: " - + remoteOriginatorAddress + "/" + remoteOriginatorPort); - } - - public void run() - { - try - { - c.cm.sendOpenConfirmation(c); - - s = new Socket(targetAddress, targetPort); - - StreamForwarder r2l = new StreamForwarder(c, null, s, c.getStdoutStream(), s.getOutputStream(), - "RemoteToLocal"); - StreamForwarder l2r = new StreamForwarder(c, null, null, s.getInputStream(), c.getStdinStream(), - "LocalToRemote"); - - /* No need to start two threads, one can be executed in the current thread */ - - r2l.setDaemon(true); - r2l.start(); - l2r.run(); - - while (r2l.isAlive()) - { - try - { - r2l.join(); - } - catch (InterruptedException e) - { - } - } - - /* If the channel is already closed, then this is a no-op */ - - c.cm.closeChannel(c, "EOF on both streams reached.", true); - s.close(); - } - catch (IOException e) - { - log.log(50, "IOException in proxy code: " + e.getMessage()); - - try - { - c.cm.closeChannel(c, "IOException in proxy code (" + e.getMessage() + ")", true); - } - catch (IOException e1) - { - } - try - { - if (s != null) - s.close(); - } - catch (IOException e1) - { - } - } - } -} diff --git a/src/com/trilead/ssh2/channel/RemoteForwardingData.java b/src/com/trilead/ssh2/channel/RemoteForwardingData.java deleted file mode 100644 index d05378e..0000000 --- a/src/com/trilead/ssh2/channel/RemoteForwardingData.java +++ /dev/null @@ -1,17 +0,0 @@ - -package com.trilead.ssh2.channel; - -/** - * RemoteForwardingData. Data about a requested remote forwarding. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: RemoteForwardingData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class RemoteForwardingData -{ - public String bindAddress; - public int bindPort; - - String targetAddress; - int targetPort; -} diff --git a/src/com/trilead/ssh2/channel/RemoteX11AcceptThread.java b/src/com/trilead/ssh2/channel/RemoteX11AcceptThread.java deleted file mode 100644 index 9f99410..0000000 --- a/src/com/trilead/ssh2/channel/RemoteX11AcceptThread.java +++ /dev/null @@ -1,240 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; - -import com.trilead.ssh2.log.Logger; - - -/** - * RemoteX11AcceptThread. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: RemoteX11AcceptThread.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class RemoteX11AcceptThread extends Thread -{ - private static final Logger log = Logger.getLogger(RemoteX11AcceptThread.class); - - Channel c; - - String remoteOriginatorAddress; - int remoteOriginatorPort; - - Socket s; - - public RemoteX11AcceptThread(Channel c, String remoteOriginatorAddress, int remoteOriginatorPort) - { - this.c = c; - this.remoteOriginatorAddress = remoteOriginatorAddress; - this.remoteOriginatorPort = remoteOriginatorPort; - } - - public void run() - { - try - { - /* Send Open Confirmation */ - - c.cm.sendOpenConfirmation(c); - - /* Read startup packet from client */ - - OutputStream remote_os = c.getStdinStream(); - InputStream remote_is = c.getStdoutStream(); - - /* The following code is based on the protocol description given in: - * Scheifler/Gettys, - * X Windows System: Core and Extension Protocols: - * X Version 11, Releases 6 and 6.1 ISBN 1-55558-148-X - */ - - /* - * Client startup: - * - * 1 0X42 MSB first/0x6c lSB first - byteorder - * 1 - unused - * 2 card16 - protocol-major-version - * 2 card16 - protocol-minor-version - * 2 n - lenght of authorization-protocol-name - * 2 d - lenght of authorization-protocol-data - * 2 - unused - * string8 - authorization-protocol-name - * p - unused, p=pad(n) - * string8 - authorization-protocol-data - * q - unused, q=pad(d) - * - * pad(X) = (4 - (X mod 4)) mod 4 - * - * Server response: - * - * 1 (0 failed, 2 authenticate, 1 success) - * ... - * - */ - - /* Later on we will simply forward the first 6 header bytes to the "real" X11 server */ - - byte[] header = new byte[6]; - - if (remote_is.read(header) != 6) - throw new IOException("Unexpected EOF on X11 startup!"); - - if ((header[0] != 0x42) && (header[0] != 0x6c)) // 0x42 MSB first, 0x6C LSB first - throw new IOException("Unknown endian format in X11 message!"); - - /* Yes, I came up with this myself - shall I file an application for a patent? =) */ - - int idxMSB = (header[0] == 0x42) ? 0 : 1; - - /* Read authorization data header */ - - byte[] auth_buff = new byte[6]; - - if (remote_is.read(auth_buff) != 6) - throw new IOException("Unexpected EOF on X11 startup!"); - - int authProtocolNameLength = ((auth_buff[idxMSB] & 0xff) << 8) | (auth_buff[1 - idxMSB] & 0xff); - int authProtocolDataLength = ((auth_buff[2 + idxMSB] & 0xff) << 8) | (auth_buff[3 - idxMSB] & 0xff); - - if ((authProtocolNameLength > 256) || (authProtocolDataLength > 256)) - throw new IOException("Buggy X11 authorization data"); - - int authProtocolNamePadding = ((4 - (authProtocolNameLength % 4)) % 4); - int authProtocolDataPadding = ((4 - (authProtocolDataLength % 4)) % 4); - - byte[] authProtocolName = new byte[authProtocolNameLength]; - byte[] authProtocolData = new byte[authProtocolDataLength]; - - byte[] paddingBuffer = new byte[4]; - - if (remote_is.read(authProtocolName) != authProtocolNameLength) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolName)"); - - if (remote_is.read(paddingBuffer, 0, authProtocolNamePadding) != authProtocolNamePadding) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolNamePadding)"); - - if (remote_is.read(authProtocolData) != authProtocolDataLength) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolData)"); - - if (remote_is.read(paddingBuffer, 0, authProtocolDataPadding) != authProtocolDataPadding) - throw new IOException("Unexpected EOF on X11 startup! (authProtocolDataPadding)"); - - if ("MIT-MAGIC-COOKIE-1".equals(new String(authProtocolName, "ISO-8859-1")) == false) - throw new IOException("Unknown X11 authorization protocol!"); - - if (authProtocolDataLength != 16) - throw new IOException("Wrong data length for X11 authorization data!"); - - StringBuffer tmp = new StringBuffer(32); - for (int i = 0; i < authProtocolData.length; i++) - { - String digit2 = Integer.toHexString(authProtocolData[i] & 0xff); - tmp.append((digit2.length() == 2) ? digit2 : "0" + digit2); - } - String hexEncodedFakeCookie = tmp.toString(); - - /* Order is very important here - it may be that a certain x11 forwarding - * gets disabled right in the moment when we check and register our connection - * */ - - synchronized (c) - { - /* Please read the comment in Channel.java */ - c.hexX11FakeCookie = hexEncodedFakeCookie; - } - - /* Now check our fake cookie directory to see if we produced this cookie */ - - X11ServerData sd = c.cm.checkX11Cookie(hexEncodedFakeCookie); - - if (sd == null) - throw new IOException("Invalid X11 cookie received."); - - /* If the session which corresponds to this cookie is closed then we will - * detect this: the session's close code will close all channels - * with the session's assigned x11 fake cookie. - */ - - s = new Socket(sd.hostname, sd.port); - - OutputStream x11_os = s.getOutputStream(); - InputStream x11_is = s.getInputStream(); - - /* Now we are sending the startup packet to the real X11 server */ - - x11_os.write(header); - - if (sd.x11_magic_cookie == null) - { - byte[] emptyAuthData = new byte[6]; - /* empty auth data, hopefully you are connecting to localhost =) */ - x11_os.write(emptyAuthData); - } - else - { - if (sd.x11_magic_cookie.length != 16) - throw new IOException("The real X11 cookie has an invalid length!"); - - /* send X11 cookie specified by client */ - x11_os.write(auth_buff); - x11_os.write(authProtocolName); /* re-use */ - x11_os.write(paddingBuffer, 0, authProtocolNamePadding); - x11_os.write(sd.x11_magic_cookie); - x11_os.write(paddingBuffer, 0, authProtocolDataPadding); - } - - x11_os.flush(); - - /* Start forwarding traffic */ - - StreamForwarder r2l = new StreamForwarder(c, null, s, remote_is, x11_os, "RemoteToX11"); - StreamForwarder l2r = new StreamForwarder(c, null, null, x11_is, remote_os, "X11ToRemote"); - - /* No need to start two threads, one can be executed in the current thread */ - - r2l.setDaemon(true); - r2l.start(); - l2r.run(); - - while (r2l.isAlive()) - { - try - { - r2l.join(); - } - catch (InterruptedException e) - { - } - } - - /* If the channel is already closed, then this is a no-op */ - - c.cm.closeChannel(c, "EOF on both X11 streams reached.", true); - s.close(); - } - catch (IOException e) - { - log.log(50, "IOException in X11 proxy code: " + e.getMessage()); - - try - { - c.cm.closeChannel(c, "IOException in X11 proxy code (" + e.getMessage() + ")", true); - } - catch (IOException e1) - { - } - try - { - if (s != null) - s.close(); - } - catch (IOException e1) - { - } - } - } -} diff --git a/src/com/trilead/ssh2/channel/StreamForwarder.java b/src/com/trilead/ssh2/channel/StreamForwarder.java deleted file mode 100644 index e1afee8..0000000 --- a/src/com/trilead/ssh2/channel/StreamForwarder.java +++ /dev/null @@ -1,113 +0,0 @@ - -package com.trilead.ssh2.channel; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; - -/** - * A StreamForwarder forwards data between two given streams. - * If two StreamForwarder threads are used (one for each direction) - * then one can be configured to shutdown the underlying channel/socket - * if both threads have finished forwarding (EOF). - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: StreamForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class StreamForwarder extends Thread -{ - final OutputStream os; - final InputStream is; - final byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE]; - final Channel c; - final StreamForwarder sibling; - final Socket s; - final String mode; - - StreamForwarder(Channel c, StreamForwarder sibling, Socket s, InputStream is, OutputStream os, String mode) - throws IOException - { - this.is = is; - this.os = os; - this.mode = mode; - this.c = c; - this.sibling = sibling; - this.s = s; - } - - public void run() - { - try - { - while (true) - { - int len = is.read(buffer); - if (len <= 0) - break; - os.write(buffer, 0, len); - os.flush(); - } - } - catch (IOException ignore) - { - try - { - c.cm.closeChannel(c, "Closed due to exception in StreamForwarder (" + mode + "): " - + ignore.getMessage(), true); - } - catch (IOException e) - { - } - } - finally - { - try - { - os.close(); - } - catch (IOException e1) - { - } - try - { - is.close(); - } - catch (IOException e2) - { - } - - if (sibling != null) - { - while (sibling.isAlive()) - { - try - { - sibling.join(); - } - catch (InterruptedException e) - { - } - } - - try - { - c.cm.closeChannel(c, "StreamForwarder (" + mode + ") is cleaning up the connection", true); - } - catch (IOException e3) - { - } - } - - if (s != null) { - try - { - s.close(); - } - catch (IOException e1) - { - } - } - } - } -} diff --git a/src/com/trilead/ssh2/channel/X11ServerData.java b/src/com/trilead/ssh2/channel/X11ServerData.java deleted file mode 100644 index 041f9cb..0000000 --- a/src/com/trilead/ssh2/channel/X11ServerData.java +++ /dev/null @@ -1,16 +0,0 @@ - -package com.trilead.ssh2.channel; - -/** - * X11ServerData. Data regarding an x11 forwarding target. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: X11ServerData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - * - */ -public class X11ServerData -{ - public String hostname; - public int port; - public byte[] x11_magic_cookie; /* not the remote (fake) one, the local (real) one */ -} diff --git a/src/com/trilead/ssh2/compression/CompressionFactory.java b/src/com/trilead/ssh2/compression/CompressionFactory.java deleted file mode 100644 index 9f8d7ef..0000000 --- a/src/com/trilead/ssh2/compression/CompressionFactory.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2.compression; - -import java.util.Vector; - -/** - * @author Kenny Root - * - */ -public class CompressionFactory { - static class CompressorEntry - { - String type; - String compressorClass; - - public CompressorEntry(String type, String compressorClass) - { - this.type = type; - this.compressorClass = compressorClass; - } - } - - static Vector<CompressorEntry> compressors = new Vector<CompressorEntry>(); - - static - { - /* Higher Priority First */ - - compressors.addElement(new CompressorEntry("zlib", "com.trilead.ssh2.compression.Zlib")); - compressors.addElement(new CompressorEntry("zlib@openssh.com", "com.trilead.ssh2.compression.ZlibOpenSSH")); - compressors.addElement(new CompressorEntry("none", "")); - } - - public static String[] getDefaultCompressorList() - { - String list[] = new String[compressors.size()]; - for (int i = 0; i < compressors.size(); i++) - { - CompressorEntry ce = compressors.elementAt(i); - list[i] = new String(ce.type); - } - return list; - } - - public static void checkCompressorList(String[] compressorCandidates) - { - for (int i = 0; i < compressorCandidates.length; i++) - getEntry(compressorCandidates[i]); - } - - public static ICompressor createCompressor(String type) - { - try - { - CompressorEntry ce = getEntry(type); - if ("".equals(ce.compressorClass)) - return null; - - Class<?> cc = Class.forName(ce.compressorClass); - ICompressor cmp = (ICompressor) cc.newInstance(); - - return cmp; - } - catch (Exception e) - { - throw new IllegalArgumentException("Cannot instantiate " + type); - } - } - - private static CompressorEntry getEntry(String type) - { - for (int i = 0; i < compressors.size(); i++) - { - CompressorEntry ce = compressors.elementAt(i); - if (ce.type.equals(type)) - return ce; - } - throw new IllegalArgumentException("Unkown algorithm " + type); - } -} diff --git a/src/com/trilead/ssh2/compression/ICompressor.java b/src/com/trilead/ssh2/compression/ICompressor.java deleted file mode 100644 index 0b435b9..0000000 --- a/src/com/trilead/ssh2/compression/ICompressor.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2.compression; - -/** - * @author Kenny Root - * - */ -public interface ICompressor { - int getBufferSize(); - - int compress(byte[] buf, int start, int len, byte[] output); - - byte[] uncompress(byte[] buf, int start, int[] len); - - boolean canCompressPreauth(); -} diff --git a/src/com/trilead/ssh2/compression/Zlib.java b/src/com/trilead/ssh2/compression/Zlib.java deleted file mode 100644 index c1203a3..0000000 --- a/src/com/trilead/ssh2/compression/Zlib.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2.compression; - -import com.jcraft.jzlib.JZlib; -import com.jcraft.jzlib.ZStream; - -/** - * @author Kenny Root - * - */ -public class Zlib implements ICompressor { - static private final int DEFAULT_BUF_SIZE = 4096; - static private final int LEVEL = 5; - - private ZStream deflate; - private byte[] deflate_tmpbuf; - - private ZStream inflate; - private byte[] inflate_tmpbuf; - private byte[] inflated_buf; - - public Zlib() { - deflate = new ZStream(); - inflate = new ZStream(); - - deflate.deflateInit(LEVEL); - inflate.inflateInit(); - - deflate_tmpbuf = new byte[DEFAULT_BUF_SIZE]; - inflate_tmpbuf = new byte[DEFAULT_BUF_SIZE]; - inflated_buf = new byte[DEFAULT_BUF_SIZE]; - } - - public boolean canCompressPreauth() { - return true; - } - - public int getBufferSize() { - return DEFAULT_BUF_SIZE; - } - - public int compress(byte[] buf, int start, int len, byte[] output) { - deflate.next_in = buf; - deflate.next_in_index = start; - deflate.avail_in = len - start; - - if ((buf.length + 1024) > deflate_tmpbuf.length) { - deflate_tmpbuf = new byte[buf.length + 1024]; - } - - deflate.next_out = deflate_tmpbuf; - deflate.next_out_index = 0; - deflate.avail_out = output.length; - - if (deflate.deflate(JZlib.Z_PARTIAL_FLUSH) != JZlib.Z_OK) { - System.err.println("compress: compression failure"); - } - - if (deflate.avail_in > 0) { - System.err.println("compress: deflated data too large"); - } - - int outputlen = output.length - deflate.avail_out; - - System.arraycopy(deflate_tmpbuf, 0, output, 0, outputlen); - - return outputlen; - } - - public byte[] uncompress(byte[] buffer, int start, int[] length) { - int inflated_end = 0; - - inflate.next_in = buffer; - inflate.next_in_index = start; - inflate.avail_in = length[0]; - - while (true) { - inflate.next_out = inflate_tmpbuf; - inflate.next_out_index = 0; - inflate.avail_out = DEFAULT_BUF_SIZE; - int status = inflate.inflate(JZlib.Z_PARTIAL_FLUSH); - switch (status) { - case JZlib.Z_OK: - if (inflated_buf.length < inflated_end + DEFAULT_BUF_SIZE - - inflate.avail_out) { - byte[] foo = new byte[inflated_end + DEFAULT_BUF_SIZE - - inflate.avail_out]; - System.arraycopy(inflated_buf, 0, foo, 0, inflated_end); - inflated_buf = foo; - } - System.arraycopy(inflate_tmpbuf, 0, inflated_buf, inflated_end, - DEFAULT_BUF_SIZE - inflate.avail_out); - inflated_end += (DEFAULT_BUF_SIZE - inflate.avail_out); - length[0] = inflated_end; - break; - case JZlib.Z_BUF_ERROR: - if (inflated_end > buffer.length - start) { - byte[] foo = new byte[inflated_end + start]; - System.arraycopy(buffer, 0, foo, 0, start); - System.arraycopy(inflated_buf, 0, foo, start, inflated_end); - buffer = foo; - } else { - System.arraycopy(inflated_buf, 0, buffer, start, - inflated_end); - } - length[0] = inflated_end; - return buffer; - default: - System.err.println("uncompress: inflate returnd " + status); - return null; - } - } - } -} diff --git a/src/com/trilead/ssh2/compression/ZlibOpenSSH.java b/src/com/trilead/ssh2/compression/ZlibOpenSSH.java deleted file mode 100644 index 266fff9..0000000 --- a/src/com/trilead/ssh2/compression/ZlibOpenSSH.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.trilead.ssh2.compression; - -/** - * Defines how zlib@openssh.org compression works. - * See - * http://www.openssh.org/txt/draft-miller-secsh-compression-delayed-00.txt - * compression is disabled until userauth has occurred. - * - * @author Matt Johnston - * - */ -public class ZlibOpenSSH extends Zlib { - - public boolean canCompressPreauth() { - return false; - } - -} diff --git a/src/com/trilead/ssh2/crypto/Base64.java b/src/com/trilead/ssh2/crypto/Base64.java deleted file mode 100644 index 93770ac..0000000 --- a/src/com/trilead/ssh2/crypto/Base64.java +++ /dev/null @@ -1,148 +0,0 @@ - -package com.trilead.ssh2.crypto; - -import java.io.CharArrayWriter; -import java.io.IOException; - -/** - * Basic Base64 Support. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Base64.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class Base64 -{ - static final char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); - - public static char[] encode(byte[] content) - { - CharArrayWriter cw = new CharArrayWriter((4 * content.length) / 3); - - int idx = 0; - - int x = 0; - - for (int i = 0; i < content.length; i++) - { - if (idx == 0) - x = (content[i] & 0xff) << 16; - else if (idx == 1) - x = x | ((content[i] & 0xff) << 8); - else - x = x | (content[i] & 0xff); - - idx++; - - if (idx == 3) - { - cw.write(alphabet[x >> 18]); - cw.write(alphabet[(x >> 12) & 0x3f]); - cw.write(alphabet[(x >> 6) & 0x3f]); - cw.write(alphabet[x & 0x3f]); - - idx = 0; - } - } - - if (idx == 1) - { - cw.write(alphabet[x >> 18]); - cw.write(alphabet[(x >> 12) & 0x3f]); - cw.write('='); - cw.write('='); - } - - if (idx == 2) - { - cw.write(alphabet[x >> 18]); - cw.write(alphabet[(x >> 12) & 0x3f]); - cw.write(alphabet[(x >> 6) & 0x3f]); - cw.write('='); - } - - return cw.toCharArray(); - } - - public static byte[] decode(char[] message) throws IOException - { - byte buff[] = new byte[4]; - byte dest[] = new byte[message.length]; - - int bpos = 0; - int destpos = 0; - - for (int i = 0; i < message.length; i++) - { - int c = message[i]; - - if ((c == '\n') || (c == '\r') || (c == ' ') || (c == '\t')) - continue; - - if ((c >= 'A') && (c <= 'Z')) - { - buff[bpos++] = (byte) (c - 'A'); - } - else if ((c >= 'a') && (c <= 'z')) - { - buff[bpos++] = (byte) ((c - 'a') + 26); - } - else if ((c >= '0') && (c <= '9')) - { - buff[bpos++] = (byte) ((c - '0') + 52); - } - else if (c == '+') - { - buff[bpos++] = 62; - } - else if (c == '/') - { - buff[bpos++] = 63; - } - else if (c == '=') - { - buff[bpos++] = 64; - } - else - { - throw new IOException("Illegal char in base64 code."); - } - - if (bpos == 4) - { - bpos = 0; - - if (buff[0] == 64) - break; - - if (buff[1] == 64) - throw new IOException("Unexpected '=' in base64 code."); - - if (buff[2] == 64) - { - int v = (((buff[0] & 0x3f) << 6) | ((buff[1] & 0x3f))); - dest[destpos++] = (byte) (v >> 4); - break; - } - else if (buff[3] == 64) - { - int v = (((buff[0] & 0x3f) << 12) | ((buff[1] & 0x3f) << 6) | ((buff[2] & 0x3f))); - dest[destpos++] = (byte) (v >> 10); - dest[destpos++] = (byte) (v >> 2); - break; - } - else - { - int v = (((buff[0] & 0x3f) << 18) | ((buff[1] & 0x3f) << 12) | ((buff[2] & 0x3f) << 6) | ((buff[3] & 0x3f))); - dest[destpos++] = (byte) (v >> 16); - dest[destpos++] = (byte) (v >> 8); - dest[destpos++] = (byte) (v); - } - } - } - - byte[] res = new byte[destpos]; - System.arraycopy(dest, 0, res, 0, destpos); - - return res; - } -} diff --git a/src/com/trilead/ssh2/crypto/CryptoWishList.java b/src/com/trilead/ssh2/crypto/CryptoWishList.java deleted file mode 100644 index 86959e7..0000000 --- a/src/com/trilead/ssh2/crypto/CryptoWishList.java +++ /dev/null @@ -1,26 +0,0 @@ - -package com.trilead.ssh2.crypto; - -import com.trilead.ssh2.compression.CompressionFactory; -import com.trilead.ssh2.crypto.cipher.BlockCipherFactory; -import com.trilead.ssh2.crypto.digest.MAC; -import com.trilead.ssh2.transport.KexManager; - - -/** - * CryptoWishList. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: CryptoWishList.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class CryptoWishList -{ - public String[] kexAlgorithms = KexManager.getDefaultKexAlgorithmList(); - public String[] serverHostKeyAlgorithms = KexManager.getDefaultServerHostkeyAlgorithmList(); - public String[] c2s_enc_algos = BlockCipherFactory.getDefaultCipherList(); - public String[] s2c_enc_algos = BlockCipherFactory.getDefaultCipherList(); - public String[] c2s_mac_algos = MAC.getMacList(); - public String[] s2c_mac_algos = MAC.getMacList(); - public String[] c2s_comp_algos = CompressionFactory.getDefaultCompressorList(); - public String[] s2c_comp_algos = CompressionFactory.getDefaultCompressorList(); -} diff --git a/src/com/trilead/ssh2/crypto/KeyMaterial.java b/src/com/trilead/ssh2/crypto/KeyMaterial.java deleted file mode 100644 index 1dbd6c7..0000000 --- a/src/com/trilead/ssh2/crypto/KeyMaterial.java +++ /dev/null @@ -1,91 +0,0 @@ - -package com.trilead.ssh2.crypto; - - -import java.math.BigInteger; - -import com.trilead.ssh2.crypto.digest.HashForSSH2Types; - -/** - * Establishes key material for iv/key/mac (both directions). - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: KeyMaterial.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class KeyMaterial -{ - public byte[] initial_iv_client_to_server; - public byte[] initial_iv_server_to_client; - public byte[] enc_key_client_to_server; - public byte[] enc_key_server_to_client; - public byte[] integrity_key_client_to_server; - public byte[] integrity_key_server_to_client; - - private static byte[] calculateKey(HashForSSH2Types sh, BigInteger K, byte[] H, byte type, byte[] SessionID, - int keyLength) - { - byte[] res = new byte[keyLength]; - - int dglen = sh.getDigestLength(); - int numRounds = (keyLength + dglen - 1) / dglen; - - byte[][] tmp = new byte[numRounds][]; - - sh.reset(); - sh.updateBigInt(K); - sh.updateBytes(H); - sh.updateByte(type); - sh.updateBytes(SessionID); - - tmp[0] = sh.getDigest(); - - int off = 0; - int produced = Math.min(dglen, keyLength); - - System.arraycopy(tmp[0], 0, res, off, produced); - - keyLength -= produced; - off += produced; - - for (int i = 1; i < numRounds; i++) - { - sh.updateBigInt(K); - sh.updateBytes(H); - - for (int j = 0; j < i; j++) - sh.updateBytes(tmp[j]); - - tmp[i] = sh.getDigest(); - - produced = Math.min(dglen, keyLength); - System.arraycopy(tmp[i], 0, res, off, produced); - keyLength -= produced; - off += produced; - } - - return res; - } - - public static KeyMaterial create(String hashAlgo, byte[] H, BigInteger K, byte[] SessionID, int keyLengthCS, - int blockSizeCS, int macLengthCS, int keyLengthSC, int blockSizeSC, int macLengthSC) - throws IllegalArgumentException - { - KeyMaterial km = new KeyMaterial(); - - HashForSSH2Types sh = new HashForSSH2Types(hashAlgo); - - km.initial_iv_client_to_server = calculateKey(sh, K, H, (byte) 'A', SessionID, blockSizeCS); - - km.initial_iv_server_to_client = calculateKey(sh, K, H, (byte) 'B', SessionID, blockSizeSC); - - km.enc_key_client_to_server = calculateKey(sh, K, H, (byte) 'C', SessionID, keyLengthCS); - - km.enc_key_server_to_client = calculateKey(sh, K, H, (byte) 'D', SessionID, keyLengthSC); - - km.integrity_key_client_to_server = calculateKey(sh, K, H, (byte) 'E', SessionID, macLengthCS); - - km.integrity_key_server_to_client = calculateKey(sh, K, H, (byte) 'F', SessionID, macLengthSC); - - return km; - } -} diff --git a/src/com/trilead/ssh2/crypto/PEMDecoder.java b/src/com/trilead/ssh2/crypto/PEMDecoder.java deleted file mode 100644 index 5c0c2fd..0000000 --- a/src/com/trilead/ssh2/crypto/PEMDecoder.java +++ /dev/null @@ -1,494 +0,0 @@ - -package com.trilead.ssh2.crypto; - -import java.io.BufferedReader; -import java.io.CharArrayReader; -import java.io.IOException; -import java.math.BigInteger; -import java.security.DigestException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.spec.DSAPrivateKeySpec; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPrivateKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.security.spec.RSAPrivateKeySpec; -import java.security.spec.RSAPublicKeySpec; - -import com.trilead.ssh2.crypto.cipher.AES; -import com.trilead.ssh2.crypto.cipher.BlockCipher; -import com.trilead.ssh2.crypto.cipher.CBCMode; -import com.trilead.ssh2.crypto.cipher.DES; -import com.trilead.ssh2.crypto.cipher.DESede; -import com.trilead.ssh2.signature.ECDSASHA2Verify; - -/** - * PEM Support. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PEMDecoder.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class PEMDecoder -{ - public static final int PEM_RSA_PRIVATE_KEY = 1; - public static final int PEM_DSA_PRIVATE_KEY = 2; - public static final int PEM_EC_PRIVATE_KEY = 3; - - private static final int hexToInt(char c) - { - if ((c >= 'a') && (c <= 'f')) - { - return (c - 'a') + 10; - } - - if ((c >= 'A') && (c <= 'F')) - { - return (c - 'A') + 10; - } - - if ((c >= '0') && (c <= '9')) - { - return (c - '0'); - } - - throw new IllegalArgumentException("Need hex char"); - } - - private static byte[] hexToByteArray(String hex) - { - if (hex == null) - throw new IllegalArgumentException("null argument"); - - if ((hex.length() % 2) != 0) - throw new IllegalArgumentException("Uneven string length in hex encoding."); - - byte decoded[] = new byte[hex.length() / 2]; - - for (int i = 0; i < decoded.length; i++) - { - int hi = hexToInt(hex.charAt(i * 2)); - int lo = hexToInt(hex.charAt((i * 2) + 1)); - - decoded[i] = (byte) (hi * 16 + lo); - } - - return decoded; - } - - private static byte[] generateKeyFromPasswordSaltWithMD5(byte[] password, byte[] salt, int keyLen) - throws IOException - { - if (salt.length < 8) - throw new IllegalArgumentException("Salt needs to be at least 8 bytes for key generation."); - - MessageDigest md5; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("VM does not support MD5", e); - } - - byte[] key = new byte[keyLen]; - byte[] tmp = new byte[md5.getDigestLength()]; - - while (true) - { - md5.update(password, 0, password.length); - md5.update(salt, 0, 8); // ARGH we only use the first 8 bytes of the - // salt in this step. - // This took me two hours until I got AES-xxx running. - - int copy = (keyLen < tmp.length) ? keyLen : tmp.length; - - try { - md5.digest(tmp, 0, tmp.length); - } catch (DigestException e) { - IOException ex = new IOException("could not digest password"); - ex.initCause(e); - throw ex; - } - - System.arraycopy(tmp, 0, key, key.length - keyLen, copy); - - keyLen -= copy; - - if (keyLen == 0) - return key; - - md5.update(tmp, 0, tmp.length); - } - } - - private static byte[] removePadding(byte[] buff, int blockSize) throws IOException - { - /* Removes RFC 1423/PKCS #7 padding */ - - int rfc_1423_padding = buff[buff.length - 1] & 0xff; - - if ((rfc_1423_padding < 1) || (rfc_1423_padding > blockSize)) - throw new IOException("Decrypted PEM has wrong padding, did you specify the correct password?"); - - for (int i = 2; i <= rfc_1423_padding; i++) - { - if (buff[buff.length - i] != rfc_1423_padding) - throw new IOException("Decrypted PEM has wrong padding, did you specify the correct password?"); - } - - byte[] tmp = new byte[buff.length - rfc_1423_padding]; - System.arraycopy(buff, 0, tmp, 0, buff.length - rfc_1423_padding); - return tmp; - } - - public static final PEMStructure parsePEM(char[] pem) throws IOException - { - PEMStructure ps = new PEMStructure(); - - String line = null; - - BufferedReader br = new BufferedReader(new CharArrayReader(pem)); - - String endLine = null; - - while (true) - { - line = br.readLine(); - - if (line == null) - throw new IOException("Invalid PEM structure, '-----BEGIN...' missing"); - - line = line.trim(); - - if (line.startsWith("-----BEGIN DSA PRIVATE KEY-----")) - { - endLine = "-----END DSA PRIVATE KEY-----"; - ps.pemType = PEM_DSA_PRIVATE_KEY; - break; - } - - if (line.startsWith("-----BEGIN RSA PRIVATE KEY-----")) - { - endLine = "-----END RSA PRIVATE KEY-----"; - ps.pemType = PEM_RSA_PRIVATE_KEY; - break; - } - - if (line.startsWith("-----BEGIN EC PRIVATE KEY-----")) { - endLine = "-----END EC PRIVATE KEY-----"; - ps.pemType = PEM_EC_PRIVATE_KEY; - break; - } - } - - while (true) - { - line = br.readLine(); - - if (line == null) - throw new IOException("Invalid PEM structure, " + endLine + " missing"); - - line = line.trim(); - - int sem_idx = line.indexOf(':'); - - if (sem_idx == -1) - break; - - String name = line.substring(0, sem_idx + 1); - String value = line.substring(sem_idx + 1); - - String values[] = value.split(","); - - for (int i = 0; i < values.length; i++) - values[i] = values[i].trim(); - - // Proc-Type: 4,ENCRYPTED - // DEK-Info: DES-EDE3-CBC,579B6BE3E5C60483 - - if ("Proc-Type:".equals(name)) - { - ps.procType = values; - continue; - } - - if ("DEK-Info:".equals(name)) - { - ps.dekInfo = values; - continue; - } - /* Ignore line */ - } - - StringBuffer keyData = new StringBuffer(); - - while (true) - { - if (line == null) - throw new IOException("Invalid PEM structure, " + endLine + " missing"); - - line = line.trim(); - - if (line.startsWith(endLine)) - break; - - keyData.append(line); - - line = br.readLine(); - } - - char[] pem_chars = new char[keyData.length()]; - keyData.getChars(0, pem_chars.length, pem_chars, 0); - - ps.data = Base64.decode(pem_chars); - - if (ps.data.length == 0) - throw new IOException("Invalid PEM structure, no data available"); - - return ps; - } - - private static final void decryptPEM(PEMStructure ps, byte[] pw) throws IOException - { - if (ps.dekInfo == null) - throw new IOException("Broken PEM, no mode and salt given, but encryption enabled"); - - if (ps.dekInfo.length != 2) - throw new IOException("Broken PEM, DEK-Info is incomplete!"); - - String algo = ps.dekInfo[0]; - byte[] salt = hexToByteArray(ps.dekInfo[1]); - - BlockCipher bc = null; - - if (algo.equals("DES-EDE3-CBC")) - { - DESede des3 = new DESede(); - des3.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 24)); - bc = new CBCMode(des3, salt, false); - } - else if (algo.equals("DES-CBC")) - { - DES des = new DES(); - des.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 8)); - bc = new CBCMode(des, salt, false); - } - else if (algo.equals("AES-128-CBC")) - { - AES aes = new AES(); - aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 16)); - bc = new CBCMode(aes, salt, false); - } - else if (algo.equals("AES-192-CBC")) - { - AES aes = new AES(); - aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 24)); - bc = new CBCMode(aes, salt, false); - } - else if (algo.equals("AES-256-CBC")) - { - AES aes = new AES(); - aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 32)); - bc = new CBCMode(aes, salt, false); - } - else - { - throw new IOException("Cannot decrypt PEM structure, unknown cipher " + algo); - } - - if ((ps.data.length % bc.getBlockSize()) != 0) - throw new IOException("Invalid PEM structure, size of encrypted block is not a multiple of " - + bc.getBlockSize()); - - /* Now decrypt the content */ - - byte[] dz = new byte[ps.data.length]; - - for (int i = 0; i < ps.data.length / bc.getBlockSize(); i++) - { - bc.transformBlock(ps.data, i * bc.getBlockSize(), dz, i * bc.getBlockSize()); - } - - /* Now check and remove RFC 1423/PKCS #7 padding */ - - dz = removePadding(dz, bc.getBlockSize()); - - ps.data = dz; - ps.dekInfo = null; - ps.procType = null; - } - - public static final boolean isPEMEncrypted(PEMStructure ps) throws IOException - { - if (ps.procType == null) - return false; - - if (ps.procType.length != 2) - throw new IOException("Unknown Proc-Type field."); - - if ("4".equals(ps.procType[0]) == false) - throw new IOException("Unknown Proc-Type field (" + ps.procType[0] + ")"); - - if ("ENCRYPTED".equals(ps.procType[1])) - return true; - - return false; - } - - public static KeyPair decode(char[] pem, String password) throws IOException - { - PEMStructure ps = parsePEM(pem); - return decode(ps, password); - } - - public static KeyPair decode(PEMStructure ps, String password) throws IOException - { - if (isPEMEncrypted(ps)) - { - if (password == null) - throw new IOException("PEM is encrypted, but no password was specified"); - - decryptPEM(ps, password.getBytes("ISO-8859-1")); - } - - if (ps.pemType == PEM_DSA_PRIVATE_KEY) - { - SimpleDERReader dr = new SimpleDERReader(ps.data); - - byte[] seq = dr.readSequenceAsByteArray(); - - if (dr.available() != 0) - throw new IOException("Padding in DSA PRIVATE KEY DER stream."); - - dr.resetInput(seq); - - BigInteger version = dr.readInt(); - - if (version.compareTo(BigInteger.ZERO) != 0) - throw new IOException("Wrong version (" + version + ") in DSA PRIVATE KEY DER stream."); - - BigInteger p = dr.readInt(); - BigInteger q = dr.readInt(); - BigInteger g = dr.readInt(); - BigInteger y = dr.readInt(); - BigInteger x = dr.readInt(); - - if (dr.available() != 0) - throw new IOException("Padding in DSA PRIVATE KEY DER stream."); - - DSAPrivateKeySpec privSpec = new DSAPrivateKeySpec(x, p, q, g); - DSAPublicKeySpec pubSpec = new DSAPublicKeySpec(y, p, q, g); - - return generateKeyPair("DSA", privSpec, pubSpec); - } - - if (ps.pemType == PEM_RSA_PRIVATE_KEY) - { - SimpleDERReader dr = new SimpleDERReader(ps.data); - - byte[] seq = dr.readSequenceAsByteArray(); - - if (dr.available() != 0) - throw new IOException("Padding in RSA PRIVATE KEY DER stream."); - - dr.resetInput(seq); - - BigInteger version = dr.readInt(); - - if ((version.compareTo(BigInteger.ZERO) != 0) && (version.compareTo(BigInteger.ONE) != 0)) - throw new IOException("Wrong version (" + version + ") in RSA PRIVATE KEY DER stream."); - - BigInteger n = dr.readInt(); - BigInteger e = dr.readInt(); - BigInteger d = dr.readInt(); - // TODO: is this right? - BigInteger primeP = dr.readInt(); - BigInteger primeQ = dr.readInt(); - BigInteger expP = dr.readInt(); - BigInteger expQ = dr.readInt(); - BigInteger coeff = dr.readInt(); - - RSAPrivateKeySpec privSpec = new RSAPrivateCrtKeySpec(n, e, d, primeP, primeQ, expP, expQ, coeff); - RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(n, e); - - return generateKeyPair("RSA", privSpec, pubSpec); - } - - if (ps.pemType == PEM_EC_PRIVATE_KEY) { - SimpleDERReader dr = new SimpleDERReader(ps.data); - - byte[] seq = dr.readSequenceAsByteArray(); - - if (dr.available() != 0) - throw new IOException("Padding in EC PRIVATE KEY DER stream."); - - dr.resetInput(seq); - - BigInteger version = dr.readInt(); - - if ((version.compareTo(BigInteger.ONE) != 0)) - throw new IOException("Wrong version (" + version + ") in EC PRIVATE KEY DER stream."); - - byte[] privateBytes = dr.readOctetString(); - - String curveOid = null; - byte[] publicBytes = null; - while (dr.available() > 0) { - int type = dr.readConstructedType(); - SimpleDERReader cr = dr.readConstructed(); - switch (type) { - case 0: - curveOid = cr.readOid(); - break; - case 1: - publicBytes = cr.readOctetString(); - break; - } - } - - ECParameterSpec params = ECDSASHA2Verify.getCurveForOID(curveOid); - if (params == null) - throw new IOException("invalid OID"); - - BigInteger s = new BigInteger(privateBytes); - byte[] publicBytesSlice = new byte[publicBytes.length - 1]; - System.arraycopy(publicBytes, 1, publicBytesSlice, 0, publicBytesSlice.length); - ECPoint w = ECDSASHA2Verify.decodeECPoint(publicBytesSlice, params.getCurve()); - - ECPrivateKeySpec privSpec = new ECPrivateKeySpec(s, params); - ECPublicKeySpec pubSpec = new ECPublicKeySpec(w, params); - - return generateKeyPair("EC", privSpec, pubSpec); - } - - throw new IOException("PEM problem: it is of unknown type"); - } - - /** - * Generate a {@code KeyPair} given an {@code algorithm} and {@code KeySpec}. - */ - private static KeyPair generateKeyPair(String algorithm, KeySpec privSpec, KeySpec pubSpec) - throws IOException { - try { - final KeyFactory kf = KeyFactory.getInstance(algorithm); - final PublicKey pubKey = kf.generatePublic(pubSpec); - final PrivateKey privKey = kf.generatePrivate(privSpec); - return new KeyPair(pubKey, privKey); - } catch (NoSuchAlgorithmException ex) { - IOException ioex = new IOException(); - ioex.initCause(ex); - throw ioex; - } catch (InvalidKeySpecException ex) { - IOException ioex = new IOException("invalid keyspec"); - ioex.initCause(ex); - throw ioex; - } - } -} diff --git a/src/com/trilead/ssh2/crypto/PEMStructure.java b/src/com/trilead/ssh2/crypto/PEMStructure.java deleted file mode 100644 index 83fb799..0000000 --- a/src/com/trilead/ssh2/crypto/PEMStructure.java +++ /dev/null @@ -1,17 +0,0 @@ - -package com.trilead.ssh2.crypto; - -/** - * Parsed PEM structure. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PEMStructure.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ - -public class PEMStructure -{ - public int pemType; - String dekInfo[]; - String procType[]; - public byte[] data; -}
\ No newline at end of file diff --git a/src/com/trilead/ssh2/crypto/SimpleDERReader.java b/src/com/trilead/ssh2/crypto/SimpleDERReader.java deleted file mode 100644 index ff8112a..0000000 --- a/src/com/trilead/ssh2/crypto/SimpleDERReader.java +++ /dev/null @@ -1,229 +0,0 @@ -package com.trilead.ssh2.crypto; - -import java.io.IOException; - -import java.math.BigInteger; - -/** - * SimpleDERReader. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: SimpleDERReader.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class SimpleDERReader -{ - private static final int CONSTRUCTED = 0x20; - - byte[] buffer; - int pos; - int count; - - public SimpleDERReader(byte[] b) - { - resetInput(b); - } - - public SimpleDERReader(byte[] b, int off, int len) - { - resetInput(b, off, len); - } - - public void resetInput(byte[] b) - { - resetInput(b, 0, b.length); - } - - public void resetInput(byte[] b, int off, int len) - { - buffer = b; - pos = off; - count = len; - } - - private byte readByte() throws IOException - { - if (count <= 0) - throw new IOException("DER byte array: out of data"); - count--; - return buffer[pos++]; - } - - private byte[] readBytes(int len) throws IOException - { - if (len > count) - throw new IOException("DER byte array: out of data"); - - byte[] b = new byte[len]; - - System.arraycopy(buffer, pos, b, 0, len); - - pos += len; - count -= len; - - return b; - } - - public int available() - { - return count; - } - - private int readLength() throws IOException - { - int len = readByte() & 0xff; - - if ((len & 0x80) == 0) - return len; - - int remain = len & 0x7F; - - if (remain == 0) - return -1; - - len = 0; - - while (remain > 0) - { - len = len << 8; - len = len | (readByte() & 0xff); - remain--; - } - - return len; - } - - public int ignoreNextObject() throws IOException - { - int type = readByte() & 0xff; - - int len = readLength(); - - if ((len < 0) || len > available()) - throw new IOException("Illegal len in DER object (" + len + ")"); - - readBytes(len); - - return type; - } - - public BigInteger readInt() throws IOException - { - int type = readByte() & 0xff; - - if (type != 0x02) - throw new IOException("Expected DER Integer, but found type " + type); - - int len = readLength(); - - if ((len < 0) || len > available()) - throw new IOException("Illegal len in DER object (" + len + ")"); - - byte[] b = readBytes(len); - - BigInteger bi = new BigInteger(b); - - return bi; - } - - public int readConstructedType() throws IOException { - int type = readByte() & 0xff; - - if ((type & CONSTRUCTED) != CONSTRUCTED) - throw new IOException("Expected constructed type, but was " + type); - - return type & 0x1f; - } - - public SimpleDERReader readConstructed() throws IOException - { - int len = readLength(); - - if ((len < 0) || len > available()) - throw new IOException("Illegal len in DER object (" + len + ")"); - - SimpleDERReader cr = new SimpleDERReader(buffer, pos, len); - - pos += len; - count -= len; - - return cr; - } - - public byte[] readSequenceAsByteArray() throws IOException - { - int type = readByte() & 0xff; - - if (type != 0x30) - throw new IOException("Expected DER Sequence, but found type " + type); - - int len = readLength(); - - if ((len < 0) || len > available()) - throw new IOException("Illegal len in DER object (" + len + ")"); - - byte[] b = readBytes(len); - - return b; - } - - public String readOid() throws IOException - { - int type = readByte() & 0xff; - - if (type != 0x06) - throw new IOException("Expected DER OID, but found type " + type); - - int len = readLength(); - - if ((len < 1) || len > available()) - throw new IOException("Illegal len in DER object (" + len + ")"); - - byte[] b = readBytes(len); - - long value = 0; - - StringBuilder sb = new StringBuilder(64); - switch(b[0] / 40) { - case 0: - sb.append('0'); - break; - case 1: - sb.append('1'); - b[0] -= 40; - break; - default: - sb.append('2'); - b[0] -= 80; - break; - } - - for (int i = 0; i < len; i++) { - value = (value << 7) + (b[i] & 0x7F); - if ((b[i] & 0x80) == 0) { - sb.append('.'); - sb.append(value); - value = 0; - } - } - - return sb.toString(); - } - - public byte[] readOctetString() throws IOException - { - int type = readByte() & 0xff; - - if (type != 0x04 && type != 0x03) - throw new IOException("Expected DER Octetstring, but found type " + type); - - int len = readLength(); - - if ((len < 0) || len > available()) - throw new IOException("Illegal len in DER object (" + len + ")"); - - byte[] b = readBytes(len); - - return b; - } - -} diff --git a/src/com/trilead/ssh2/crypto/cipher/AES.java b/src/com/trilead/ssh2/crypto/cipher/AES.java deleted file mode 100644 index e89e4a6..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/AES.java +++ /dev/null @@ -1,698 +0,0 @@ - -package com.trilead.ssh2.crypto.cipher; - -/* - This file was shamelessly taken from the Bouncy Castle Crypto package. - Their licence file states the following: - - Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle - (http://www.bouncycastle.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - 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 THE - AUTHORS OR COPYRIGHT HOLDERS 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. - */ - -/** - * An implementation of the AES (Rijndael), from FIPS-197. - * <p> - * For further details see: <a - * href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/ - * </a>. - * - * This implementation is based on optimizations from Dr. Brian Gladman's paper - * and C code at <a - * href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/ - * </a> - * - * There are three levels of tradeoff of speed vs memory Because java has no - * preprocessor, they are written as three separate classes from which to choose - * - * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 - * 256 word tables for encryption and 4 for decryption. - * - * The middle performance version uses only one 256 word table for each, for a - * total of 2Kbytes, adding 12 rotate operations per round to compute the values - * contained in the other tables from the contents of the first - * - * The slowest version uses no static tables at all and computes the values in - * each round - * <p> - * This file contains the fast version with 8Kbytes of static tables for round - * precomputation - * - * @author See comments in the source file - * @version $Id: AES.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class AES implements BlockCipher -{ - // The S box - private static final byte[] S = { (byte) 99, (byte) 124, (byte) 119, (byte) 123, (byte) 242, (byte) 107, - (byte) 111, (byte) 197, (byte) 48, (byte) 1, (byte) 103, (byte) 43, (byte) 254, (byte) 215, (byte) 171, - (byte) 118, (byte) 202, (byte) 130, (byte) 201, (byte) 125, (byte) 250, (byte) 89, (byte) 71, (byte) 240, - (byte) 173, (byte) 212, (byte) 162, (byte) 175, (byte) 156, (byte) 164, (byte) 114, (byte) 192, (byte) 183, - (byte) 253, (byte) 147, (byte) 38, (byte) 54, (byte) 63, (byte) 247, (byte) 204, (byte) 52, (byte) 165, - (byte) 229, (byte) 241, (byte) 113, (byte) 216, (byte) 49, (byte) 21, (byte) 4, (byte) 199, (byte) 35, - (byte) 195, (byte) 24, (byte) 150, (byte) 5, (byte) 154, (byte) 7, (byte) 18, (byte) 128, (byte) 226, - (byte) 235, (byte) 39, (byte) 178, (byte) 117, (byte) 9, (byte) 131, (byte) 44, (byte) 26, (byte) 27, - (byte) 110, (byte) 90, (byte) 160, (byte) 82, (byte) 59, (byte) 214, (byte) 179, (byte) 41, (byte) 227, - (byte) 47, (byte) 132, (byte) 83, (byte) 209, (byte) 0, (byte) 237, (byte) 32, (byte) 252, (byte) 177, - (byte) 91, (byte) 106, (byte) 203, (byte) 190, (byte) 57, (byte) 74, (byte) 76, (byte) 88, (byte) 207, - (byte) 208, (byte) 239, (byte) 170, (byte) 251, (byte) 67, (byte) 77, (byte) 51, (byte) 133, (byte) 69, - (byte) 249, (byte) 2, (byte) 127, (byte) 80, (byte) 60, (byte) 159, (byte) 168, (byte) 81, (byte) 163, - (byte) 64, (byte) 143, (byte) 146, (byte) 157, (byte) 56, (byte) 245, (byte) 188, (byte) 182, (byte) 218, - (byte) 33, (byte) 16, (byte) 255, (byte) 243, (byte) 210, (byte) 205, (byte) 12, (byte) 19, (byte) 236, - (byte) 95, (byte) 151, (byte) 68, (byte) 23, (byte) 196, (byte) 167, (byte) 126, (byte) 61, (byte) 100, - (byte) 93, (byte) 25, (byte) 115, (byte) 96, (byte) 129, (byte) 79, (byte) 220, (byte) 34, (byte) 42, - (byte) 144, (byte) 136, (byte) 70, (byte) 238, (byte) 184, (byte) 20, (byte) 222, (byte) 94, (byte) 11, - (byte) 219, (byte) 224, (byte) 50, (byte) 58, (byte) 10, (byte) 73, (byte) 6, (byte) 36, (byte) 92, - (byte) 194, (byte) 211, (byte) 172, (byte) 98, (byte) 145, (byte) 149, (byte) 228, (byte) 121, (byte) 231, - (byte) 200, (byte) 55, (byte) 109, (byte) 141, (byte) 213, (byte) 78, (byte) 169, (byte) 108, (byte) 86, - (byte) 244, (byte) 234, (byte) 101, (byte) 122, (byte) 174, (byte) 8, (byte) 186, (byte) 120, (byte) 37, - (byte) 46, (byte) 28, (byte) 166, (byte) 180, (byte) 198, (byte) 232, (byte) 221, (byte) 116, (byte) 31, - (byte) 75, (byte) 189, (byte) 139, (byte) 138, (byte) 112, (byte) 62, (byte) 181, (byte) 102, (byte) 72, - (byte) 3, (byte) 246, (byte) 14, (byte) 97, (byte) 53, (byte) 87, (byte) 185, (byte) 134, (byte) 193, - (byte) 29, (byte) 158, (byte) 225, (byte) 248, (byte) 152, (byte) 17, (byte) 105, (byte) 217, (byte) 142, - (byte) 148, (byte) 155, (byte) 30, (byte) 135, (byte) 233, (byte) 206, (byte) 85, (byte) 40, (byte) 223, - (byte) 140, (byte) 161, (byte) 137, (byte) 13, (byte) 191, (byte) 230, (byte) 66, (byte) 104, (byte) 65, - (byte) 153, (byte) 45, (byte) 15, (byte) 176, (byte) 84, (byte) 187, (byte) 22, }; - - // The inverse S-box - private static final byte[] Si = { (byte) 82, (byte) 9, (byte) 106, (byte) 213, (byte) 48, (byte) 54, (byte) 165, - (byte) 56, (byte) 191, (byte) 64, (byte) 163, (byte) 158, (byte) 129, (byte) 243, (byte) 215, (byte) 251, - (byte) 124, (byte) 227, (byte) 57, (byte) 130, (byte) 155, (byte) 47, (byte) 255, (byte) 135, (byte) 52, - (byte) 142, (byte) 67, (byte) 68, (byte) 196, (byte) 222, (byte) 233, (byte) 203, (byte) 84, (byte) 123, - (byte) 148, (byte) 50, (byte) 166, (byte) 194, (byte) 35, (byte) 61, (byte) 238, (byte) 76, (byte) 149, - (byte) 11, (byte) 66, (byte) 250, (byte) 195, (byte) 78, (byte) 8, (byte) 46, (byte) 161, (byte) 102, - (byte) 40, (byte) 217, (byte) 36, (byte) 178, (byte) 118, (byte) 91, (byte) 162, (byte) 73, (byte) 109, - (byte) 139, (byte) 209, (byte) 37, (byte) 114, (byte) 248, (byte) 246, (byte) 100, (byte) 134, (byte) 104, - (byte) 152, (byte) 22, (byte) 212, (byte) 164, (byte) 92, (byte) 204, (byte) 93, (byte) 101, (byte) 182, - (byte) 146, (byte) 108, (byte) 112, (byte) 72, (byte) 80, (byte) 253, (byte) 237, (byte) 185, (byte) 218, - (byte) 94, (byte) 21, (byte) 70, (byte) 87, (byte) 167, (byte) 141, (byte) 157, (byte) 132, (byte) 144, - (byte) 216, (byte) 171, (byte) 0, (byte) 140, (byte) 188, (byte) 211, (byte) 10, (byte) 247, (byte) 228, - (byte) 88, (byte) 5, (byte) 184, (byte) 179, (byte) 69, (byte) 6, (byte) 208, (byte) 44, (byte) 30, - (byte) 143, (byte) 202, (byte) 63, (byte) 15, (byte) 2, (byte) 193, (byte) 175, (byte) 189, (byte) 3, - (byte) 1, (byte) 19, (byte) 138, (byte) 107, (byte) 58, (byte) 145, (byte) 17, (byte) 65, (byte) 79, - (byte) 103, (byte) 220, (byte) 234, (byte) 151, (byte) 242, (byte) 207, (byte) 206, (byte) 240, (byte) 180, - (byte) 230, (byte) 115, (byte) 150, (byte) 172, (byte) 116, (byte) 34, (byte) 231, (byte) 173, (byte) 53, - (byte) 133, (byte) 226, (byte) 249, (byte) 55, (byte) 232, (byte) 28, (byte) 117, (byte) 223, (byte) 110, - (byte) 71, (byte) 241, (byte) 26, (byte) 113, (byte) 29, (byte) 41, (byte) 197, (byte) 137, (byte) 111, - (byte) 183, (byte) 98, (byte) 14, (byte) 170, (byte) 24, (byte) 190, (byte) 27, (byte) 252, (byte) 86, - (byte) 62, (byte) 75, (byte) 198, (byte) 210, (byte) 121, (byte) 32, (byte) 154, (byte) 219, (byte) 192, - (byte) 254, (byte) 120, (byte) 205, (byte) 90, (byte) 244, (byte) 31, (byte) 221, (byte) 168, (byte) 51, - (byte) 136, (byte) 7, (byte) 199, (byte) 49, (byte) 177, (byte) 18, (byte) 16, (byte) 89, (byte) 39, - (byte) 128, (byte) 236, (byte) 95, (byte) 96, (byte) 81, (byte) 127, (byte) 169, (byte) 25, (byte) 181, - (byte) 74, (byte) 13, (byte) 45, (byte) 229, (byte) 122, (byte) 159, (byte) 147, (byte) 201, (byte) 156, - (byte) 239, (byte) 160, (byte) 224, (byte) 59, (byte) 77, (byte) 174, (byte) 42, (byte) 245, (byte) 176, - (byte) 200, (byte) 235, (byte) 187, (byte) 60, (byte) 131, (byte) 83, (byte) 153, (byte) 97, (byte) 23, - (byte) 43, (byte) 4, (byte) 126, (byte) 186, (byte) 119, (byte) 214, (byte) 38, (byte) 225, (byte) 105, - (byte) 20, (byte) 99, (byte) 85, (byte) 33, (byte) 12, (byte) 125, }; - - // vector used in calculating key schedule (powers of x in GF(256)) - private static final int[] rcon = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, - 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; - - // precomputation tables of calculations for rounds - private static final int[] T0 = { 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, - 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, - 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, - 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775, - 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551, - 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, 0x65232346, - 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, - 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, - 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, - 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, - 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, - 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, - 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, - 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, - 0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, - 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, - 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, - 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, - 0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, - 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, - 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac, - 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, - 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, - 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, - 0x05030306, 0x01f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, - 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, - 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, - 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, - 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c }; - - private static final int[] T1 = { 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, - 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, - 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, - 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, 0xb7b775c2, - 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4, - 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552, 0x23234665, - 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, - 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, - 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, - 0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, - 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, - 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, - 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, - 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, - 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, - 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, - 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, - 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, - 0xdbdbad76, 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, - 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, 0xe7e7d532, - 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa, - 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, - 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, - 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, - 0x03030605, 0xf6f6f701, 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, - 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, - 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, - 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, - 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a }; - - private static final int[] T2 = { 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, - 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, - 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, - 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, 0xb775c2b7, - 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5, - 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7, 0x23466523, - 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, - 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, - 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, - 0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, - 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, - 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, - 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, - 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, - 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, - 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, - 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, - 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, - 0xdbad76db, 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, - 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, 0xe7d532e7, - 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56, - 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, - 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, - 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, - 0x03060503, 0xf6f701f6, 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, - 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, - 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, - 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, - 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16 }; - - private static final int[] T3 = { 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, - 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, - 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, - 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, - 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5, - 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7, 0x46652323, - 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, - 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, - 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, - 0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, - 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, - 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, - 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, - 0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, - 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, - 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, - 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, - 0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, - 0xad76dbdb, 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, - 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, 0xd532e7e7, - 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656, - 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, - 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, - 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, - 0x06050303, 0xf701f6f6, 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, - 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x07898e8e, - 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, - 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, - 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616 }; - - private static final int[] Tinv0 = { 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, - 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, - 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, - 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, 0x6a89c275, - 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5, - 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 0x876cde94, - 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, - 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, - 0xd5be0506, 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, - 0x069f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x055dc471, 0x6fd40604, - 0xff155060, 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, - 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, - 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, - 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, - 0x1d171b12, 0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, - 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, - 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, - 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, - 0xef903322, 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, - 0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, 0xbe805d9f, - 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, 0xf418596e, - 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, - 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, - 0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, - 0x1b886a4c, 0xb81f2cc1, 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, - 0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, - 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, - 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, - 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0 }; - - private static final int[] Tinv1 = { 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, - 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, - 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, - 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, 0x89c2756a, - 0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 0x4adf6318, 0x311ae582, - 0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 0x6cde9487, - 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, - 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, - 0xbe0506d5, 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa, - 0x9f715e06, 0x106ebd51, 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f, - 0x155060ff, 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, - 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, - 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, - 0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, - 0x171b121d, 0x0d090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd, - 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca, - 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, - 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, - 0x903322ef, 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, - 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, 0x805d9fbe, - 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 0x18596ef4, - 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4, - 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, - 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x0496e4df, 0xb5d19ee3, - 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252, - 0x5610e933, 0x47d66d13, 0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed, - 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, - 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, - 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042 }; - - private static final int[] Tinv2 = { 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, - 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, - 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, - 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, 0xc2756a89, - 0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 0xdf63184a, 0x1ae58231, - 0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd, 0xde94876c, - 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, - 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c, 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, - 0x0506d5be, 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef, - 0x715e069f, 0x6ebd5110, 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x06046fd4, - 0x5060ff15, 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, - 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff, - 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, - 0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 0x93e20aba, 0xa0c0e52a, 0x223c43e0, - 0x1b121d17, 0x090e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, - 0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc, - 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, - 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, - 0x3322ef90, 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, - 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, 0x5d9fbe80, - 0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 0x596ef418, - 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, - 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, - 0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5, - 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, 0x67b35a1d, 0xdb9252d2, - 0x10e93356, 0xd66d1347, 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, - 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, - 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, - 0x0c08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257 }; - - private static final int[] Tinv3 = { 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, - 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, - 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, - 0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, 0x756a89c2, - 0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 0x63184adf, 0xe582311a, - 0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 0x94876cde, - 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, - 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, - 0x06d5be05, 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6, 0x0b39ec83, 0x40aaef60, - 0x5e069f71, 0xbd51106e, 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x046fd406, - 0x60ff1550, 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8, - 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, - 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, - 0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 0xe20aba93, 0xc0e52aa0, 0x3c43e022, - 0x121d171b, 0x0e0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, - 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31, - 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, - 0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, - 0x22ef9033, 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, - 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, 0x9fbe805d, - 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 0x6ef41859, - 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, - 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, - 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, - 0x4c1b886a, 0xc1b81f2c, 0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db, - 0xe9335610, 0x6d1347d6, 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c, - 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, - 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, - 0x08deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8 }; - - private final int shift(int r, int shift) - { - return (((r >>> shift) | (r << (32 - shift)))); - } - - /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ - - private static final int m1 = 0x80808080; - private static final int m2 = 0x7f7f7f7f; - private static final int m3 = 0x0000001b; - - private final int FFmulX(int x) - { - return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); - } - - /* - * The following defines provide alternative definitions of FFmulX that - * might give improved performance if a fast 32-bit multiply is not - * available. - * - * private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & - * m2) < < 1) ^ ((u >>> 3) | (u >>> 6)); } private static final int m4 = - * 0x1b1b1b1b; private int FFmulX(int x) { int u = x & m1; return ((x & m2) < < - * 1) ^ ((u - (u >>> 7)) & m4); } - * - */ - - private final int inv_mcol(int x) - { - int f2 = FFmulX(x); - int f4 = FFmulX(f2); - int f8 = FFmulX(f4); - int f9 = x ^ f8; - - return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24); - } - - private final int subWord(int x) - { - return (S[x & 255] & 255 | ((S[(x >> 8) & 255] & 255) << 8) | ((S[(x >> 16) & 255] & 255) << 16) | S[(x >> 24) & 255] << 24); - } - - /** - * Calculate the necessary round keys The number of calculations depends on - * key size and block size AES specified a fixed block size of 128 bits and - * key sizes 128/192/256 bits This code is written assuming those are the - * only possible values - */ - private final int[][] generateWorkingKey(byte[] key, boolean forEncryption) - { - int KC = key.length / 4; // key length in words - int t; - - if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length)) - { - throw new IllegalArgumentException("Key length not 128/192/256 bits."); - } - - ROUNDS = KC + 6; // This is not always true for the generalized - // Rijndael that allows larger block sizes - int[][] W = new int[ROUNDS + 1][4]; // 4 words in a block - - // - // copy the key into the round key array - // - - t = 0; - for (int i = 0; i < key.length; t++) - { - W[t >> 2][t & 3] = (key[i] & 0xff) | ((key[i + 1] & 0xff) << 8) | ((key[i + 2] & 0xff) << 16) - | (key[i + 3] << 24); - i += 4; - } - - // - // while not enough round key material calculated - // calculate new values - // - int k = (ROUNDS + 1) << 2; - for (int i = KC; (i < k); i++) - { - int temp = W[(i - 1) >> 2][(i - 1) & 3]; - if ((i % KC) == 0) - { - temp = subWord(shift(temp, 8)) ^ rcon[(i / KC) - 1]; - } - else if ((KC > 6) && ((i % KC) == 4)) - { - temp = subWord(temp); - } - - W[i >> 2][i & 3] = W[(i - KC) >> 2][(i - KC) & 3] ^ temp; - } - - if (!forEncryption) - { - for (int j = 1; j < ROUNDS; j++) - { - for (int i = 0; i < 4; i++) - { - W[j][i] = inv_mcol(W[j][i]); - } - } - } - - return W; - } - - private int ROUNDS; - private int[][] WorkingKey = null; - private int C0, C1, C2, C3; - private boolean doEncrypt; - - private static final int BLOCK_SIZE = 16; - - /** - * default constructor - 128 bit block size. - */ - public AES() - { - } - - /** - * initialise an AES cipher. - * - * @param forEncryption - * whether or not we are for encryption. - * @param key - * the key required to set up the cipher. - * @exception IllegalArgumentException - * if the params argument is inappropriate. - */ - - public final void init(boolean forEncryption, byte[] key) - { - WorkingKey = generateWorkingKey(key, forEncryption); - this.doEncrypt = forEncryption; - } - - public final String getAlgorithmName() - { - return "AES"; - } - - public final int getBlockSize() - { - return BLOCK_SIZE; - } - - public final int processBlock(byte[] in, int inOff, byte[] out, int outOff) - { - if (WorkingKey == null) - { - throw new IllegalStateException("AES engine not initialised"); - } - - if ((inOff + (32 / 2)) > in.length) - { - throw new IllegalArgumentException("input buffer too short"); - } - - if ((outOff + (32 / 2)) > out.length) - { - throw new IllegalArgumentException("output buffer too short"); - } - - if (doEncrypt) - { - unpackBlock(in, inOff); - encryptBlock(WorkingKey); - packBlock(out, outOff); - } - else - { - unpackBlock(in, inOff); - decryptBlock(WorkingKey); - packBlock(out, outOff); - } - - return BLOCK_SIZE; - } - - public final void reset() - { - } - - private final void unpackBlock(byte[] bytes, int off) - { - int index = off; - - C0 = (bytes[index++] & 0xff); - C0 |= (bytes[index++] & 0xff) << 8; - C0 |= (bytes[index++] & 0xff) << 16; - C0 |= bytes[index++] << 24; - - C1 = (bytes[index++] & 0xff); - C1 |= (bytes[index++] & 0xff) << 8; - C1 |= (bytes[index++] & 0xff) << 16; - C1 |= bytes[index++] << 24; - - C2 = (bytes[index++] & 0xff); - C2 |= (bytes[index++] & 0xff) << 8; - C2 |= (bytes[index++] & 0xff) << 16; - C2 |= bytes[index++] << 24; - - C3 = (bytes[index++] & 0xff); - C3 |= (bytes[index++] & 0xff) << 8; - C3 |= (bytes[index++] & 0xff) << 16; - C3 |= bytes[index++] << 24; - } - - private final void packBlock(byte[] bytes, int off) - { - int index = off; - - bytes[index++] = (byte) C0; - bytes[index++] = (byte) (C0 >> 8); - bytes[index++] = (byte) (C0 >> 16); - bytes[index++] = (byte) (C0 >> 24); - - bytes[index++] = (byte) C1; - bytes[index++] = (byte) (C1 >> 8); - bytes[index++] = (byte) (C1 >> 16); - bytes[index++] = (byte) (C1 >> 24); - - bytes[index++] = (byte) C2; - bytes[index++] = (byte) (C2 >> 8); - bytes[index++] = (byte) (C2 >> 16); - bytes[index++] = (byte) (C2 >> 24); - - bytes[index++] = (byte) C3; - bytes[index++] = (byte) (C3 >> 8); - bytes[index++] = (byte) (C3 >> 16); - bytes[index++] = (byte) (C3 >> 24); - } - - private final void encryptBlock(int[][] KW) - { - int r, r0, r1, r2, r3; - - C0 ^= KW[0][0]; - C1 ^= KW[0][1]; - C2 ^= KW[0][2]; - C3 ^= KW[0][3]; - - for (r = 1; r < ROUNDS - 1;) - { - r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[(C3 >> 24) & 255] ^ KW[r][0]; - r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[(C0 >> 24) & 255] ^ KW[r][1]; - r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[(C1 >> 24) & 255] ^ KW[r][2]; - r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[(C2 >> 24) & 255] ^ KW[r++][3]; - C0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[(r3 >> 24) & 255] ^ KW[r][0]; - C1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[(r0 >> 24) & 255] ^ KW[r][1]; - C2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[(r1 >> 24) & 255] ^ KW[r][2]; - C3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[(r2 >> 24) & 255] ^ KW[r++][3]; - } - - r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[(C3 >> 24) & 255] ^ KW[r][0]; - r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[(C0 >> 24) & 255] ^ KW[r][1]; - r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[(C1 >> 24) & 255] ^ KW[r][2]; - r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[(C2 >> 24) & 255] ^ KW[r++][3]; - - // the final round's table is a simple function of S so we don't use a - // whole other four tables for it - - C0 = (S[r0 & 255] & 255) ^ ((S[(r1 >> 8) & 255] & 255) << 8) ^ ((S[(r2 >> 16) & 255] & 255) << 16) - ^ (S[(r3 >> 24) & 255] << 24) ^ KW[r][0]; - C1 = (S[r1 & 255] & 255) ^ ((S[(r2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16) - ^ (S[(r0 >> 24) & 255] << 24) ^ KW[r][1]; - C2 = (S[r2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(r0 >> 16) & 255] & 255) << 16) - ^ (S[(r1 >> 24) & 255] << 24) ^ KW[r][2]; - C3 = (S[r3 & 255] & 255) ^ ((S[(r0 >> 8) & 255] & 255) << 8) ^ ((S[(r1 >> 16) & 255] & 255) << 16) - ^ (S[(r2 >> 24) & 255] << 24) ^ KW[r][3]; - - } - - private final void decryptBlock(int[][] KW) - { - int r, r0, r1, r2, r3; - - C0 ^= KW[ROUNDS][0]; - C1 ^= KW[ROUNDS][1]; - C2 ^= KW[ROUNDS][2]; - C3 ^= KW[ROUNDS][3]; - - for (r = ROUNDS - 1; r > 1;) - { - r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[(C1 >> 24) & 255] - ^ KW[r][0]; - r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[(C2 >> 24) & 255] - ^ KW[r][1]; - r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[(C3 >> 24) & 255] - ^ KW[r][2]; - r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[(C0 >> 24) & 255] - ^ KW[r--][3]; - C0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[(r1 >> 24) & 255] - ^ KW[r][0]; - C1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[(r2 >> 24) & 255] - ^ KW[r][1]; - C2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[(r3 >> 24) & 255] - ^ KW[r][2]; - C3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[(r0 >> 24) & 255] - ^ KW[r--][3]; - } - - r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[(C1 >> 24) & 255] ^ KW[r][0]; - r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[(C2 >> 24) & 255] ^ KW[r][1]; - r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[(C3 >> 24) & 255] ^ KW[r][2]; - r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[(C0 >> 24) & 255] ^ KW[r--][3]; - - // the final round's table is a simple function of Si so we don't use a - // whole other four tables for it - - C0 = (Si[r0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8) ^ ((Si[(r2 >> 16) & 255] & 255) << 16) - ^ (Si[(r1 >> 24) & 255] << 24) ^ KW[0][0]; - C1 = (Si[r1 & 255] & 255) ^ ((Si[(r0 >> 8) & 255] & 255) << 8) ^ ((Si[(r3 >> 16) & 255] & 255) << 16) - ^ (Si[(r2 >> 24) & 255] << 24) ^ KW[0][1]; - C2 = (Si[r2 & 255] & 255) ^ ((Si[(r1 >> 8) & 255] & 255) << 8) ^ ((Si[(r0 >> 16) & 255] & 255) << 16) - ^ (Si[(r3 >> 24) & 255] << 24) ^ KW[0][2]; - C3 = (Si[r3 & 255] & 255) ^ ((Si[(r2 >> 8) & 255] & 255) << 8) ^ ((Si[(r1 >> 16) & 255] & 255) << 16) - ^ (Si[(r0 >> 24) & 255] << 24) ^ KW[0][3]; - } - - public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) - { - processBlock(src, srcoff, dst, dstoff); - } -} diff --git a/src/com/trilead/ssh2/crypto/cipher/BlockCipher.java b/src/com/trilead/ssh2/crypto/cipher/BlockCipher.java deleted file mode 100644 index 4cc28ab..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/BlockCipher.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.trilead.ssh2.crypto.cipher; - -/** - * BlockCipher. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: BlockCipher.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public interface BlockCipher -{ - public void init(boolean forEncryption, byte[] key); - - public int getBlockSize(); - - public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff); -} diff --git a/src/com/trilead/ssh2/crypto/cipher/BlockCipherFactory.java b/src/com/trilead/ssh2/crypto/cipher/BlockCipherFactory.java deleted file mode 100644 index 6e386a5..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/BlockCipherFactory.java +++ /dev/null @@ -1,115 +0,0 @@ - -package com.trilead.ssh2.crypto.cipher; - -import java.util.Vector; - -/** - * BlockCipherFactory. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: BlockCipherFactory.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class BlockCipherFactory -{ - static class CipherEntry - { - String type; - int blocksize; - int keysize; - String cipherClass; - - public CipherEntry(String type, int blockSize, int keySize, String cipherClass) - { - this.type = type; - this.blocksize = blockSize; - this.keysize = keySize; - this.cipherClass = cipherClass; - } - } - - static Vector<CipherEntry> ciphers = new Vector<CipherEntry>(); - - static - { - /* Higher Priority First */ - - ciphers.addElement(new CipherEntry("aes256-ctr", 16, 32, "com.trilead.ssh2.crypto.cipher.AES")); - ciphers.addElement(new CipherEntry("aes192-ctr", 16, 24, "com.trilead.ssh2.crypto.cipher.AES")); - ciphers.addElement(new CipherEntry("aes128-ctr", 16, 16, "com.trilead.ssh2.crypto.cipher.AES")); - ciphers.addElement(new CipherEntry("blowfish-ctr", 8, 16, "com.trilead.ssh2.crypto.cipher.BlowFish")); - - ciphers.addElement(new CipherEntry("aes256-cbc", 16, 32, "com.trilead.ssh2.crypto.cipher.AES")); - ciphers.addElement(new CipherEntry("aes192-cbc", 16, 24, "com.trilead.ssh2.crypto.cipher.AES")); - ciphers.addElement(new CipherEntry("aes128-cbc", 16, 16, "com.trilead.ssh2.crypto.cipher.AES")); - ciphers.addElement(new CipherEntry("blowfish-cbc", 8, 16, "com.trilead.ssh2.crypto.cipher.BlowFish")); - - ciphers.addElement(new CipherEntry("3des-ctr", 8, 24, "com.trilead.ssh2.crypto.cipher.DESede")); - ciphers.addElement(new CipherEntry("3des-cbc", 8, 24, "com.trilead.ssh2.crypto.cipher.DESede")); - } - - public static String[] getDefaultCipherList() - { - String list[] = new String[ciphers.size()]; - for (int i = 0; i < ciphers.size(); i++) - { - CipherEntry ce = ciphers.elementAt(i); - list[i] = new String(ce.type); - } - return list; - } - - public static void checkCipherList(String[] cipherCandidates) - { - for (int i = 0; i < cipherCandidates.length; i++) - getEntry(cipherCandidates[i]); - } - - public static BlockCipher createCipher(String type, boolean encrypt, byte[] key, byte[] iv) - { - try - { - CipherEntry ce = getEntry(type); - Class cc = Class.forName(ce.cipherClass); - BlockCipher bc = (BlockCipher) cc.newInstance(); - - if (type.endsWith("-cbc")) - { - bc.init(encrypt, key); - return new CBCMode(bc, iv, encrypt); - } - else if (type.endsWith("-ctr")) - { - bc.init(true, key); - return new CTRMode(bc, iv, encrypt); - } - throw new IllegalArgumentException("Cannot instantiate " + type); - } - catch (Exception e) - { - throw new IllegalArgumentException("Cannot instantiate " + type); - } - } - - private static CipherEntry getEntry(String type) - { - for (int i = 0; i < ciphers.size(); i++) - { - CipherEntry ce = ciphers.elementAt(i); - if (ce.type.equals(type)) - return ce; - } - throw new IllegalArgumentException("Unkown algorithm " + type); - } - - public static int getBlockSize(String type) - { - CipherEntry ce = getEntry(type); - return ce.blocksize; - } - - public static int getKeySize(String type) - { - CipherEntry ce = getEntry(type); - return ce.keysize; - } -} diff --git a/src/com/trilead/ssh2/crypto/cipher/BlowFish.java b/src/com/trilead/ssh2/crypto/cipher/BlowFish.java deleted file mode 100644 index 0b2f295..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/BlowFish.java +++ /dev/null @@ -1,403 +0,0 @@ - -package com.trilead.ssh2.crypto.cipher; - -/* - This file was shamelessly taken from the Bouncy Castle Crypto package. - Their licence file states the following: - - Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle - (http://www.bouncycastle.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - 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 THE - AUTHORS OR COPYRIGHT HOLDERS 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. - */ - -/** - * A class that provides Blowfish key encryption operations, such as encoding - * data and generating keys. All the algorithms herein are from Applied - * Cryptography and implement a simplified cryptography interface. - * - * @author See comments in the source file - * @version $Id: BlowFish.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class BlowFish implements BlockCipher -{ - - private final static int[] KP = { 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, - 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, - 0xB5470917, 0x9216D5D9, 0x8979FB1B }, - - KS0 = { 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947, - 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, - 0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918, - 0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, - 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF, - 0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, - 0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60, - 0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, - 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2, - 0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, - 0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073, 0x401A449F, - 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, - 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, - 0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C, - 0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39, - 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, - 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB, - 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8, - 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC, - 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, - 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB, - 0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777, - 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, - 0xD2ADA8D9, 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, - 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, 0x2464369B, - 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9, - 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, - 0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, - 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A }, - - KS1 = { 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, - 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, - 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6, - 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, - 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A, - 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, - 0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, - 0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, - 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718, - 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, - 0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, 0x81AC77D6, - 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, - 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6, - 0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D, - 0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1, - 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, - 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90, - 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA, - 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E, - 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, - 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF, - 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA, - 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A, - 0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, - 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, 0x3372F092, - 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E, - 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705, - 0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, - 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 }, - - KS2 = { 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471, - 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF, - 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, - 0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, - 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35, - 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332, - 0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7, - 0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, - 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, - 0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60, - 0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62, - 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, - 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, - 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3, - 0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF, - 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, - 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, - 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057, 0xF0F7C086, - 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187, - 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, - 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E, - 0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09, - 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, - 0x2868F169, 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, - 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7, - 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188, - 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, - 0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, - 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 }, - - KS3 = { 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D, - 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, - 0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, - 0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, - 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3, - 0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, - 0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, - 0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, - 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15, - 0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, - 0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E, 0x379D5862, - 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, - 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, - 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB, - 0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671, - 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, - 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1, - 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A, - 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, - 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, - 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532, - 0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E, - 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5, - 0xF6FB2299, 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, - 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD, - 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3, - 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, - 0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, - 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 }; - - // ==================================== - // Useful constants - // ==================================== - - private static final int ROUNDS = 16; - private static final int BLOCK_SIZE = 8; // bytes = 64 bits - private static final int SBOX_SK = 256; - private static final int P_SZ = ROUNDS + 2; - - private final int[] S0, S1, S2, S3; // the s-boxes - private final int[] P; // the p-array - - private boolean doEncrypt = false; - - private byte[] workingKey = null; - - public BlowFish() - { - S0 = new int[SBOX_SK]; - S1 = new int[SBOX_SK]; - S2 = new int[SBOX_SK]; - S3 = new int[SBOX_SK]; - P = new int[P_SZ]; - } - - /** - * initialise a Blowfish cipher. - * - * @param encrypting - * whether or not we are for encryption. - * @param key - * the key required to set up the cipher. - * @exception IllegalArgumentException - * if the params argument is inappropriate. - */ - public void init(boolean encrypting, byte[] key) - { - this.doEncrypt = encrypting; - this.workingKey = key; - setKey(this.workingKey); - } - - public String getAlgorithmName() - { - return "Blowfish"; - } - - public final void transformBlock(byte[] in, int inOff, byte[] out, int outOff) - { - if (workingKey == null) - { - throw new IllegalStateException("Blowfish not initialised"); - } - - if (doEncrypt) - { - encryptBlock(in, inOff, out, outOff); - } - else - { - decryptBlock(in, inOff, out, outOff); - } - } - - public void reset() - { - } - - public int getBlockSize() - { - return BLOCK_SIZE; - } - - // ================================== - // Private Implementation - // ================================== - - private int F(int x) - { - return (((S0[(x >>> 24)] + S1[(x >>> 16) & 0xff]) ^ S2[(x >>> 8) & 0xff]) + S3[x & 0xff]); - } - - /** - * apply the encryption cycle to each value pair in the table. - */ - private void processTable(int xl, int xr, int[] table) - { - int size = table.length; - - for (int s = 0; s < size; s += 2) - { - xl ^= P[0]; - - for (int i = 1; i < ROUNDS; i += 2) - { - xr ^= F(xl) ^ P[i]; - xl ^= F(xr) ^ P[i + 1]; - } - - xr ^= P[ROUNDS + 1]; - - table[s] = xr; - table[s + 1] = xl; - - xr = xl; // end of cycle swap - xl = table[s]; - } - } - - private void setKey(byte[] key) - { - /* - * - comments are from _Applied Crypto_, Schneier, p338 please be - * careful comparing the two, AC numbers the arrays from 1, the enclosed - * code from 0. - * - * (1) Initialise the S-boxes and the P-array, with a fixed string This - * string contains the hexadecimal digits of pi (3.141...) - */ - System.arraycopy(KS0, 0, S0, 0, SBOX_SK); - System.arraycopy(KS1, 0, S1, 0, SBOX_SK); - System.arraycopy(KS2, 0, S2, 0, SBOX_SK); - System.arraycopy(KS3, 0, S3, 0, SBOX_SK); - - System.arraycopy(KP, 0, P, 0, P_SZ); - - /* - * (2) Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with - * the second 32-bits of the key, and so on for all bits of the key (up - * to P[17]). Repeatedly cycle through the key bits until the entire - * P-array has been XOR-ed with the key bits - */ - int keyLength = key.length; - int keyIndex = 0; - - for (int i = 0; i < P_SZ; i++) - { - // get the 32 bits of the key, in 4 * 8 bit chunks - int data = 0x0000000; - for (int j = 0; j < 4; j++) - { - // create a 32 bit block - data = (data << 8) | (key[keyIndex++] & 0xff); - - // wrap when we get to the end of the key - if (keyIndex >= keyLength) - { - keyIndex = 0; - } - } - // XOR the newly created 32 bit chunk onto the P-array - P[i] ^= data; - } - - /* - * (3) Encrypt the all-zero string with the Blowfish algorithm, using - * the subkeys described in (1) and (2) - * - * (4) Replace P1 and P2 with the output of step (3) - * - * (5) Encrypt the output of step(3) using the Blowfish algorithm, with - * the modified subkeys. - * - * (6) Replace P3 and P4 with the output of step (5) - * - * (7) Continue the process, replacing all elements of the P-array and - * then all four S-boxes in order, with the output of the continuously - * changing Blowfish algorithm - */ - - processTable(0, 0, P); - processTable(P[P_SZ - 2], P[P_SZ - 1], S0); - processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1); - processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2); - processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3); - } - - /** - * Encrypt the given input starting at the given offset and place the result - * in the provided buffer starting at the given offset. The input will be an - * exact multiple of our blocksize. - */ - private void encryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex) - { - int xl = BytesTo32bits(src, srcIndex); - int xr = BytesTo32bits(src, srcIndex + 4); - - xl ^= P[0]; - - for (int i = 1; i < ROUNDS; i += 2) - { - xr ^= F(xl) ^ P[i]; - xl ^= F(xr) ^ P[i + 1]; - } - - xr ^= P[ROUNDS + 1]; - - Bits32ToBytes(xr, dst, dstIndex); - Bits32ToBytes(xl, dst, dstIndex + 4); - } - - /** - * Decrypt the given input starting at the given offset and place the result - * in the provided buffer starting at the given offset. The input will be an - * exact multiple of our blocksize. - */ - private void decryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex) - { - int xl = BytesTo32bits(src, srcIndex); - int xr = BytesTo32bits(src, srcIndex + 4); - - xl ^= P[ROUNDS + 1]; - - for (int i = ROUNDS; i > 0; i -= 2) - { - xr ^= F(xl) ^ P[i]; - xl ^= F(xr) ^ P[i - 1]; - } - - xr ^= P[0]; - - Bits32ToBytes(xr, dst, dstIndex); - Bits32ToBytes(xl, dst, dstIndex + 4); - } - - private int BytesTo32bits(byte[] b, int i) - { - return ((b[i] & 0xff) << 24) | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | ((b[i + 3] & 0xff)); - } - - private void Bits32ToBytes(int in, byte[] b, int offset) - { - b[offset + 3] = (byte) in; - b[offset + 2] = (byte) (in >> 8); - b[offset + 1] = (byte) (in >> 16); - b[offset] = (byte) (in >> 24); - } - -} diff --git a/src/com/trilead/ssh2/crypto/cipher/CBCMode.java b/src/com/trilead/ssh2/crypto/cipher/CBCMode.java deleted file mode 100644 index 0ae51b3..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/CBCMode.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.trilead.ssh2.crypto.cipher; - -/** - * CBCMode. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: CBCMode.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class CBCMode implements BlockCipher -{ - BlockCipher tc; - int blockSize; - boolean doEncrypt; - - byte[] cbc_vector; - byte[] tmp_vector; - - public void init(boolean forEncryption, byte[] key) - { - } - - public CBCMode(BlockCipher tc, byte[] iv, boolean doEncrypt) - throws IllegalArgumentException - { - this.tc = tc; - this.blockSize = tc.getBlockSize(); - this.doEncrypt = doEncrypt; - - if (this.blockSize != iv.length) - throw new IllegalArgumentException("IV must be " + blockSize - + " bytes long! (currently " + iv.length + ")"); - - this.cbc_vector = new byte[blockSize]; - this.tmp_vector = new byte[blockSize]; - System.arraycopy(iv, 0, cbc_vector, 0, blockSize); - } - - public int getBlockSize() - { - return blockSize; - } - - private void encryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff) - { - for (int i = 0; i < blockSize; i++) - cbc_vector[i] ^= src[srcoff + i]; - - tc.transformBlock(cbc_vector, 0, dst, dstoff); - - System.arraycopy(dst, dstoff, cbc_vector, 0, blockSize); - } - - private void decryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff) - { - /* Assume the worst, src and dst are overlapping... */ - - System.arraycopy(src, srcoff, tmp_vector, 0, blockSize); - - tc.transformBlock(src, srcoff, dst, dstoff); - - for (int i = 0; i < blockSize; i++) - dst[dstoff + i] ^= cbc_vector[i]; - - /* ...that is why we need a tmp buffer. */ - - byte[] swap = cbc_vector; - cbc_vector = tmp_vector; - tmp_vector = swap; - } - - public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) - { - if (doEncrypt) - encryptBlock(src, srcoff, dst, dstoff); - else - decryptBlock(src, srcoff, dst, dstoff); - } -} diff --git a/src/com/trilead/ssh2/crypto/cipher/CTRMode.java b/src/com/trilead/ssh2/crypto/cipher/CTRMode.java deleted file mode 100644 index 8541c8d..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/CTRMode.java +++ /dev/null @@ -1,62 +0,0 @@ - -package com.trilead.ssh2.crypto.cipher; - -/** - * This is CTR mode as described in draft-ietf-secsh-newmodes-XY.txt - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: CTRMode.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class CTRMode implements BlockCipher -{ - byte[] X; - byte[] Xenc; - - BlockCipher bc; - int blockSize; - boolean doEncrypt; - - int count = 0; - - public void init(boolean forEncryption, byte[] key) - { - } - - public CTRMode(BlockCipher tc, byte[] iv, boolean doEnc) throws IllegalArgumentException - { - bc = tc; - blockSize = bc.getBlockSize(); - doEncrypt = doEnc; - - if (blockSize != iv.length) - throw new IllegalArgumentException("IV must be " + blockSize + " bytes long! (currently " + iv.length + ")"); - - X = new byte[blockSize]; - Xenc = new byte[blockSize]; - - System.arraycopy(iv, 0, X, 0, blockSize); - } - - public final int getBlockSize() - { - return blockSize; - } - - public final void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) - { - bc.transformBlock(X, 0, Xenc, 0); - - for (int i = 0; i < blockSize; i++) - { - dst[dstoff + i] = (byte) (src[srcoff + i] ^ Xenc[i]); - } - - for (int i = (blockSize - 1); i >= 0; i--) - { - X[i]++; - if (X[i] != 0) - break; - - } - } -} diff --git a/src/com/trilead/ssh2/crypto/cipher/CipherInputStream.java b/src/com/trilead/ssh2/crypto/cipher/CipherInputStream.java deleted file mode 100644 index c9055ab..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/CipherInputStream.java +++ /dev/null @@ -1,144 +0,0 @@ - -package com.trilead.ssh2.crypto.cipher; - -import java.io.IOException; -import java.io.InputStream; - -/** - * CipherInputStream. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: CipherInputStream.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class CipherInputStream -{ - BlockCipher currentCipher; - InputStream bi; - byte[] buffer; - byte[] enc; - int blockSize; - int pos; - - /* - * We cannot use java.io.BufferedInputStream, since that is not available in - * J2ME. Everything could be improved alot here. - */ - - final int BUFF_SIZE = 2048; - byte[] input_buffer = new byte[BUFF_SIZE]; - int input_buffer_pos = 0; - int input_buffer_size = 0; - - public CipherInputStream(BlockCipher tc, InputStream bi) - { - this.bi = bi; - changeCipher(tc); - } - - private int fill_buffer() throws IOException - { - input_buffer_pos = 0; - input_buffer_size = bi.read(input_buffer, 0, BUFF_SIZE); - return input_buffer_size; - } - - private int internal_read(byte[] b, int off, int len) throws IOException - { - if (input_buffer_size < 0) - return -1; - - if (input_buffer_pos >= input_buffer_size) - { - if (fill_buffer() <= 0) - return -1; - } - - int avail = input_buffer_size - input_buffer_pos; - int thiscopy = (len > avail) ? avail : len; - - System.arraycopy(input_buffer, input_buffer_pos, b, off, thiscopy); - input_buffer_pos += thiscopy; - - return thiscopy; - } - - public void changeCipher(BlockCipher bc) - { - this.currentCipher = bc; - blockSize = bc.getBlockSize(); - buffer = new byte[blockSize]; - enc = new byte[blockSize]; - pos = blockSize; - } - - private void getBlock() throws IOException - { - int n = 0; - while (n < blockSize) - { - int len = internal_read(enc, n, blockSize - n); - if (len < 0) - throw new IOException("Cannot read full block, EOF reached."); - n += len; - } - - try - { - currentCipher.transformBlock(enc, 0, buffer, 0); - } - catch (Exception e) - { - throw new IOException("Error while decrypting block."); - } - pos = 0; - } - - public int read(byte[] dst) throws IOException - { - return read(dst, 0, dst.length); - } - - public int read(byte[] dst, int off, int len) throws IOException - { - int count = 0; - - while (len > 0) - { - if (pos >= blockSize) - getBlock(); - - int avail = blockSize - pos; - int copy = Math.min(avail, len); - System.arraycopy(buffer, pos, dst, off, copy); - pos += copy; - off += copy; - len -= copy; - count += copy; - } - return count; - } - - public int read() throws IOException - { - if (pos >= blockSize) - { - getBlock(); - } - return buffer[pos++] & 0xff; - } - - public int readPlain(byte[] b, int off, int len) throws IOException - { - if (pos != blockSize) - throw new IOException("Cannot read plain since crypto buffer is not aligned."); - int n = 0; - while (n < len) - { - int cnt = internal_read(b, off + n, len - n); - if (cnt < 0) - throw new IOException("Cannot fill buffer, EOF reached."); - n += cnt; - } - return n; - } -} diff --git a/src/com/trilead/ssh2/crypto/cipher/CipherOutputStream.java b/src/com/trilead/ssh2/crypto/cipher/CipherOutputStream.java deleted file mode 100644 index cf0db4a..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/CipherOutputStream.java +++ /dev/null @@ -1,142 +0,0 @@ - -package com.trilead.ssh2.crypto.cipher; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * CipherOutputStream. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: CipherOutputStream.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class CipherOutputStream -{ - BlockCipher currentCipher; - OutputStream bo; - byte[] buffer; - byte[] enc; - int blockSize; - int pos; - - /* - * We cannot use java.io.BufferedOutputStream, since that is not available - * in J2ME. Everything could be improved here alot. - */ - - final int BUFF_SIZE = 2048; - byte[] out_buffer = new byte[BUFF_SIZE]; - int out_buffer_pos = 0; - - public CipherOutputStream(BlockCipher tc, OutputStream bo) - { - this.bo = bo; - changeCipher(tc); - } - - private void internal_write(byte[] src, int off, int len) throws IOException - { - while (len > 0) - { - int space = BUFF_SIZE - out_buffer_pos; - int copy = (len > space) ? space : len; - - System.arraycopy(src, off, out_buffer, out_buffer_pos, copy); - - off += copy; - out_buffer_pos += copy; - len -= copy; - - if (out_buffer_pos >= BUFF_SIZE) - { - bo.write(out_buffer, 0, BUFF_SIZE); - out_buffer_pos = 0; - } - } - } - - private void internal_write(int b) throws IOException - { - out_buffer[out_buffer_pos++] = (byte) b; - if (out_buffer_pos >= BUFF_SIZE) - { - bo.write(out_buffer, 0, BUFF_SIZE); - out_buffer_pos = 0; - } - } - - public void flush() throws IOException - { - if (pos != 0) - throw new IOException("FATAL: cannot flush since crypto buffer is not aligned."); - - if (out_buffer_pos > 0) - { - bo.write(out_buffer, 0, out_buffer_pos); - out_buffer_pos = 0; - } - bo.flush(); - } - - public void changeCipher(BlockCipher bc) - { - this.currentCipher = bc; - blockSize = bc.getBlockSize(); - buffer = new byte[blockSize]; - enc = new byte[blockSize]; - pos = 0; - } - - private void writeBlock() throws IOException - { - try - { - currentCipher.transformBlock(buffer, 0, enc, 0); - } - catch (Exception e) - { - throw (IOException) new IOException("Error while decrypting block.").initCause(e); - } - - internal_write(enc, 0, blockSize); - pos = 0; - } - - public void write(byte[] src, int off, int len) throws IOException - { - while (len > 0) - { - int avail = blockSize - pos; - int copy = Math.min(avail, len); - - System.arraycopy(src, off, buffer, pos, copy); - pos += copy; - off += copy; - len -= copy; - - if (pos >= blockSize) - writeBlock(); - } - } - - public void write(int b) throws IOException - { - buffer[pos++] = (byte) b; - if (pos >= blockSize) - writeBlock(); - } - - public void writePlain(int b) throws IOException - { - if (pos != 0) - throw new IOException("Cannot write plain since crypto buffer is not aligned."); - internal_write(b); - } - - public void writePlain(byte[] b, int off, int len) throws IOException - { - if (pos != 0) - throw new IOException("Cannot write plain since crypto buffer is not aligned."); - internal_write(b, off, len); - } -} diff --git a/src/com/trilead/ssh2/crypto/cipher/DES.java b/src/com/trilead/ssh2/crypto/cipher/DES.java deleted file mode 100644 index 6588459..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/DES.java +++ /dev/null @@ -1,373 +0,0 @@ - -package com.trilead.ssh2.crypto.cipher; - -/* - This file is based on the 3DES implementation from the Bouncy Castle Crypto package. - Their licence file states the following: - - Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle - (http://www.bouncycastle.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - 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 THE - AUTHORS OR COPYRIGHT HOLDERS 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. - */ - -/** - * DES. - * - * @author See comments in the source file - * @version $Id: DES.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class DES implements BlockCipher -{ - private int[] workingKey = null; - - /** - * standard constructor. - */ - public DES() - { - } - - /** - * initialise a DES cipher. - * - * @param encrypting - * whether or not we are for encryption. - * @param key - * the parameters required to set up the cipher. - * @exception IllegalArgumentException - * if the params argument is inappropriate. - */ - public void init(boolean encrypting, byte[] key) - { - this.workingKey = generateWorkingKey(encrypting, key, 0); - } - - public String getAlgorithmName() - { - return "DES"; - } - - public int getBlockSize() - { - return 8; - } - - public void transformBlock(byte[] in, int inOff, byte[] out, int outOff) - { - if (workingKey == null) - { - throw new IllegalStateException("DES engine not initialised!"); - } - - desFunc(workingKey, in, inOff, out, outOff); - } - - public void reset() - { - } - - /** - * what follows is mainly taken from "Applied Cryptography", by Bruce - * Schneier, however it also bears great resemblance to Richard - * Outerbridge's D3DES... - */ - - static short[] Df_Key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, - 0x10, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67 }; - - static short[] bytebit = { 0200, 0100, 040, 020, 010, 04, 02, 01 }; - - static int[] bigbyte = { 0x800000, 0x400000, 0x200000, 0x100000, 0x80000, 0x40000, 0x20000, 0x10000, 0x8000, - 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; - - /* - * Use the key schedule specified in the Standard (ANSI X3.92-1981). - */ - - static byte[] pc1 = { 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, - 59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12, - 4, 27, 19, 11, 3 }; - - static byte[] totrot = { 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 }; - - static byte[] pc2 = { 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40, - 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 }; - - static int[] SP1 = { 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, - 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, - 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, - 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, - 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, - 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, - 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, - 0x00010400, 0x00000000, 0x01010004 }; - - static int[] SP2 = { 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, - 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, - 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, - 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, - 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, - 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, - 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, - 0x80100020, 0x80108020, 0x00108000 }; - - static int[] SP3 = { 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, - 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, - 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, - 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, - 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, - 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, - 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, - 0x00000008, 0x08020008, 0x00020200 }; - - static int[] SP4 = { 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, - 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, - 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, - 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, - 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, - 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, - 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, - 0x00800000, 0x00002000, 0x00802080 }; - - static int[] SP5 = { 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, - 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, - 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, - 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, - 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, - 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, - 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, - 0x40080000, 0x02080100, 0x40000100 }; - - static int[] SP6 = { 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, - 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, - 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, - 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, - 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, - 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, - 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, - 0x20000000, 0x00400010, 0x20004010 }; - - static int[] SP7 = { 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, - 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, - 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, - 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, - 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, - 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, - 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, - 0x04000800, 0x00000800, 0x00200002 }; - - static int[] SP8 = { 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, - 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, - 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, - 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, - 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, - 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, - 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, - 0x00040040, 0x10000000, 0x10041000 }; - - /** - * generate an integer based working key based on our secret key and what we - * processing we are planning to do. - * - * Acknowledgements for this routine go to James Gillogly & Phil Karn. - * (whoever, and wherever they are!). - */ - protected int[] generateWorkingKey(boolean encrypting, byte[] key, int off) - { - int[] newKey = new int[32]; - boolean[] pc1m = new boolean[56], pcr = new boolean[56]; - - for (int j = 0; j < 56; j++) - { - int l = pc1[j]; - - pc1m[j] = ((key[off + (l >>> 3)] & bytebit[l & 07]) != 0); - } - - for (int i = 0; i < 16; i++) - { - int l, m, n; - - if (encrypting) - { - m = i << 1; - } - else - { - m = (15 - i) << 1; - } - - n = m + 1; - newKey[m] = newKey[n] = 0; - - for (int j = 0; j < 28; j++) - { - l = j + totrot[i]; - if (l < 28) - { - pcr[j] = pc1m[l]; - } - else - { - pcr[j] = pc1m[l - 28]; - } - } - - for (int j = 28; j < 56; j++) - { - l = j + totrot[i]; - if (l < 56) - { - pcr[j] = pc1m[l]; - } - else - { - pcr[j] = pc1m[l - 28]; - } - } - - for (int j = 0; j < 24; j++) - { - if (pcr[pc2[j]]) - { - newKey[m] |= bigbyte[j]; - } - - if (pcr[pc2[j + 24]]) - { - newKey[n] |= bigbyte[j]; - } - } - } - - // - // store the processed key - // - for (int i = 0; i != 32; i += 2) - { - int i1, i2; - - i1 = newKey[i]; - i2 = newKey[i + 1]; - - newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10) | ((i2 & 0x00fc0000) >>> 10) - | ((i2 & 0x00000fc0) >>> 6); - - newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16) | ((i2 & 0x0003f000) >>> 4) - | (i2 & 0x0000003f); - } - - return newKey; - } - - /** - * the DES engine. - */ - protected void desFunc(int[] wKey, byte[] in, int inOff, byte[] out, int outOff) - { - int work, right, left; - - left = (in[inOff + 0] & 0xff) << 24; - left |= (in[inOff + 1] & 0xff) << 16; - left |= (in[inOff + 2] & 0xff) << 8; - left |= (in[inOff + 3] & 0xff); - - right = (in[inOff + 4] & 0xff) << 24; - right |= (in[inOff + 5] & 0xff) << 16; - right |= (in[inOff + 6] & 0xff) << 8; - right |= (in[inOff + 7] & 0xff); - - work = ((left >>> 4) ^ right) & 0x0f0f0f0f; - right ^= work; - left ^= (work << 4); - work = ((left >>> 16) ^ right) & 0x0000ffff; - right ^= work; - left ^= (work << 16); - work = ((right >>> 2) ^ left) & 0x33333333; - left ^= work; - right ^= (work << 2); - work = ((right >>> 8) ^ left) & 0x00ff00ff; - left ^= work; - right ^= (work << 8); - right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff; - work = (left ^ right) & 0xaaaaaaaa; - left ^= work; - right ^= work; - left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff; - - for (int round = 0; round < 8; round++) - { - int fval; - - work = (right << 28) | (right >>> 4); - work ^= wKey[round * 4 + 0]; - fval = SP7[work & 0x3f]; - fval |= SP5[(work >>> 8) & 0x3f]; - fval |= SP3[(work >>> 16) & 0x3f]; - fval |= SP1[(work >>> 24) & 0x3f]; - work = right ^ wKey[round * 4 + 1]; - fval |= SP8[work & 0x3f]; - fval |= SP6[(work >>> 8) & 0x3f]; - fval |= SP4[(work >>> 16) & 0x3f]; - fval |= SP2[(work >>> 24) & 0x3f]; - left ^= fval; - work = (left << 28) | (left >>> 4); - work ^= wKey[round * 4 + 2]; - fval = SP7[work & 0x3f]; - fval |= SP5[(work >>> 8) & 0x3f]; - fval |= SP3[(work >>> 16) & 0x3f]; - fval |= SP1[(work >>> 24) & 0x3f]; - work = left ^ wKey[round * 4 + 3]; - fval |= SP8[work & 0x3f]; - fval |= SP6[(work >>> 8) & 0x3f]; - fval |= SP4[(work >>> 16) & 0x3f]; - fval |= SP2[(work >>> 24) & 0x3f]; - right ^= fval; - } - - right = (right << 31) | (right >>> 1); - work = (left ^ right) & 0xaaaaaaaa; - left ^= work; - right ^= work; - left = (left << 31) | (left >>> 1); - work = ((left >>> 8) ^ right) & 0x00ff00ff; - right ^= work; - left ^= (work << 8); - work = ((left >>> 2) ^ right) & 0x33333333; - right ^= work; - left ^= (work << 2); - work = ((right >>> 16) ^ left) & 0x0000ffff; - left ^= work; - right ^= (work << 16); - work = ((right >>> 4) ^ left) & 0x0f0f0f0f; - left ^= work; - right ^= (work << 4); - - out[outOff + 0] = (byte) ((right >>> 24) & 0xff); - out[outOff + 1] = (byte) ((right >>> 16) & 0xff); - out[outOff + 2] = (byte) ((right >>> 8) & 0xff); - out[outOff + 3] = (byte) (right & 0xff); - out[outOff + 4] = (byte) ((left >>> 24) & 0xff); - out[outOff + 5] = (byte) ((left >>> 16) & 0xff); - out[outOff + 6] = (byte) ((left >>> 8) & 0xff); - out[outOff + 7] = (byte) (left & 0xff); - } -} diff --git a/src/com/trilead/ssh2/crypto/cipher/DESede.java b/src/com/trilead/ssh2/crypto/cipher/DESede.java deleted file mode 100644 index f47a636..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/DESede.java +++ /dev/null @@ -1,105 +0,0 @@ - -package com.trilead.ssh2.crypto.cipher; - -/* - This file was shamelessly taken (and modified) from the Bouncy Castle Crypto package. - Their licence file states the following: - - Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle - (http://www.bouncycastle.org) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - 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 THE - AUTHORS OR COPYRIGHT HOLDERS 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. - */ - -/** - * DESede. - * - * @author See comments in the source file - * @version $Id: DESede.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class DESede extends DES -{ - private int[] key1 = null; - private int[] key2 = null; - private int[] key3 = null; - - private boolean encrypt; - - /** - * standard constructor. - */ - public DESede() - { - } - - /** - * initialise a DES cipher. - * - * @param encrypting - * whether or not we are for encryption. - * @param key - * the parameters required to set up the cipher. - * @exception IllegalArgumentException - * if the params argument is inappropriate. - */ - public void init(boolean encrypting, byte[] key) - { - key1 = generateWorkingKey(encrypting, key, 0); - key2 = generateWorkingKey(!encrypting, key, 8); - key3 = generateWorkingKey(encrypting, key, 16); - - encrypt = encrypting; - } - - public String getAlgorithmName() - { - return "DESede"; - } - - public int getBlockSize() - { - return 8; - } - - public void transformBlock(byte[] in, int inOff, byte[] out, int outOff) - { - if (key1 == null) - { - throw new IllegalStateException("DESede engine not initialised!"); - } - - if (encrypt) - { - desFunc(key1, in, inOff, out, outOff); - desFunc(key2, out, outOff, out, outOff); - desFunc(key3, out, outOff, out, outOff); - } - else - { - desFunc(key3, in, inOff, out, outOff); - desFunc(key2, out, outOff, out, outOff); - desFunc(key1, out, outOff, out, outOff); - } - } - - public void reset() - { - } -} diff --git a/src/com/trilead/ssh2/crypto/cipher/NullCipher.java b/src/com/trilead/ssh2/crypto/cipher/NullCipher.java deleted file mode 100644 index 38f8215..0000000 --- a/src/com/trilead/ssh2/crypto/cipher/NullCipher.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.trilead.ssh2.crypto.cipher; - -/** - * NullCipher. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: NullCipher.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class NullCipher implements BlockCipher -{ - private int blockSize = 8; - - public NullCipher() - { - } - - public NullCipher(int blockSize) - { - this.blockSize = blockSize; - } - - public void init(boolean forEncryption, byte[] key) - { - } - - public int getBlockSize() - { - return blockSize; - } - - public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) - { - System.arraycopy(src, srcoff, dst, dstoff, blockSize); - } -} diff --git a/src/com/trilead/ssh2/crypto/dh/DhExchange.java b/src/com/trilead/ssh2/crypto/dh/DhExchange.java deleted file mode 100644 index 3acde25..0000000 --- a/src/com/trilead/ssh2/crypto/dh/DhExchange.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * - */ -package com.trilead.ssh2.crypto.dh; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; - -import javax.crypto.KeyAgreement; -import javax.crypto.interfaces.DHPrivateKey; -import javax.crypto.interfaces.DHPublicKey; -import javax.crypto.spec.DHParameterSpec; -import javax.crypto.spec.DHPublicKeySpec; - -/** - * @author kenny - * - */ -public class DhExchange extends GenericDhExchange { - - /* Given by the standard */ - - private static final BigInteger P1 = new BigInteger( - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" - + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" - + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" - + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" - + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" - + "FFFFFFFFFFFFFFFF", 16); - - private static final BigInteger P14 = new BigInteger( - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" - + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" - + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" - + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" - + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" - + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" - + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" - + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" - + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" - + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" - + "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16); - - private static final BigInteger G = BigInteger.valueOf(2); - - /* Client public and private */ - - private DHPrivateKey clientPrivate; - private DHPublicKey clientPublic; - - /* Server public */ - - private DHPublicKey serverPublic; - - @Override - public void init(String name) throws IOException { - final DHParameterSpec spec; - if ("diffie-hellman-group1-sha1".equals(name)) { - spec = new DHParameterSpec(P1, G); - } else if ("diffie-hellman-group14-sha1".equals(name)) { - spec = new DHParameterSpec(P14, G); - } else { - throw new IllegalArgumentException("Unknown DH group " + name); - } - - try { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH"); - kpg.initialize(spec); - KeyPair pair = kpg.generateKeyPair(); - clientPrivate = (DHPrivateKey) pair.getPrivate(); - clientPublic = (DHPublicKey) pair.getPublic(); - } catch (NoSuchAlgorithmException e) { - throw (IOException) new IOException("No DH keypair generator").initCause(e); - } catch (InvalidAlgorithmParameterException e) { - throw (IOException) new IOException("Invalid DH parameters").initCause(e); - } - } - - @Override - public byte[] getE() { - if (clientPublic == null) - throw new IllegalStateException("DhExchange not initialized!"); - - return clientPublic.getY().toByteArray(); - } - - @Override - protected byte[] getServerE() { - if (serverPublic == null) - throw new IllegalStateException("DhExchange not initialized!"); - - return serverPublic.getY().toByteArray(); - } - - @Override - public void setF(byte[] f) throws IOException { - if (clientPublic == null) - throw new IllegalStateException("DhExchange not initialized!"); - - final KeyAgreement ka; - try { - KeyFactory kf = KeyFactory.getInstance("DH"); - DHParameterSpec params = clientPublic.getParams(); - this.serverPublic = (DHPublicKey) kf.generatePublic(new DHPublicKeySpec( - new BigInteger(f), params.getP(), params.getG())); - - ka = KeyAgreement.getInstance("DH"); - ka.init(clientPrivate); - ka.doPhase(serverPublic, true); - } catch (NoSuchAlgorithmException e) { - throw (IOException) new IOException("No DH key agreement method").initCause(e); - } catch (InvalidKeyException e) { - throw (IOException) new IOException("Invalid DH key").initCause(e); - } catch (InvalidKeySpecException e) { - throw (IOException) new IOException("Invalid DH key").initCause(e); - } - - sharedSecret = new BigInteger(ka.generateSecret()); - } - - @Override - public String getHashAlgo() { - return "SHA1"; - } -} diff --git a/src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java b/src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java deleted file mode 100644 index a888950..0000000 --- a/src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java +++ /dev/null @@ -1,113 +0,0 @@ - -package com.trilead.ssh2.crypto.dh; - -import java.math.BigInteger; -import java.security.SecureRandom; - -import com.trilead.ssh2.DHGexParameters; -import com.trilead.ssh2.crypto.digest.HashForSSH2Types; - - -/** - * DhGroupExchange. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: DhGroupExchange.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public class DhGroupExchange -{ - /* Given by the standard */ - - private BigInteger p; - private BigInteger g; - - /* Client public and private */ - - private BigInteger e; - private BigInteger x; - - /* Server public */ - - private BigInteger f; - - /* Shared secret */ - - private BigInteger k; - - public DhGroupExchange(BigInteger p, BigInteger g) - { - this.p = p; - this.g = g; - } - - public void init(SecureRandom rnd) - { - k = null; - - x = new BigInteger(p.bitLength() - 1, rnd); - e = g.modPow(x, p); - } - - /** - * @return Returns the e. - */ - public BigInteger getE() - { - if (e == null) - throw new IllegalStateException("Not initialized!"); - - return e; - } - - /** - * @return Returns the shared secret k. - */ - public BigInteger getK() - { - if (k == null) - throw new IllegalStateException("Shared secret not yet known, need f first!"); - - return k; - } - - /** - * Sets f and calculates the shared secret. - */ - public void setF(BigInteger f) - { - if (e == null) - throw new IllegalStateException("Not initialized!"); - - BigInteger zero = BigInteger.valueOf(0); - - if (zero.compareTo(f) >= 0 || p.compareTo(f) <= 0) - throw new IllegalArgumentException("Invalid f specified!"); - - this.f = f; - this.k = f.modPow(x, p); - } - - public byte[] calculateH(String hashAlgo, byte[] clientversion, byte[] serverversion, - byte[] clientKexPayload, byte[] serverKexPayload, byte[] hostKey, DHGexParameters para) - { - HashForSSH2Types hash = new HashForSSH2Types(hashAlgo); - - hash.updateByteString(clientversion); - hash.updateByteString(serverversion); - hash.updateByteString(clientKexPayload); - hash.updateByteString(serverKexPayload); - hash.updateByteString(hostKey); - if (para.getMin_group_len() > 0) - hash.updateUINT32(para.getMin_group_len()); - hash.updateUINT32(para.getPref_group_len()); - if (para.getMax_group_len() > 0) - hash.updateUINT32(para.getMax_group_len()); - hash.updateBigInt(p); - hash.updateBigInt(g); - hash.updateBigInt(e); - hash.updateBigInt(f); - hash.updateBigInt(k); - - return hash.getDigest(); - } -} diff --git a/src/com/trilead/ssh2/crypto/dh/EcDhExchange.java b/src/com/trilead/ssh2/crypto/dh/EcDhExchange.java deleted file mode 100644 index 43d31ad..0000000 --- a/src/com/trilead/ssh2/crypto/dh/EcDhExchange.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * - */ -package com.trilead.ssh2.crypto.dh; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; - -import javax.crypto.KeyAgreement; - -import com.trilead.ssh2.signature.ECDSASHA2Verify; - -/** - * @author kenny - * - */ -public class EcDhExchange extends GenericDhExchange { - private ECPrivateKey clientPrivate; - private ECPublicKey clientPublic; - private ECPublicKey serverPublic; - - @Override - public void init(String name) throws IOException { - final ECParameterSpec spec; - - if ("ecdh-sha2-nistp256".equals(name)) { - spec = ECDSASHA2Verify.EllipticCurves.nistp256; - } else if ("ecdh-sha2-nistp384".equals(name)) { - spec = ECDSASHA2Verify.EllipticCurves.nistp384; - } else if ("ecdh-sha2-nistp521".equals(name)) { - spec = ECDSASHA2Verify.EllipticCurves.nistp521; - } else { - throw new IllegalArgumentException("Unknown EC curve " + name); - } - - KeyPairGenerator kpg; - try { - kpg = KeyPairGenerator.getInstance("EC"); - kpg.initialize(spec); - KeyPair pair = kpg.generateKeyPair(); - clientPrivate = (ECPrivateKey) pair.getPrivate(); - clientPublic = (ECPublicKey) pair.getPublic(); - } catch (NoSuchAlgorithmException e) { - throw (IOException) new IOException("No DH keypair generator").initCause(e); - } catch (InvalidAlgorithmParameterException e) { - throw (IOException) new IOException("Invalid DH parameters").initCause(e); - } - } - - @Override - public byte[] getE() { - return ECDSASHA2Verify.encodeECPoint(clientPublic.getW(), clientPublic.getParams() - .getCurve()); - } - - @Override - protected byte[] getServerE() { - return ECDSASHA2Verify.encodeECPoint(serverPublic.getW(), serverPublic.getParams() - .getCurve()); - } - - @Override - public void setF(byte[] f) throws IOException { - - if (clientPublic == null) - throw new IllegalStateException("DhDsaExchange not initialized!"); - - final KeyAgreement ka; - try { - KeyFactory kf = KeyFactory.getInstance("EC"); - ECParameterSpec params = clientPublic.getParams(); - ECPoint serverPoint = ECDSASHA2Verify.decodeECPoint(f, params.getCurve()); - this.serverPublic = (ECPublicKey) kf.generatePublic(new ECPublicKeySpec(serverPoint, - params)); - - ka = KeyAgreement.getInstance("ECDH"); - ka.init(clientPrivate); - ka.doPhase(serverPublic, true); - } catch (NoSuchAlgorithmException e) { - throw (IOException) new IOException("No ECDH key agreement method").initCause(e); - } catch (InvalidKeyException e) { - throw (IOException) new IOException("Invalid ECDH key").initCause(e); - } catch (InvalidKeySpecException e) { - throw (IOException) new IOException("Invalid ECDH key").initCause(e); - } - - sharedSecret = new BigInteger(ka.generateSecret()); - } - - @Override - public String getHashAlgo() { - return ECDSASHA2Verify.getDigestAlgorithmForParams(clientPublic.getParams()); - } -} diff --git a/src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java b/src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java deleted file mode 100644 index 039ff75..0000000 --- a/src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java +++ /dev/null @@ -1,93 +0,0 @@ - -package com.trilead.ssh2.crypto.dh; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; - -import com.trilead.ssh2.crypto.digest.HashForSSH2Types; -import com.trilead.ssh2.log.Logger; - - -/** - * DhExchange. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: DhExchange.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public abstract class GenericDhExchange -{ - private static final Logger log = Logger.getLogger(GenericDhExchange.class); - - /* Shared secret */ - - BigInteger sharedSecret; - - protected GenericDhExchange() - { - } - - public static GenericDhExchange getInstance(String algo) { - if (algo.startsWith("ecdh-sha2-")) { - return new EcDhExchange(); - } else { - return new DhExchange(); - } - } - - public abstract void init(String name) throws IOException; - - /** - * @return Returns the e (public value) - * @throws IllegalStateException - */ - public abstract byte[] getE(); - - /** - * @return Returns the server's e (public value) - * @throws IllegalStateException - */ - protected abstract byte[] getServerE(); - - /** - * @return Returns the shared secret k. - * @throws IllegalStateException - */ - public BigInteger getK() - { - if (sharedSecret == null) - throw new IllegalStateException("Shared secret not yet known, need f first!"); - - return sharedSecret; - } - - /** - * @param f - */ - public abstract void setF(byte[] f) throws IOException; - - public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload, - byte[] serverKexPayload, byte[] hostKey) throws UnsupportedEncodingException - { - HashForSSH2Types hash = new HashForSSH2Types(getHashAlgo()); - - if (log.isEnabled()) - { - log.log(90, "Client: '" + new String(clientversion, "ISO-8859-1") + "'"); - log.log(90, "Server: '" + new String(serverversion, "ISO-8859-1") + "'"); - } - - hash.updateByteString(clientversion); - hash.updateByteString(serverversion); - hash.updateByteString(clientKexPayload); - hash.updateByteString(serverKexPayload); - hash.updateByteString(hostKey); - hash.updateByteString(getE()); - hash.updateByteString(getServerE()); - hash.updateBigInt(sharedSecret); - - return hash.getDigest(); - } - - public abstract String getHashAlgo(); -} diff --git a/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java b/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java deleted file mode 100644 index 6b0d6e3..0000000 --- a/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java +++ /dev/null @@ -1,91 +0,0 @@ - -package com.trilead.ssh2.crypto.digest; - -import java.math.BigInteger; -import java.security.DigestException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -/** - * HashForSSH2Types. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: HashForSSH2Types.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public class HashForSSH2Types -{ - MessageDigest md; - - public HashForSSH2Types(String type) - { - try { - md = MessageDigest.getInstance(type); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Unsupported algorithm " + type); - } - } - - public void updateByte(byte b) - { - /* HACK - to test it with J2ME */ - byte[] tmp = new byte[1]; - tmp[0] = b; - md.update(tmp); - } - - public void updateBytes(byte[] b) - { - md.update(b); - } - - public void updateUINT32(int v) - { - md.update((byte) (v >> 24)); - md.update((byte) (v >> 16)); - md.update((byte) (v >> 8)); - md.update((byte) (v)); - } - - public void updateByteString(byte[] b) - { - updateUINT32(b.length); - updateBytes(b); - } - - public void updateBigInt(BigInteger b) - { - updateByteString(b.toByteArray()); - } - - public void reset() - { - md.reset(); - } - - public int getDigestLength() - { - return md.getDigestLength(); - } - - public byte[] getDigest() - { - byte[] tmp = new byte[md.getDigestLength()]; - getDigest(tmp); - return tmp; - } - - public void getDigest(byte[] out) - { - getDigest(out, 0); - } - - public void getDigest(byte[] out, int off) - { - try { - md.digest(out, off, out.length - off); - } catch (DigestException e) { - // TODO is this right?! - throw new RuntimeException("Unable to digest", e); - } - } -} diff --git a/src/com/trilead/ssh2/crypto/digest/MAC.java b/src/com/trilead/ssh2/crypto/digest/MAC.java deleted file mode 100644 index 561599c..0000000 --- a/src/com/trilead/ssh2/crypto/digest/MAC.java +++ /dev/null @@ -1,157 +0,0 @@ - -package com.trilead.ssh2.crypto.digest; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import javax.crypto.Mac; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.SecretKeySpec; - -/** - * MAC. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: MAC.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public final class MAC -{ - /** - * From http://tools.ietf.org/html/rfc4253 - */ - private static final String HMAC_MD5 = "hmac-md5"; - - /** - * From http://tools.ietf.org/html/rfc4253 - */ - private static final String HMAC_MD5_96 = "hmac-md5-96"; - - /** - * From http://tools.ietf.org/html/rfc4253 - */ - private static final String HMAC_SHA1 = "hmac-sha1"; - - /** - * From http://tools.ietf.org/html/rfc4253 - */ - private static final String HMAC_SHA1_96 = "hmac-sha1-96"; - - /** - * From http://tools.ietf.org/html/rfc6668 - */ - private static final String HMAC_SHA2_256 = "hmac-sha2-256"; - - /** - * From http://tools.ietf.org/html/rfc6668 - */ - private static final String HMAC_SHA2_512 = "hmac-sha2-512"; - - Mac mac; - int outSize; - int macSize; - byte[] buffer; - - /* Higher Priority First */ - private static final String[] MAC_LIST = { - HMAC_SHA2_256, HMAC_SHA2_512, - HMAC_SHA1_96, HMAC_SHA1, HMAC_MD5_96, HMAC_MD5 - }; - - public final static String[] getMacList() - { - return MAC_LIST; - } - - public final static void checkMacList(String[] macs) - { - for (int i = 0; i < macs.length; i++) - getKeyLen(macs[i]); - } - - public final static int getKeyLen(String type) - { - if (HMAC_SHA1.equals(type) || HMAC_SHA1_96.equals(type)) - return 20; - if (HMAC_MD5.equals(type) || HMAC_MD5_96.equals(type)) - return 16; - if (HMAC_SHA2_256.equals(type)) - return 32; - if (HMAC_SHA2_512.equals(type)) - return 64; - throw new IllegalArgumentException("Unkown algorithm " + type); - } - - public MAC(String type, byte[] key) - { - try { - if (HMAC_SHA1.equals(type) || HMAC_SHA1_96.equals(type)) - { - mac = Mac.getInstance("HmacSHA1"); - } - else if (HMAC_MD5.equals(type) || HMAC_MD5_96.equals(type)) - { - mac = Mac.getInstance("HmacMD5"); - } - else if (HMAC_SHA2_256.equals(type)) - { - mac = Mac.getInstance("HmacSHA256"); - } - else if (HMAC_SHA2_512.equals(type)) - { - mac = Mac.getInstance("HmacSHA512"); - } - else - throw new IllegalArgumentException("Unkown algorithm " + type); - } catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("Unknown algorithm " + type, e); - } - - macSize = mac.getMacLength(); - if (type.endsWith("-96")) { - outSize = 12; - buffer = new byte[macSize]; - } else { - outSize = macSize; - buffer = null; - } - - try { - mac.init(new SecretKeySpec(key, type)); - } catch (InvalidKeyException e) { - throw new IllegalArgumentException(e); - } - } - - public final void initMac(int seq) - { - mac.reset(); - mac.update((byte) (seq >> 24)); - mac.update((byte) (seq >> 16)); - mac.update((byte) (seq >> 8)); - mac.update((byte) (seq)); - } - - public final void update(byte[] packetdata, int off, int len) - { - mac.update(packetdata, off, len); - } - - public final void getMac(byte[] out, int off) - { - try { - if (buffer != null) { - mac.doFinal(buffer, 0); - System.arraycopy(buffer, 0, out, off, out.length - off); - } else { - mac.doFinal(out, off); - } - } catch (ShortBufferException e) { - throw new IllegalStateException(e); - } - } - - public final int size() - { - return outSize; - } -} diff --git a/src/com/trilead/ssh2/log/Logger.java b/src/com/trilead/ssh2/log/Logger.java deleted file mode 100644 index 20ab397..0000000 --- a/src/com/trilead/ssh2/log/Logger.java +++ /dev/null @@ -1,54 +0,0 @@ - -package com.trilead.ssh2.log; - -import com.trilead.ssh2.DebugLogger; - -/** - * Logger - a very simple logger, mainly used during development. - * Is not based on log4j (to reduce external dependencies). - * However, if needed, something like log4j could easily be - * hooked in. - * <p> - * For speed reasons, the static variables are not protected - * with semaphores. In other words, if you dynamicaly change the - * logging settings, then some threads may still use the old setting. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Logger.java,v 1.2 2008/03/03 07:01:36 cplattne Exp $ - */ - -public class Logger -{ - public static boolean enabled = false; - public static DebugLogger logger = null; - - private String className; - - public final static Logger getLogger(Class x) - { - return new Logger(x); - } - - public Logger(Class x) - { - this.className = x.getName(); - } - - public final boolean isEnabled() - { - return enabled; - } - - public final void log(int level, String message) - { - if (!enabled) - return; - - DebugLogger target = logger; - - if (target == null) - return; - - target.log(level, className, message); - } -} diff --git a/src/com/trilead/ssh2/packets/PacketChannelAuthAgentReq.java b/src/com/trilead/ssh2/packets/PacketChannelAuthAgentReq.java deleted file mode 100644 index 95fa396..0000000 --- a/src/com/trilead/ssh2/packets/PacketChannelAuthAgentReq.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.trilead.ssh2.packets; - -/** - * PacketGlobalAuthAgent. - * - * @author Kenny Root, kenny@the-b.org - * @version $Id$ - */ -public class PacketChannelAuthAgentReq -{ - byte[] payload; - - public int recipientChannelID; - - public PacketChannelAuthAgentReq(int recipientChannelID) - { - this.recipientChannelID = recipientChannelID; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); - tw.writeUINT32(recipientChannelID); - tw.writeString("auth-agent-req@openssh.com"); - tw.writeBoolean(true); // want reply - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketChannelOpenConfirmation.java b/src/com/trilead/ssh2/packets/PacketChannelOpenConfirmation.java deleted file mode 100644 index bd2ea3f..0000000 --- a/src/com/trilead/ssh2/packets/PacketChannelOpenConfirmation.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketChannelOpenConfirmation. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketChannelOpenConfirmation.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketChannelOpenConfirmation -{ - byte[] payload; - - public int recipientChannelID; - public int senderChannelID; - public int initialWindowSize; - public int maxPacketSize; - - public PacketChannelOpenConfirmation(int recipientChannelID, int senderChannelID, int initialWindowSize, - int maxPacketSize) - { - this.recipientChannelID = recipientChannelID; - this.senderChannelID = senderChannelID; - this.initialWindowSize = initialWindowSize; - this.maxPacketSize = maxPacketSize; - } - - public PacketChannelOpenConfirmation(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) - throw new IOException( - "This is not a SSH_MSG_CHANNEL_OPEN_CONFIRMATION! (" - + packet_type + ")"); - - recipientChannelID = tr.readUINT32(); - senderChannelID = tr.readUINT32(); - initialWindowSize = tr.readUINT32(); - maxPacketSize = tr.readUINT32(); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION); - tw.writeUINT32(recipientChannelID); - tw.writeUINT32(senderChannelID); - tw.writeUINT32(initialWindowSize); - tw.writeUINT32(maxPacketSize); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketChannelOpenFailure.java b/src/com/trilead/ssh2/packets/PacketChannelOpenFailure.java deleted file mode 100644 index 1370355..0000000 --- a/src/com/trilead/ssh2/packets/PacketChannelOpenFailure.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketChannelOpenFailure. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketChannelOpenFailure.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketChannelOpenFailure -{ - byte[] payload; - - public int recipientChannelID; - public int reasonCode; - public String description; - public String languageTag; - - public PacketChannelOpenFailure(int recipientChannelID, int reasonCode, String description, - String languageTag) - { - this.recipientChannelID = recipientChannelID; - this.reasonCode = reasonCode; - this.description = description; - this.languageTag = languageTag; - } - - public PacketChannelOpenFailure(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN_FAILURE) - throw new IOException( - "This is not a SSH_MSG_CHANNEL_OPEN_FAILURE! (" - + packet_type + ")"); - - recipientChannelID = tr.readUINT32(); - reasonCode = tr.readUINT32(); - description = tr.readString(); - languageTag = tr.readString(); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN_FAILURE packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN_FAILURE); - tw.writeUINT32(recipientChannelID); - tw.writeUINT32(reasonCode); - tw.writeString(description); - tw.writeString(languageTag); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketChannelTrileadPing.java b/src/com/trilead/ssh2/packets/PacketChannelTrileadPing.java deleted file mode 100644 index c337930..0000000 --- a/src/com/trilead/ssh2/packets/PacketChannelTrileadPing.java +++ /dev/null @@ -1,35 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * PacketChannelTrileadPing. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketChannelTrileadPing.java,v 1.1 2008/03/03 07:01:36 - * cplattne Exp $ - */ -public class PacketChannelTrileadPing -{ - byte[] payload; - - public int recipientChannelID; - - public PacketChannelTrileadPing(int recipientChannelID) - { - this.recipientChannelID = recipientChannelID; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); - tw.writeUINT32(recipientChannelID); - tw.writeString("trilead-ping"); - tw.writeBoolean(true); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketChannelWindowAdjust.java b/src/com/trilead/ssh2/packets/PacketChannelWindowAdjust.java deleted file mode 100644 index 37ec081..0000000 --- a/src/com/trilead/ssh2/packets/PacketChannelWindowAdjust.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketChannelWindowAdjust. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketChannelWindowAdjust.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketChannelWindowAdjust -{ - byte[] payload; - - public int recipientChannelID; - public int windowChange; - - public PacketChannelWindowAdjust(int recipientChannelID, int windowChange) - { - this.recipientChannelID = recipientChannelID; - this.windowChange = windowChange; - } - - public PacketChannelWindowAdjust(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST) - throw new IOException( - "This is not a SSH_MSG_CHANNEL_WINDOW_ADJUST! (" - + packet_type + ")"); - - recipientChannelID = tr.readUINT32(); - windowChange = tr.readUINT32(); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_CHANNEL_WINDOW_ADJUST packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST); - tw.writeUINT32(recipientChannelID); - tw.writeUINT32(windowChange); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketDisconnect.java b/src/com/trilead/ssh2/packets/PacketDisconnect.java deleted file mode 100644 index 50d6ec2..0000000 --- a/src/com/trilead/ssh2/packets/PacketDisconnect.java +++ /dev/null @@ -1,57 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketDisconnect. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketDisconnect.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class PacketDisconnect -{ - byte[] payload; - - int reason; - String desc; - String lang; - - public PacketDisconnect(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_DISCONNECT) - throw new IOException("This is not a Disconnect Packet! (" + packet_type + ")"); - - reason = tr.readUINT32(); - desc = tr.readString(); - lang = tr.readString(); - } - - public PacketDisconnect(int reason, String desc, String lang) - { - this.reason = reason; - this.desc = desc; - this.lang = lang; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_DISCONNECT); - tw.writeUINT32(reason); - tw.writeString(desc); - tw.writeString(lang); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketGlobalCancelForwardRequest.java b/src/com/trilead/ssh2/packets/PacketGlobalCancelForwardRequest.java deleted file mode 100644 index 20bd558..0000000 --- a/src/com/trilead/ssh2/packets/PacketGlobalCancelForwardRequest.java +++ /dev/null @@ -1,42 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * PacketGlobalCancelForwardRequest. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketGlobalCancelForwardRequest.java,v 1.1 2007/10/15 12:49:55 - * cplattne Exp $ - */ -public class PacketGlobalCancelForwardRequest -{ - byte[] payload; - - public boolean wantReply; - public String bindAddress; - public int bindPort; - - public PacketGlobalCancelForwardRequest(boolean wantReply, String bindAddress, int bindPort) - { - this.wantReply = wantReply; - this.bindAddress = bindAddress; - this.bindPort = bindPort; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); - - tw.writeString("cancel-tcpip-forward"); - tw.writeBoolean(wantReply); - tw.writeString(bindAddress); - tw.writeUINT32(bindPort); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketGlobalForwardRequest.java b/src/com/trilead/ssh2/packets/PacketGlobalForwardRequest.java deleted file mode 100644 index 55257e9..0000000 --- a/src/com/trilead/ssh2/packets/PacketGlobalForwardRequest.java +++ /dev/null @@ -1,41 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * PacketGlobalForwardRequest. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketGlobalForwardRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketGlobalForwardRequest -{ - byte[] payload; - - public boolean wantReply; - public String bindAddress; - public int bindPort; - - public PacketGlobalForwardRequest(boolean wantReply, String bindAddress, int bindPort) - { - this.wantReply = wantReply; - this.bindAddress = bindAddress; - this.bindPort = bindPort; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); - - tw.writeString("tcpip-forward"); - tw.writeBoolean(wantReply); - tw.writeString(bindAddress); - tw.writeUINT32(bindPort); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketGlobalTrileadPing.java b/src/com/trilead/ssh2/packets/PacketGlobalTrileadPing.java deleted file mode 100644 index 3d8930e..0000000 --- a/src/com/trilead/ssh2/packets/PacketGlobalTrileadPing.java +++ /dev/null @@ -1,32 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * PacketGlobalTrileadPing. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketGlobalTrileadPing.java,v 1.1 2008/03/03 07:01:36 cplattne Exp $ - */ -public class PacketGlobalTrileadPing -{ - byte[] payload; - - public PacketGlobalTrileadPing() - { - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); - - tw.writeString("trilead-ping"); - tw.writeBoolean(true); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketIgnore.java b/src/com/trilead/ssh2/packets/PacketIgnore.java deleted file mode 100644 index 2b4d917..0000000 --- a/src/com/trilead/ssh2/packets/PacketIgnore.java +++ /dev/null @@ -1,59 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketIgnore. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketIgnore.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketIgnore -{ - byte[] payload; - - byte[] data; - - public void setData(byte[] data) - { - this.data = data; - payload = null; - } - - public PacketIgnore() - { - } - - public PacketIgnore(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_IGNORE) - throw new IOException("This is not a SSH_MSG_IGNORE packet! (" + packet_type + ")"); - - /* Could parse String body */ - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_IGNORE); - - if (data != null) - tw.writeString(data, 0, data.length); - else - tw.writeString(""); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketKexDHInit.java b/src/com/trilead/ssh2/packets/PacketKexDHInit.java deleted file mode 100644 index 0092516..0000000 --- a/src/com/trilead/ssh2/packets/PacketKexDHInit.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.trilead.ssh2.packets; - -/** - * PacketKexDHInit. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketKexDHInit.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketKexDHInit -{ - byte[] payload; - - byte[] publicKey; - - public PacketKexDHInit(byte[] publicKey) - { - this.publicKey = publicKey; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_KEXDH_INIT); - tw.writeString(publicKey, 0, publicKey.length); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketKexDHReply.java b/src/com/trilead/ssh2/packets/PacketKexDHReply.java deleted file mode 100644 index 51f2bda..0000000 --- a/src/com/trilead/ssh2/packets/PacketKexDHReply.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketKexDHReply. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketKexDHReply.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketKexDHReply -{ - byte[] payload; - - byte[] hostKey; - byte[] publicKey; - byte[] signature; - - public PacketKexDHReply(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_KEXDH_REPLY) - throw new IOException("This is not a SSH_MSG_KEXDH_REPLY! (" - + packet_type + ")"); - - hostKey = tr.readByteString(); - publicKey = tr.readByteString(); - signature = tr.readByteString(); - - if (tr.remain() != 0) throw new IOException("PADDING IN SSH_MSG_KEXDH_REPLY!"); - } - - public byte[] getF() - { - return publicKey; - } - - public byte[] getHostKey() - { - return hostKey; - } - - public byte[] getSignature() - { - return signature; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketKexDhGexGroup.java b/src/com/trilead/ssh2/packets/PacketKexDhGexGroup.java deleted file mode 100644 index db85b61..0000000 --- a/src/com/trilead/ssh2/packets/PacketKexDhGexGroup.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -import java.math.BigInteger; - -/** - * PacketKexDhGexGroup. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketKexDhGexGroup.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketKexDhGexGroup -{ - byte[] payload; - - BigInteger p; - BigInteger g; - - public PacketKexDhGexGroup(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_KEX_DH_GEX_GROUP) - throw new IllegalArgumentException( - "This is not a SSH_MSG_KEX_DH_GEX_GROUP! (" + packet_type - + ")"); - - p = tr.readMPINT(); - g = tr.readMPINT(); - - if (tr.remain() != 0) - throw new IOException("PADDING IN SSH_MSG_KEX_DH_GEX_GROUP!"); - } - - public BigInteger getG() - { - return g; - } - - public BigInteger getP() - { - return p; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketKexDhGexInit.java b/src/com/trilead/ssh2/packets/PacketKexDhGexInit.java deleted file mode 100644 index 8b34230..0000000 --- a/src/com/trilead/ssh2/packets/PacketKexDhGexInit.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.math.BigInteger; - -/** - * PacketKexDhGexInit. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketKexDhGexInit.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketKexDhGexInit -{ - byte[] payload; - - BigInteger e; - - public PacketKexDhGexInit(BigInteger e) - { - this.e = e; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_INIT); - tw.writeMPInt(e); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketKexDhGexReply.java b/src/com/trilead/ssh2/packets/PacketKexDhGexReply.java deleted file mode 100644 index 382b3b7..0000000 --- a/src/com/trilead/ssh2/packets/PacketKexDhGexReply.java +++ /dev/null @@ -1,56 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.IOException; - -import java.math.BigInteger; - -/** - * PacketKexDhGexReply. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketKexDhGexReply.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketKexDhGexReply -{ - byte[] payload; - - byte[] hostKey; - BigInteger f; - byte[] signature; - - public PacketKexDhGexReply(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_KEX_DH_GEX_REPLY) - throw new IOException("This is not a SSH_MSG_KEX_DH_GEX_REPLY! (" + packet_type + ")"); - - hostKey = tr.readByteString(); - f = tr.readMPINT(); - signature = tr.readByteString(); - - if (tr.remain() != 0) - throw new IOException("PADDING IN SSH_MSG_KEX_DH_GEX_REPLY!"); - } - - public BigInteger getF() - { - return f; - } - - public byte[] getHostKey() - { - return hostKey; - } - - public byte[] getSignature() - { - return signature; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketKexDhGexRequest.java b/src/com/trilead/ssh2/packets/PacketKexDhGexRequest.java deleted file mode 100644 index 50369df..0000000 --- a/src/com/trilead/ssh2/packets/PacketKexDhGexRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.trilead.ssh2.packets; - -import com.trilead.ssh2.DHGexParameters; - -/** - * PacketKexDhGexRequest. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketKexDhGexRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketKexDhGexRequest -{ - byte[] payload; - - int min; - int n; - int max; - - public PacketKexDhGexRequest(DHGexParameters para) - { - this.min = para.getMin_group_len(); - this.n = para.getPref_group_len(); - this.max = para.getMax_group_len(); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_REQUEST); - tw.writeUINT32(min); - tw.writeUINT32(n); - tw.writeUINT32(max); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketKexDhGexRequestOld.java b/src/com/trilead/ssh2/packets/PacketKexDhGexRequestOld.java deleted file mode 100644 index 327f379..0000000 --- a/src/com/trilead/ssh2/packets/PacketKexDhGexRequestOld.java +++ /dev/null @@ -1,34 +0,0 @@ - -package com.trilead.ssh2.packets; - -import com.trilead.ssh2.DHGexParameters; - -/** - * PacketKexDhGexRequestOld. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketKexDhGexRequestOld.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketKexDhGexRequestOld -{ - byte[] payload; - - int n; - - public PacketKexDhGexRequestOld(DHGexParameters para) - { - this.n = para.getPref_group_len(); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_REQUEST_OLD); - tw.writeUINT32(n); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketKexInit.java b/src/com/trilead/ssh2/packets/PacketKexInit.java deleted file mode 100644 index 087d658..0000000 --- a/src/com/trilead/ssh2/packets/PacketKexInit.java +++ /dev/null @@ -1,165 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.IOException; -import java.security.SecureRandom; - -import com.trilead.ssh2.crypto.CryptoWishList; -import com.trilead.ssh2.transport.KexParameters; - - -/** - * PacketKexInit. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketKexInit.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketKexInit -{ - byte[] payload; - - KexParameters kp = new KexParameters(); - - public PacketKexInit(CryptoWishList cwl) - { - kp.cookie = new byte[16]; - new SecureRandom().nextBytes(kp.cookie); - - kp.kex_algorithms = cwl.kexAlgorithms; - kp.server_host_key_algorithms = cwl.serverHostKeyAlgorithms; - kp.encryption_algorithms_client_to_server = cwl.c2s_enc_algos; - kp.encryption_algorithms_server_to_client = cwl.s2c_enc_algos; - kp.mac_algorithms_client_to_server = cwl.c2s_mac_algos; - kp.mac_algorithms_server_to_client = cwl.s2c_mac_algos; - kp.compression_algorithms_client_to_server = cwl.c2s_comp_algos; - kp.compression_algorithms_server_to_client = cwl.s2c_comp_algos; - kp.languages_client_to_server = new String[] {}; - kp.languages_server_to_client = new String[] {}; - kp.first_kex_packet_follows = false; - kp.reserved_field1 = 0; - } - - public PacketKexInit(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_KEXINIT) - throw new IOException("This is not a KexInitPacket! (" + packet_type + ")"); - - kp.cookie = tr.readBytes(16); - kp.kex_algorithms = tr.readNameList(); - kp.server_host_key_algorithms = tr.readNameList(); - kp.encryption_algorithms_client_to_server = tr.readNameList(); - kp.encryption_algorithms_server_to_client = tr.readNameList(); - kp.mac_algorithms_client_to_server = tr.readNameList(); - kp.mac_algorithms_server_to_client = tr.readNameList(); - kp.compression_algorithms_client_to_server = tr.readNameList(); - kp.compression_algorithms_server_to_client = tr.readNameList(); - kp.languages_client_to_server = tr.readNameList(); - kp.languages_server_to_client = tr.readNameList(); - kp.first_kex_packet_follows = tr.readBoolean(); - kp.reserved_field1 = tr.readUINT32(); - - if (tr.remain() != 0) - throw new IOException("Padding in KexInitPacket!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_KEXINIT); - tw.writeBytes(kp.cookie, 0, 16); - tw.writeNameList(kp.kex_algorithms); - tw.writeNameList(kp.server_host_key_algorithms); - tw.writeNameList(kp.encryption_algorithms_client_to_server); - tw.writeNameList(kp.encryption_algorithms_server_to_client); - tw.writeNameList(kp.mac_algorithms_client_to_server); - tw.writeNameList(kp.mac_algorithms_server_to_client); - tw.writeNameList(kp.compression_algorithms_client_to_server); - tw.writeNameList(kp.compression_algorithms_server_to_client); - tw.writeNameList(kp.languages_client_to_server); - tw.writeNameList(kp.languages_server_to_client); - tw.writeBoolean(kp.first_kex_packet_follows); - tw.writeUINT32(kp.reserved_field1); - payload = tw.getBytes(); - } - return payload; - } - - public KexParameters getKexParameters() - { - return kp; - } - - public String[] getCompression_algorithms_client_to_server() - { - return kp.compression_algorithms_client_to_server; - } - - public String[] getCompression_algorithms_server_to_client() - { - return kp.compression_algorithms_server_to_client; - } - - public byte[] getCookie() - { - return kp.cookie; - } - - public String[] getEncryption_algorithms_client_to_server() - { - return kp.encryption_algorithms_client_to_server; - } - - public String[] getEncryption_algorithms_server_to_client() - { - return kp.encryption_algorithms_server_to_client; - } - - public boolean isFirst_kex_packet_follows() - { - return kp.first_kex_packet_follows; - } - - public String[] getKex_algorithms() - { - return kp.kex_algorithms; - } - - public String[] getLanguages_client_to_server() - { - return kp.languages_client_to_server; - } - - public String[] getLanguages_server_to_client() - { - return kp.languages_server_to_client; - } - - public String[] getMac_algorithms_client_to_server() - { - return kp.mac_algorithms_client_to_server; - } - - public String[] getMac_algorithms_server_to_client() - { - return kp.mac_algorithms_server_to_client; - } - - public int getReserved_field1() - { - return kp.reserved_field1; - } - - public String[] getServer_host_key_algorithms() - { - return kp.server_host_key_algorithms; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketNewKeys.java b/src/com/trilead/ssh2/packets/PacketNewKeys.java deleted file mode 100644 index 3ca6503..0000000 --- a/src/com/trilead/ssh2/packets/PacketNewKeys.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketNewKeys. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketNewKeys.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketNewKeys -{ - byte[] payload; - - public PacketNewKeys() - { - } - - public PacketNewKeys(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_NEWKEYS) - throw new IOException("This is not a SSH_MSG_NEWKEYS! (" - + packet_type + ")"); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_NEWKEYS packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_NEWKEYS); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketOpenDirectTCPIPChannel.java b/src/com/trilead/ssh2/packets/PacketOpenDirectTCPIPChannel.java deleted file mode 100644 index da6cbef..0000000 --- a/src/com/trilead/ssh2/packets/PacketOpenDirectTCPIPChannel.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.trilead.ssh2.packets; - - -/** - * PacketOpenDirectTCPIPChannel. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketOpenDirectTCPIPChannel.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketOpenDirectTCPIPChannel -{ - byte[] payload; - - int channelID; - int initialWindowSize; - int maxPacketSize; - - String host_to_connect; - int port_to_connect; - String originator_IP_address; - int originator_port; - - public PacketOpenDirectTCPIPChannel(int channelID, int initialWindowSize, int maxPacketSize, - String host_to_connect, int port_to_connect, String originator_IP_address, - int originator_port) - { - this.channelID = channelID; - this.initialWindowSize = initialWindowSize; - this.maxPacketSize = maxPacketSize; - this.host_to_connect = host_to_connect; - this.port_to_connect = port_to_connect; - this.originator_IP_address = originator_IP_address; - this.originator_port = originator_port; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - - tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN); - tw.writeString("direct-tcpip"); - tw.writeUINT32(channelID); - tw.writeUINT32(initialWindowSize); - tw.writeUINT32(maxPacketSize); - tw.writeString(host_to_connect); - tw.writeUINT32(port_to_connect); - tw.writeString(originator_IP_address); - tw.writeUINT32(originator_port); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketOpenSessionChannel.java b/src/com/trilead/ssh2/packets/PacketOpenSessionChannel.java deleted file mode 100644 index a75ea63..0000000 --- a/src/com/trilead/ssh2/packets/PacketOpenSessionChannel.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketOpenSessionChannel. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketOpenSessionChannel.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketOpenSessionChannel -{ - byte[] payload; - - int channelID; - int initialWindowSize; - int maxPacketSize; - - public PacketOpenSessionChannel(int channelID, int initialWindowSize, - int maxPacketSize) - { - this.channelID = channelID; - this.initialWindowSize = initialWindowSize; - this.maxPacketSize = maxPacketSize; - } - - public PacketOpenSessionChannel(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN) - throw new IOException("This is not a SSH_MSG_CHANNEL_OPEN! (" - + packet_type + ")"); - - channelID = tr.readUINT32(); - initialWindowSize = tr.readUINT32(); - maxPacketSize = tr.readUINT32(); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN); - tw.writeString("session"); - tw.writeUINT32(channelID); - tw.writeUINT32(initialWindowSize); - tw.writeUINT32(maxPacketSize); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketServiceAccept.java b/src/com/trilead/ssh2/packets/PacketServiceAccept.java deleted file mode 100644 index d5c9a90..0000000 --- a/src/com/trilead/ssh2/packets/PacketServiceAccept.java +++ /dev/null @@ -1,61 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketServiceAccept. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketServiceAccept.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class PacketServiceAccept -{ - byte[] payload; - - String serviceName; - - public PacketServiceAccept(String serviceName) - { - this.serviceName = serviceName; - } - - public PacketServiceAccept(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_SERVICE_ACCEPT) - throw new IOException("This is not a SSH_MSG_SERVICE_ACCEPT! (" + packet_type + ")"); - - /* Be clever in case the server is not. Some servers seem to violate RFC4253 */ - - if (tr.remain() > 0) - { - serviceName = tr.readString(); - } - else - { - serviceName = ""; - } - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_SERVICE_ACCEPT packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_SERVICE_ACCEPT); - tw.writeString(serviceName); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketServiceRequest.java b/src/com/trilead/ssh2/packets/PacketServiceRequest.java deleted file mode 100644 index c2d2065..0000000 --- a/src/com/trilead/ssh2/packets/PacketServiceRequest.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketServiceRequest. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketServiceRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketServiceRequest -{ - byte[] payload; - - String serviceName; - - public PacketServiceRequest(String serviceName) - { - this.serviceName = serviceName; - } - - public PacketServiceRequest(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_SERVICE_REQUEST) - throw new IOException("This is not a SSH_MSG_SERVICE_REQUEST! (" - + packet_type + ")"); - - serviceName = tr.readString(); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_SERVICE_REQUEST packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_SERVICE_REQUEST); - tw.writeString(serviceName); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketSessionExecCommand.java b/src/com/trilead/ssh2/packets/PacketSessionExecCommand.java deleted file mode 100644 index 84efa5d..0000000 --- a/src/com/trilead/ssh2/packets/PacketSessionExecCommand.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.trilead.ssh2.packets; - - -/** - * PacketSessionExecCommand. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketSessionExecCommand.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketSessionExecCommand -{ - byte[] payload; - - public int recipientChannelID; - public boolean wantReply; - public String command; - - public PacketSessionExecCommand(int recipientChannelID, boolean wantReply, String command) - { - this.recipientChannelID = recipientChannelID; - this.wantReply = wantReply; - this.command = command; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); - tw.writeUINT32(recipientChannelID); - tw.writeString("exec"); - tw.writeBoolean(wantReply); - tw.writeString(command); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketSessionPtyRequest.java b/src/com/trilead/ssh2/packets/PacketSessionPtyRequest.java deleted file mode 100644 index d9c3d59..0000000 --- a/src/com/trilead/ssh2/packets/PacketSessionPtyRequest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.trilead.ssh2.packets; - - -/** - * PacketSessionPtyRequest. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketSessionPtyRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketSessionPtyRequest -{ - byte[] payload; - - public int recipientChannelID; - public boolean wantReply; - public String term; - public int character_width; - public int character_height; - public int pixel_width; - public int pixel_height; - public byte[] terminal_modes; - - public PacketSessionPtyRequest(int recipientChannelID, boolean wantReply, String term, - int character_width, int character_height, int pixel_width, int pixel_height, - byte[] terminal_modes) - { - this.recipientChannelID = recipientChannelID; - this.wantReply = wantReply; - this.term = term; - this.character_width = character_width; - this.character_height = character_height; - this.pixel_width = pixel_width; - this.pixel_height = pixel_height; - this.terminal_modes = terminal_modes; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); - tw.writeUINT32(recipientChannelID); - tw.writeString("pty-req"); - tw.writeBoolean(wantReply); - tw.writeString(term); - tw.writeUINT32(character_width); - tw.writeUINT32(character_height); - tw.writeUINT32(pixel_width); - tw.writeUINT32(pixel_height); - tw.writeString(terminal_modes, 0, terminal_modes.length); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketSessionPtyResize.java b/src/com/trilead/ssh2/packets/PacketSessionPtyResize.java deleted file mode 100644 index 1e3b558..0000000 --- a/src/com/trilead/ssh2/packets/PacketSessionPtyResize.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.trilead.ssh2.packets; - -public class PacketSessionPtyResize { - byte[] payload; - - public int recipientChannelID; - public int width; - public int height; - public int pixelWidth; - public int pixelHeight; - - public PacketSessionPtyResize(int recipientChannelID, int width, int height, int pixelWidth, int pixelHeight) { - this.recipientChannelID = recipientChannelID; - this.width = width; - this.height = height; - this.pixelWidth = pixelWidth; - this.pixelHeight = pixelHeight; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); - tw.writeUINT32(recipientChannelID); - tw.writeString("window-change"); - tw.writeBoolean(false); - tw.writeUINT32(width); - tw.writeUINT32(height); - tw.writeUINT32(pixelWidth); - tw.writeUINT32(pixelHeight); - - payload = tw.getBytes(); - } - return payload; - } -} - - diff --git a/src/com/trilead/ssh2/packets/PacketSessionStartShell.java b/src/com/trilead/ssh2/packets/PacketSessionStartShell.java deleted file mode 100644 index e5add01..0000000 --- a/src/com/trilead/ssh2/packets/PacketSessionStartShell.java +++ /dev/null @@ -1,36 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * PacketSessionStartShell. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketSessionStartShell.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketSessionStartShell -{ - byte[] payload; - - public int recipientChannelID; - public boolean wantReply; - - public PacketSessionStartShell(int recipientChannelID, boolean wantReply) - { - this.recipientChannelID = recipientChannelID; - this.wantReply = wantReply; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); - tw.writeUINT32(recipientChannelID); - tw.writeString("shell"); - tw.writeBoolean(wantReply); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketSessionSubsystemRequest.java b/src/com/trilead/ssh2/packets/PacketSessionSubsystemRequest.java deleted file mode 100644 index cdc3a8c..0000000 --- a/src/com/trilead/ssh2/packets/PacketSessionSubsystemRequest.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.trilead.ssh2.packets; - - -/** - * PacketSessionSubsystemRequest. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketSessionSubsystemRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketSessionSubsystemRequest -{ - byte[] payload; - - public int recipientChannelID; - public boolean wantReply; - public String subsystem; - - public PacketSessionSubsystemRequest(int recipientChannelID, boolean wantReply, String subsystem) - { - this.recipientChannelID = recipientChannelID; - this.wantReply = wantReply; - this.subsystem = subsystem; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); - tw.writeUINT32(recipientChannelID); - tw.writeString("subsystem"); - tw.writeBoolean(wantReply); - tw.writeString(subsystem); - payload = tw.getBytes(); - tw.getBytes(payload); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketSessionX11Request.java b/src/com/trilead/ssh2/packets/PacketSessionX11Request.java deleted file mode 100644 index 26479c7..0000000 --- a/src/com/trilead/ssh2/packets/PacketSessionX11Request.java +++ /dev/null @@ -1,53 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * PacketSessionX11Request. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketSessionX11Request.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketSessionX11Request -{ - byte[] payload; - - public int recipientChannelID; - public boolean wantReply; - - public boolean singleConnection; - String x11AuthenticationProtocol; - String x11AuthenticationCookie; - int x11ScreenNumber; - - public PacketSessionX11Request(int recipientChannelID, boolean wantReply, boolean singleConnection, - String x11AuthenticationProtocol, String x11AuthenticationCookie, int x11ScreenNumber) - { - this.recipientChannelID = recipientChannelID; - this.wantReply = wantReply; - - this.singleConnection = singleConnection; - this.x11AuthenticationProtocol = x11AuthenticationProtocol; - this.x11AuthenticationCookie = x11AuthenticationCookie; - this.x11ScreenNumber = x11ScreenNumber; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); - tw.writeUINT32(recipientChannelID); - tw.writeString("x11-req"); - tw.writeBoolean(wantReply); - - tw.writeBoolean(singleConnection); - tw.writeString(x11AuthenticationProtocol); - tw.writeString(x11AuthenticationCookie); - tw.writeUINT32(x11ScreenNumber); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketUserauthBanner.java b/src/com/trilead/ssh2/packets/PacketUserauthBanner.java deleted file mode 100644 index 8ad8c3b..0000000 --- a/src/com/trilead/ssh2/packets/PacketUserauthBanner.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketUserauthBanner. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketUserauthBanner.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketUserauthBanner -{ - byte[] payload; - - String message; - String language; - - public PacketUserauthBanner(String message, String language) - { - this.message = message; - this.language = language; - } - - public String getBanner() - { - return message; - } - - public PacketUserauthBanner(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_USERAUTH_BANNER) - throw new IOException("This is not a SSH_MSG_USERAUTH_BANNER! (" + packet_type + ")"); - - message = tr.readString("UTF-8"); - language = tr.readString(); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_USERAUTH_REQUEST packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_USERAUTH_BANNER); - tw.writeString(message); - tw.writeString(language); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketUserauthFailure.java b/src/com/trilead/ssh2/packets/PacketUserauthFailure.java deleted file mode 100644 index fd4a726..0000000 --- a/src/com/trilead/ssh2/packets/PacketUserauthFailure.java +++ /dev/null @@ -1,53 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketUserauthBanner. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketUserauthFailure.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketUserauthFailure -{ - byte[] payload; - - String[] authThatCanContinue; - boolean partialSuccess; - - public PacketUserauthFailure(String[] authThatCanContinue, boolean partialSuccess) - { - this.authThatCanContinue = authThatCanContinue; - this.partialSuccess = partialSuccess; - } - - public PacketUserauthFailure(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_USERAUTH_FAILURE) - throw new IOException("This is not a SSH_MSG_USERAUTH_FAILURE! (" + packet_type + ")"); - - authThatCanContinue = tr.readNameList(); - partialSuccess = tr.readBoolean(); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_USERAUTH_FAILURE packet!"); - } - - public String[] getAuthThatCanContinue() - { - return authThatCanContinue; - } - - public boolean isPartialSuccess() - { - return partialSuccess; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketUserauthInfoRequest.java b/src/com/trilead/ssh2/packets/PacketUserauthInfoRequest.java deleted file mode 100644 index e1606d1..0000000 --- a/src/com/trilead/ssh2/packets/PacketUserauthInfoRequest.java +++ /dev/null @@ -1,84 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketUserauthInfoRequest. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketUserauthInfoRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketUserauthInfoRequest -{ - byte[] payload; - - String name; - String instruction; - String languageTag; - int numPrompts; - - String prompt[]; - boolean echo[]; - - public PacketUserauthInfoRequest(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_USERAUTH_INFO_REQUEST) - throw new IOException("This is not a SSH_MSG_USERAUTH_INFO_REQUEST! (" + packet_type + ")"); - - name = tr.readString(); - instruction = tr.readString(); - languageTag = tr.readString(); - - numPrompts = tr.readUINT32(); - - prompt = new String[numPrompts]; - echo = new boolean[numPrompts]; - - for (int i = 0; i < numPrompts; i++) - { - prompt[i] = tr.readString(); - echo[i] = tr.readBoolean(); - } - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_USERAUTH_INFO_REQUEST packet!"); - } - - public boolean[] getEcho() - { - return echo; - } - - public String getInstruction() - { - return instruction; - } - - public String getLanguageTag() - { - return languageTag; - } - - public String getName() - { - return name; - } - - public int getNumPrompts() - { - return numPrompts; - } - - public String[] getPrompt() - { - return prompt; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketUserauthInfoResponse.java b/src/com/trilead/ssh2/packets/PacketUserauthInfoResponse.java deleted file mode 100644 index e8795d4..0000000 --- a/src/com/trilead/ssh2/packets/PacketUserauthInfoResponse.java +++ /dev/null @@ -1,35 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * PacketUserauthInfoResponse. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketUserauthInfoResponse.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketUserauthInfoResponse -{ - byte[] payload; - - String[] responses; - - public PacketUserauthInfoResponse(String[] responses) - { - this.responses = responses; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_USERAUTH_INFO_RESPONSE); - tw.writeUINT32(responses.length); - for (int i = 0; i < responses.length; i++) - tw.writeString(responses[i]); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketUserauthRequestInteractive.java b/src/com/trilead/ssh2/packets/PacketUserauthRequestInteractive.java deleted file mode 100644 index 83e9f49..0000000 --- a/src/com/trilead/ssh2/packets/PacketUserauthRequestInteractive.java +++ /dev/null @@ -1,42 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * PacketUserauthRequestInteractive. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketUserauthRequestInteractive.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketUserauthRequestInteractive -{ - byte[] payload; - - String userName; - String serviceName; - String[] submethods; - - public PacketUserauthRequestInteractive(String serviceName, String user, String[] submethods) - { - this.serviceName = serviceName; - this.userName = user; - this.submethods = submethods; - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); - tw.writeString(userName); - tw.writeString(serviceName); - tw.writeString("keyboard-interactive"); - tw.writeString(""); // draft-ietf-secsh-newmodes-04.txt says that - // the language tag should be empty. - tw.writeNameList(submethods); - - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketUserauthRequestNone.java b/src/com/trilead/ssh2/packets/PacketUserauthRequestNone.java deleted file mode 100644 index d786003..0000000 --- a/src/com/trilead/ssh2/packets/PacketUserauthRequestNone.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketUserauthRequestPassword. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketUserauthRequestNone.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketUserauthRequestNone -{ - byte[] payload; - - String userName; - String serviceName; - - public PacketUserauthRequestNone(String serviceName, String user) - { - this.serviceName = serviceName; - this.userName = user; - } - - public PacketUserauthRequestNone(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST) - throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST! (" + packet_type + ")"); - - userName = tr.readString(); - serviceName = tr.readString(); - - String method = tr.readString(); - - if (method.equals("none") == false) - throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST with type none!"); - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_USERAUTH_REQUEST packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); - tw.writeString(userName); - tw.writeString(serviceName); - tw.writeString("none"); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketUserauthRequestPassword.java b/src/com/trilead/ssh2/packets/PacketUserauthRequestPassword.java deleted file mode 100644 index 83047dd..0000000 --- a/src/com/trilead/ssh2/packets/PacketUserauthRequestPassword.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketUserauthRequestPassword. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketUserauthRequestPassword.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketUserauthRequestPassword -{ - byte[] payload; - - String userName; - String serviceName; - String password; - - public PacketUserauthRequestPassword(String serviceName, String user, String pass) - { - this.serviceName = serviceName; - this.userName = user; - this.password = pass; - } - - public PacketUserauthRequestPassword(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST) - throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST! (" + packet_type + ")"); - - userName = tr.readString(); - serviceName = tr.readString(); - - String method = tr.readString(); - - if (method.equals("password") == false) - throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST with type password!"); - - /* ... */ - - if (tr.remain() != 0) - throw new IOException("Padding in SSH_MSG_USERAUTH_REQUEST packet!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); - tw.writeString(userName); - tw.writeString(serviceName); - tw.writeString("password"); - tw.writeBoolean(false); - tw.writeString(password); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/PacketUserauthRequestPublicKey.java b/src/com/trilead/ssh2/packets/PacketUserauthRequestPublicKey.java deleted file mode 100644 index 6462864..0000000 --- a/src/com/trilead/ssh2/packets/PacketUserauthRequestPublicKey.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.trilead.ssh2.packets; - -import java.io.IOException; - -/** - * PacketUserauthRequestPublicKey. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: PacketUserauthRequestPublicKey.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class PacketUserauthRequestPublicKey -{ - byte[] payload; - - String userName; - String serviceName; - String password; - String pkAlgoName; - byte[] pk; - byte[] sig; - - public PacketUserauthRequestPublicKey(String serviceName, String user, - String pkAlgorithmName, byte[] pk, byte[] sig) - { - this.serviceName = serviceName; - this.userName = user; - this.pkAlgoName = pkAlgorithmName; - this.pk = pk; - this.sig = sig; - } - - public PacketUserauthRequestPublicKey(byte payload[], int off, int len) throws IOException - { - this.payload = new byte[len]; - System.arraycopy(payload, off, this.payload, 0, len); - - TypesReader tr = new TypesReader(payload, off, len); - - int packet_type = tr.readByte(); - - if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST) - throw new IOException("This is not a SSH_MSG_USERAUTH_REQUEST! (" - + packet_type + ")"); - - throw new IOException("Not implemented!"); - } - - public byte[] getPayload() - { - if (payload == null) - { - TypesWriter tw = new TypesWriter(); - tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); - tw.writeString(userName); - tw.writeString(serviceName); - tw.writeString("publickey"); - tw.writeBoolean(true); - tw.writeString(pkAlgoName); - tw.writeString(pk, 0, pk.length); - tw.writeString(sig, 0, sig.length); - payload = tw.getBytes(); - } - return payload; - } -} diff --git a/src/com/trilead/ssh2/packets/Packets.java b/src/com/trilead/ssh2/packets/Packets.java deleted file mode 100644 index 6989286..0000000 --- a/src/com/trilead/ssh2/packets/Packets.java +++ /dev/null @@ -1,149 +0,0 @@ - -package com.trilead.ssh2.packets; - -/** - * Packets. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Packets.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class Packets -{ - public static final int SSH_MSG_DISCONNECT = 1; - public static final int SSH_MSG_IGNORE = 2; - public static final int SSH_MSG_UNIMPLEMENTED = 3; - public static final int SSH_MSG_DEBUG = 4; - public static final int SSH_MSG_SERVICE_REQUEST = 5; - public static final int SSH_MSG_SERVICE_ACCEPT = 6; - - public static final int SSH_MSG_KEXINIT = 20; - public static final int SSH_MSG_NEWKEYS = 21; - - public static final int SSH_MSG_KEXDH_INIT = 30; - public static final int SSH_MSG_KEXDH_REPLY = 31; - - public static final int SSH_MSG_KEX_DH_GEX_REQUEST_OLD = 30; - public static final int SSH_MSG_KEX_DH_GEX_REQUEST = 34; - public static final int SSH_MSG_KEX_DH_GEX_GROUP = 31; - public static final int SSH_MSG_KEX_DH_GEX_INIT = 32; - public static final int SSH_MSG_KEX_DH_GEX_REPLY = 33; - - public static final int SSH_MSG_USERAUTH_REQUEST = 50; - public static final int SSH_MSG_USERAUTH_FAILURE = 51; - public static final int SSH_MSG_USERAUTH_SUCCESS = 52; - public static final int SSH_MSG_USERAUTH_BANNER = 53; - public static final int SSH_MSG_USERAUTH_INFO_REQUEST = 60; - public static final int SSH_MSG_USERAUTH_INFO_RESPONSE = 61; - - public static final int SSH_MSG_GLOBAL_REQUEST = 80; - public static final int SSH_MSG_REQUEST_SUCCESS = 81; - public static final int SSH_MSG_REQUEST_FAILURE = 82; - - public static final int SSH_MSG_CHANNEL_OPEN = 90; - public static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91; - public static final int SSH_MSG_CHANNEL_OPEN_FAILURE = 92; - public static final int SSH_MSG_CHANNEL_WINDOW_ADJUST = 93; - public static final int SSH_MSG_CHANNEL_DATA = 94; - public static final int SSH_MSG_CHANNEL_EXTENDED_DATA = 95; - public static final int SSH_MSG_CHANNEL_EOF = 96; - public static final int SSH_MSG_CHANNEL_CLOSE = 97; - public static final int SSH_MSG_CHANNEL_REQUEST = 98; - public static final int SSH_MSG_CHANNEL_SUCCESS = 99; - public static final int SSH_MSG_CHANNEL_FAILURE = 100; - - public static final int SSH_EXTENDED_DATA_STDERR = 1; - - public static final int SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1; - public static final int SSH_DISCONNECT_PROTOCOL_ERROR = 2; - public static final int SSH_DISCONNECT_KEY_EXCHANGE_FAILED = 3; - public static final int SSH_DISCONNECT_RESERVED = 4; - public static final int SSH_DISCONNECT_MAC_ERROR = 5; - public static final int SSH_DISCONNECT_COMPRESSION_ERROR = 6; - public static final int SSH_DISCONNECT_SERVICE_NOT_AVAILABLE = 7; - public static final int SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8; - public static final int SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9; - public static final int SSH_DISCONNECT_CONNECTION_LOST = 10; - public static final int SSH_DISCONNECT_BY_APPLICATION = 11; - public static final int SSH_DISCONNECT_TOO_MANY_CONNECTIONS = 12; - public static final int SSH_DISCONNECT_AUTH_CANCELLED_BY_USER = 13; - public static final int SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14; - public static final int SSH_DISCONNECT_ILLEGAL_USER_NAME = 15; - - public static final int SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1; - public static final int SSH_OPEN_CONNECT_FAILED = 2; - public static final int SSH_OPEN_UNKNOWN_CHANNEL_TYPE = 3; - public static final int SSH_OPEN_RESOURCE_SHORTAGE = 4; - - private static final String[] reverseNames = new String[101]; - - static - { - reverseNames[1] = "SSH_MSG_DISCONNECT"; - reverseNames[2] = "SSH_MSG_IGNORE"; - reverseNames[3] = "SSH_MSG_UNIMPLEMENTED"; - reverseNames[4] = "SSH_MSG_DEBUG"; - reverseNames[5] = "SSH_MSG_SERVICE_REQUEST"; - reverseNames[6] = "SSH_MSG_SERVICE_ACCEPT"; - - reverseNames[20] = "SSH_MSG_KEXINIT"; - reverseNames[21] = "SSH_MSG_NEWKEYS"; - - reverseNames[30] = "SSH_MSG_KEXDH_INIT"; - reverseNames[31] = "SSH_MSG_KEXDH_REPLY/SSH_MSG_KEX_DH_GEX_GROUP"; - reverseNames[32] = "SSH_MSG_KEX_DH_GEX_INIT"; - reverseNames[33] = "SSH_MSG_KEX_DH_GEX_REPLY"; - reverseNames[34] = "SSH_MSG_KEX_DH_GEX_REQUEST"; - - reverseNames[50] = "SSH_MSG_USERAUTH_REQUEST"; - reverseNames[51] = "SSH_MSG_USERAUTH_FAILURE"; - reverseNames[52] = "SSH_MSG_USERAUTH_SUCCESS"; - reverseNames[53] = "SSH_MSG_USERAUTH_BANNER"; - - reverseNames[60] = "SSH_MSG_USERAUTH_INFO_REQUEST"; - reverseNames[61] = "SSH_MSG_USERAUTH_INFO_RESPONSE"; - - reverseNames[80] = "SSH_MSG_GLOBAL_REQUEST"; - reverseNames[81] = "SSH_MSG_REQUEST_SUCCESS"; - reverseNames[82] = "SSH_MSG_REQUEST_FAILURE"; - - reverseNames[90] = "SSH_MSG_CHANNEL_OPEN"; - reverseNames[91] = "SSH_MSG_CHANNEL_OPEN_CONFIRMATION"; - reverseNames[92] = "SSH_MSG_CHANNEL_OPEN_FAILURE"; - reverseNames[93] = "SSH_MSG_CHANNEL_WINDOW_ADJUST"; - reverseNames[94] = "SSH_MSG_CHANNEL_DATA"; - reverseNames[95] = "SSH_MSG_CHANNEL_EXTENDED_DATA"; - reverseNames[96] = "SSH_MSG_CHANNEL_EOF"; - reverseNames[97] = "SSH_MSG_CHANNEL_CLOSE"; - reverseNames[98] = "SSH_MSG_CHANNEL_REQUEST"; - reverseNames[99] = "SSH_MSG_CHANNEL_SUCCESS"; - reverseNames[100] = "SSH_MSG_CHANNEL_FAILURE"; - } - - public static final String getMessageName(int type) - { - String res = null; - - if ((type >= 0) && (type < reverseNames.length)) - { - res = reverseNames[type]; - } - - return (res == null) ? ("UNKNOWN MSG " + type) : res; - } - - // public static final void debug(String tag, byte[] msg) - // { - // System.err.println(tag + " Type: " + msg[0] + ", LEN: " + msg.length); - // - // for (int i = 0; i < msg.length; i++) - // { - // if (((msg[i] >= 'a') && (msg[i] <= 'z')) || ((msg[i] >= 'A') && (msg[i] <= 'Z')) - // || ((msg[i] >= '0') && (msg[i] <= '9')) || (msg[i] == ' ')) - // System.err.print((char) msg[i]); - // else - // System.err.print("."); - // } - // System.err.println(); - // System.err.flush(); - // } -} diff --git a/src/com/trilead/ssh2/packets/TypesReader.java b/src/com/trilead/ssh2/packets/TypesReader.java deleted file mode 100644 index 28f5363..0000000 --- a/src/com/trilead/ssh2/packets/TypesReader.java +++ /dev/null @@ -1,177 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.IOException; -import java.math.BigInteger; - -import com.trilead.ssh2.util.Tokenizer; - - -/** - * TypesReader. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: TypesReader.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class TypesReader -{ - byte[] arr; - int pos = 0; - int max = 0; - - public TypesReader(byte[] arr) - { - this.arr = arr; - pos = 0; - max = arr.length; - } - - public TypesReader(byte[] arr, int off) - { - this.arr = arr; - this.pos = off; - this.max = arr.length; - - if ((pos < 0) || (pos > arr.length)) - throw new IllegalArgumentException("Illegal offset."); - } - - public TypesReader(byte[] arr, int off, int len) - { - this.arr = arr; - this.pos = off; - this.max = off + len; - - if ((pos < 0) || (pos > arr.length)) - throw new IllegalArgumentException("Illegal offset."); - - if ((max < 0) || (max > arr.length)) - throw new IllegalArgumentException("Illegal length."); - } - - public int readByte() throws IOException - { - if (pos >= max) - throw new IOException("Packet too short."); - - return (arr[pos++] & 0xff); - } - - public byte[] readBytes(int len) throws IOException - { - if ((pos + len) > max) - throw new IOException("Packet too short."); - - byte[] res = new byte[len]; - - System.arraycopy(arr, pos, res, 0, len); - pos += len; - - return res; - } - - public void readBytes(byte[] dst, int off, int len) throws IOException - { - if ((pos + len) > max) - throw new IOException("Packet too short."); - - System.arraycopy(arr, pos, dst, off, len); - pos += len; - } - - public boolean readBoolean() throws IOException - { - if (pos >= max) - throw new IOException("Packet too short."); - - return (arr[pos++] != 0); - } - - public int readUINT32() throws IOException - { - if ((pos + 4) > max) - throw new IOException("Packet too short."); - - return ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8) - | (arr[pos++] & 0xff); - } - - public long readUINT64() throws IOException - { - if ((pos + 8) > max) - throw new IOException("Packet too short."); - - long high = ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8) - | (arr[pos++] & 0xff); /* sign extension may take place - will be shifted away =) */ - - long low = ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8) - | (arr[pos++] & 0xff); /* sign extension may take place - handle below */ - - return (high << 32) | (low & 0xffffffffl); /* see Java language spec (15.22.1, 5.6.2) */ - } - - public BigInteger readMPINT() throws IOException - { - BigInteger b; - - byte raw[] = readByteString(); - - if (raw.length == 0) - b = BigInteger.ZERO; - else - b = new BigInteger(raw); - - return b; - } - - public byte[] readByteString() throws IOException - { - int len = readUINT32(); - - if ((len + pos) > max) - throw new IOException("Malformed SSH byte string."); - - byte[] res = new byte[len]; - System.arraycopy(arr, pos, res, 0, len); - pos += len; - return res; - } - - public String readString(String charsetName) throws IOException - { - int len = readUINT32(); - - if ((len + pos) > max) - throw new IOException("Malformed SSH string."); - - String res = (charsetName == null) ? new String(arr, pos, len) : new String(arr, pos, len, charsetName); - pos += len; - - return res; - } - - public String readString() throws IOException - { - int len = readUINT32(); - - if ((len + pos) > max) - throw new IOException("Malformed SSH string."); - - String res = new String(arr, pos, len, "ISO-8859-1"); - - pos += len; - - return res; - } - - public String[] readNameList() throws IOException - { - return Tokenizer.parseTokens(readString(), ','); - } - - public int remain() - { - return max - pos; - } - -} diff --git a/src/com/trilead/ssh2/packets/TypesWriter.java b/src/com/trilead/ssh2/packets/TypesWriter.java deleted file mode 100644 index 9f7336b..0000000 --- a/src/com/trilead/ssh2/packets/TypesWriter.java +++ /dev/null @@ -1,169 +0,0 @@ - -package com.trilead.ssh2.packets; - -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; - -/** - * TypesWriter. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: TypesWriter.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class TypesWriter -{ - byte arr[]; - int pos; - - public TypesWriter() - { - arr = new byte[256]; - pos = 0; - } - - private void resize(int len) - { - byte new_arr[] = new byte[len]; - System.arraycopy(arr, 0, new_arr, 0, arr.length); - arr = new_arr; - } - - public int length() - { - return pos; - } - - public byte[] getBytes() - { - byte[] dst = new byte[pos]; - System.arraycopy(arr, 0, dst, 0, pos); - return dst; - } - - public void getBytes(byte dst[]) - { - System.arraycopy(arr, 0, dst, 0, pos); - } - - public void writeUINT32(int val, int off) - { - if ((off + 4) > arr.length) - resize(off + 32); - - arr[off++] = (byte) (val >> 24); - arr[off++] = (byte) (val >> 16); - arr[off++] = (byte) (val >> 8); - arr[off++] = (byte) val; - } - - public void writeUINT32(int val) - { - writeUINT32(val, pos); - pos += 4; - } - - public void writeUINT64(long val) - { - if ((pos + 8) > arr.length) - resize(arr.length + 32); - - arr[pos++] = (byte) (val >> 56); - arr[pos++] = (byte) (val >> 48); - arr[pos++] = (byte) (val >> 40); - arr[pos++] = (byte) (val >> 32); - arr[pos++] = (byte) (val >> 24); - arr[pos++] = (byte) (val >> 16); - arr[pos++] = (byte) (val >> 8); - arr[pos++] = (byte) val; - } - - public void writeBoolean(boolean v) - { - if ((pos + 1) > arr.length) - resize(arr.length + 32); - - arr[pos++] = v ? (byte) 1 : (byte) 0; - } - - public void writeByte(int v, int off) - { - if ((off + 1) > arr.length) - resize(off + 32); - - arr[off] = (byte) v; - } - - public void writeByte(int v) - { - writeByte(v, pos); - pos++; - } - - public void writeMPInt(BigInteger b) - { - byte raw[] = b.toByteArray(); - - if ((raw.length == 1) && (raw[0] == 0)) - writeUINT32(0); /* String with zero bytes of data */ - else - writeString(raw, 0, raw.length); - } - - public void writeBytes(byte[] buff) - { - writeBytes(buff, 0, buff.length); - } - - public void writeBytes(byte[] buff, int off, int len) - { - if ((pos + len) > arr.length) - resize(arr.length + len + 32); - - System.arraycopy(buff, off, arr, pos, len); - pos += len; - } - - public void writeString(byte[] buff, int off, int len) - { - writeUINT32(len); - writeBytes(buff, off, len); - } - - public void writeString(String v) - { - byte[] b; - - try - { - /* All Java JVMs must support ISO-8859-1 */ - b = v.getBytes("ISO-8859-1"); - } - catch (UnsupportedEncodingException ignore) - { - b = v.getBytes(); - } - - writeUINT32(b.length); - writeBytes(b, 0, b.length); - } - - public void writeString(String v, String charsetName) throws UnsupportedEncodingException - { - byte[] b = (charsetName == null) ? v.getBytes() : v.getBytes(charsetName); - - writeUINT32(b.length); - writeBytes(b, 0, b.length); - } - - public void writeNameList(String v[]) - { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < v.length; i++) - { - if (i > 0) - sb.append(','); - sb.append(v[i]); - } - writeString(sb.toString()); - } -} diff --git a/src/com/trilead/ssh2/sftp/AttrTextHints.java b/src/com/trilead/ssh2/sftp/AttrTextHints.java deleted file mode 100644 index 19f0525..0000000 --- a/src/com/trilead/ssh2/sftp/AttrTextHints.java +++ /dev/null @@ -1,38 +0,0 @@ - -package com.trilead.ssh2.sftp; - -/** - * - * Values for the 'text-hint' field in the SFTP ATTRS data type. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: AttrTextHints.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class AttrTextHints -{ - /** - * The server knows the file is a text file, and should be opened - * using the SSH_FXF_ACCESS_TEXT_MODE flag. - */ - public static final int SSH_FILEXFER_ATTR_KNOWN_TEXT = 0x00; - - /** - * The server has applied a heuristic or other mechanism and - * believes that the file should be opened with the - * SSH_FXF_ACCESS_TEXT_MODE flag. - */ - public static final int SSH_FILEXFER_ATTR_GUESSED_TEXT = 0x01; - - /** - * The server knows the file has binary content. - */ - public static final int SSH_FILEXFER_ATTR_KNOWN_BINARY = 0x02; - - /** - * The server has applied a heuristic or other mechanism and - * believes has binary content, and should not be opened with the - * SSH_FXF_ACCESS_TEXT_MODE flag. - */ - public static final int SSH_FILEXFER_ATTR_GUESSED_BINARY = 0x03; -} diff --git a/src/com/trilead/ssh2/sftp/AttribBits.java b/src/com/trilead/ssh2/sftp/AttribBits.java deleted file mode 100644 index b143613..0000000 --- a/src/com/trilead/ssh2/sftp/AttribBits.java +++ /dev/null @@ -1,129 +0,0 @@ - -package com.trilead.ssh2.sftp; - -/** - * - * SFTP Attribute Bits for the "attrib-bits" and "attrib-bits-valid" fields - * of the SFTP ATTR data type. - * <p> - * Yes, these are the "attrib-bits", even though they have "_FLAGS_" in - * their name. Don't ask - I did not invent it. - * <p> - * "<i>These fields, taken together, reflect various attributes of the file - * or directory, on the server. Bits not set in 'attrib-bits-valid' MUST be - * ignored in the 'attrib-bits' field. This allows both the server and the - * client to communicate only the bits it knows about without inadvertently - * twiddling bits they don't understand.</i>" - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: AttribBits.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class AttribBits -{ - /** - * Advisory, read-only bit. This bit is not part of the access - * control information on the file, but is rather an advisory field - * indicating that the file should not be written. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_READONLY = 0x00000001; - - /** - * The file is part of the operating system. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_SYSTEM = 0x00000002; - - /** - * File SHOULD NOT be shown to user unless specifically requested. - * For example, most UNIX systems SHOULD set this bit if the filename - * begins with a 'period'. This bit may be read-only (see section 5.4 of - * the SFTP standard draft). Most UNIX systems will not allow this to be - * changed. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_HIDDEN = 0x00000004; - - /** - * This attribute applies only to directories. This attribute is - * always read-only, and cannot be modified. This attribute means - * that files and directory names in this directory should be compared - * without regard to case. - * <p> - * It is recommended that where possible, the server's filesystem be - * allowed to do comparisons. For example, if a client wished to prompt - * a user before overwriting a file, it should not compare the new name - * with the previously retrieved list of names in the directory. Rather, - * it should first try to create the new file by specifying - * SSH_FXF_CREATE_NEW flag. Then, if this fails and returns - * SSH_FX_FILE_ALREADY_EXISTS, it should prompt the user and then retry - * the create specifying SSH_FXF_CREATE_TRUNCATE. - * <p> - * Unless otherwise specified, filenames are assumed to be case sensitive. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE = 0x00000008; - - /** - * The file should be included in backup / archive operations. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_ARCHIVE = 0x00000010; - - /** - * The file is stored on disk using file-system level transparent - * encryption. This flag does not affect the file data on the wire - * (for either READ or WRITE requests.) - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED = 0x00000020; - - /** - * The file is stored on disk using file-system level transparent - * compression. This flag does not affect the file data on the wire. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_COMPRESSED = 0x00000040; - - /** - * The file is a sparse file; this means that file blocks that have - * not been explicitly written are not stored on disk. For example, if - * a client writes a buffer at 10 M from the beginning of the file, - * the blocks between the previous EOF marker and the 10 M offset would - * not consume physical disk space. - * <p> - * Some servers may store all files as sparse files, in which case - * this bit will be unconditionally set. Other servers may not have - * a mechanism for determining if the file is sparse, and so the file - * MAY be stored sparse even if this flag is not set. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_SPARSE = 0x00000080; - - /** - * Opening the file without either the SSH_FXF_ACCESS_APPEND_DATA or - * the SSH_FXF_ACCESS_APPEND_DATA_ATOMIC flag (see section 8.1.1.3 - * of the SFTP standard draft) MUST result in an - * SSH_FX_INVALID_PARAMETER error. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY = 0x00000100; - - /** - * The file cannot be deleted or renamed, no hard link can be created - * to this file, and no data can be written to the file. - * <p> - * This bit implies a stronger level of protection than - * SSH_FILEXFER_ATTR_FLAGS_READONLY, the file permission mask or ACLs. - * Typically even the superuser cannot write to immutable files, and - * only the superuser can set or remove the bit. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE = 0x00000200; - - /** - * When the file is modified, the changes are written synchronously - * to the disk. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_SYNC = 0x00000400; - - /** - * The server MAY include this bit in a directory listing or realpath - * response. It indicates there was a failure in the translation to UTF-8. - * If this flag is included, the server SHOULD also include the - * UNTRANSLATED_NAME attribute. - */ - public static final int SSH_FILEXFER_ATTR_FLAGS_TRANSLATION_ERR = 0x00000800; - -} diff --git a/src/com/trilead/ssh2/sftp/AttribFlags.java b/src/com/trilead/ssh2/sftp/AttribFlags.java deleted file mode 100644 index ea27871..0000000 --- a/src/com/trilead/ssh2/sftp/AttribFlags.java +++ /dev/null @@ -1,112 +0,0 @@ - -package com.trilead.ssh2.sftp; - -/** - * - * Attribute Flags. The 'valid-attribute-flags' field in - * the SFTP ATTRS data type specifies which of the fields are actually present. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: AttribFlags.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class AttribFlags -{ - /** - * Indicates that the 'allocation-size' field is present. - */ - public static final int SSH_FILEXFER_ATTR_SIZE = 0x00000001; - - /** Protocol version 6: - * 0x00000002 was used in a previous version of this protocol. - * It is now a reserved value and MUST NOT appear in the mask. - * Some future version of this protocol may reuse this value. - */ - public static final int SSH_FILEXFER_ATTR_V3_UIDGID = 0x00000002; - - /** - * Indicates that the 'permissions' field is present. - */ - public static final int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004; - - /** - * Indicates that the 'atime' and 'mtime' field are present - * (protocol v3). - */ - public static final int SSH_FILEXFER_ATTR_V3_ACMODTIME = 0x00000008; - - /** - * Indicates that the 'atime' field is present. - */ - public static final int SSH_FILEXFER_ATTR_ACCESSTIME = 0x00000008; - - /** - * Indicates that the 'createtime' field is present. - */ - public static final int SSH_FILEXFER_ATTR_CREATETIME = 0x00000010; - - /** - * Indicates that the 'mtime' field is present. - */ - public static final int SSH_FILEXFER_ATTR_MODIFYTIME = 0x00000020; - - /** - * Indicates that the 'acl' field is present. - */ - public static final int SSH_FILEXFER_ATTR_ACL = 0x00000040; - - /** - * Indicates that the 'owner' and 'group' fields are present. - */ - public static final int SSH_FILEXFER_ATTR_OWNERGROUP = 0x00000080; - - /** - * Indicates that additionally to the 'atime', 'createtime', - * 'mtime' and 'ctime' fields (if present), there is also - * 'atime-nseconds', 'createtime-nseconds', 'mtime-nseconds' - * and 'ctime-nseconds'. - */ - public static final int SSH_FILEXFER_ATTR_SUBSECOND_TIMES = 0x00000100; - - /** - * Indicates that the 'attrib-bits' and 'attrib-bits-valid' - * fields are present. - */ - public static final int SSH_FILEXFER_ATTR_BITS = 0x00000200; - - /** - * Indicates that the 'allocation-size' field is present. - */ - public static final int SSH_FILEXFER_ATTR_ALLOCATION_SIZE = 0x00000400; - - /** - * Indicates that the 'text-hint' field is present. - */ - public static final int SSH_FILEXFER_ATTR_TEXT_HINT = 0x00000800; - - /** - * Indicates that the 'mime-type' field is present. - */ - public static final int SSH_FILEXFER_ATTR_MIME_TYPE = 0x00001000; - - /** - * Indicates that the 'link-count' field is present. - */ - public static final int SSH_FILEXFER_ATTR_LINK_COUNT = 0x00002000; - - /** - * Indicates that the 'untranslated-name' field is present. - */ - public static final int SSH_FILEXFER_ATTR_UNTRANSLATED_NAME = 0x00004000; - - /** - * Indicates that the 'ctime' field is present. - */ - public static final int SSH_FILEXFER_ATTR_CTIME = 0x00008000; - - /** - * Indicates that the 'extended-count' field (and probablby some - * 'extensions') is present. - */ - public static final int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000; -} diff --git a/src/com/trilead/ssh2/sftp/AttribPermissions.java b/src/com/trilead/ssh2/sftp/AttribPermissions.java deleted file mode 100644 index 558aa6f..0000000 --- a/src/com/trilead/ssh2/sftp/AttribPermissions.java +++ /dev/null @@ -1,32 +0,0 @@ - -package com.trilead.ssh2.sftp; - -/** - * - * Permissions for the 'permissions' field in the SFTP ATTRS data type. - * <p> - * "<i>The 'permissions' field contains a bit mask specifying file permissions. - * These permissions correspond to the st_mode field of the stat structure - * defined by POSIX [IEEE.1003-1.1996].</i>" - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: AttribPermissions.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class AttribPermissions -{ - /* Octal values! */ - - public static final int S_IRUSR = 0400; - public static final int S_IWUSR = 0200; - public static final int S_IXUSR = 0100; - public static final int S_IRGRP = 0040; - public static final int S_IWGRP = 0020; - public static final int S_IXGRP = 0010; - public static final int S_IROTH = 0004; - public static final int S_IWOTH = 0002; - public static final int S_IXOTH = 0001; - public static final int S_ISUID = 04000; - public static final int S_ISGID = 02000; - public static final int S_ISVTX = 01000; -} diff --git a/src/com/trilead/ssh2/sftp/AttribTypes.java b/src/com/trilead/ssh2/sftp/AttribTypes.java deleted file mode 100644 index e2f4169..0000000 --- a/src/com/trilead/ssh2/sftp/AttribTypes.java +++ /dev/null @@ -1,28 +0,0 @@ - -package com.trilead.ssh2.sftp; - -/** - * - * Types for the 'type' field in the SFTP ATTRS data type. - * <p> - * "<i>On a POSIX system, these values would be derived from the mode field - * of the stat structure. SPECIAL should be used for files that are of - * a known type which cannot be expressed in the protocol. UNKNOWN - * should be used if the type is not known.</i>" - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: AttribTypes.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class AttribTypes -{ - public static final int SSH_FILEXFER_TYPE_REGULAR = 1; - public static final int SSH_FILEXFER_TYPE_DIRECTORY = 2; - public static final int SSH_FILEXFER_TYPE_SYMLINK = 3; - public static final int SSH_FILEXFER_TYPE_SPECIAL = 4; - public static final int SSH_FILEXFER_TYPE_UNKNOWN = 5; - public static final int SSH_FILEXFER_TYPE_SOCKET = 6; - public static final int SSH_FILEXFER_TYPE_CHAR_DEVICE = 7; - public static final int SSH_FILEXFER_TYPE_BLOCK_DEVICE = 8; - public static final int SSH_FILEXFER_TYPE_FIFO = 9; -} diff --git a/src/com/trilead/ssh2/sftp/ErrorCodes.java b/src/com/trilead/ssh2/sftp/ErrorCodes.java deleted file mode 100644 index 7317a00..0000000 --- a/src/com/trilead/ssh2/sftp/ErrorCodes.java +++ /dev/null @@ -1,104 +0,0 @@ - -package com.trilead.ssh2.sftp; - -/** - * - * SFTP Error Codes - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ErrorCodes.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class ErrorCodes -{ - public static final int SSH_FX_OK = 0; - public static final int SSH_FX_EOF = 1; - public static final int SSH_FX_NO_SUCH_FILE = 2; - public static final int SSH_FX_PERMISSION_DENIED = 3; - public static final int SSH_FX_FAILURE = 4; - public static final int SSH_FX_BAD_MESSAGE = 5; - public static final int SSH_FX_NO_CONNECTION = 6; - public static final int SSH_FX_CONNECTION_LOST = 7; - public static final int SSH_FX_OP_UNSUPPORTED = 8; - public static final int SSH_FX_INVALID_HANDLE = 9; - public static final int SSH_FX_NO_SUCH_PATH = 10; - public static final int SSH_FX_FILE_ALREADY_EXISTS = 11; - public static final int SSH_FX_WRITE_PROTECT = 12; - public static final int SSH_FX_NO_MEDIA = 13; - public static final int SSH_FX_NO_SPACE_ON_FILESYSTEM = 14; - public static final int SSH_FX_QUOTA_EXCEEDED = 15; - public static final int SSH_FX_UNKNOWN_PRINCIPAL = 16; - public static final int SSH_FX_LOCK_CONFLICT = 17; - public static final int SSH_FX_DIR_NOT_EMPTY = 18; - public static final int SSH_FX_NOT_A_DIRECTORY = 19; - public static final int SSH_FX_INVALID_FILENAME = 20; - public static final int SSH_FX_LINK_LOOP = 21; - public static final int SSH_FX_CANNOT_DELETE = 22; - public static final int SSH_FX_INVALID_PARAMETER = 23; - public static final int SSH_FX_FILE_IS_A_DIRECTORY = 24; - public static final int SSH_FX_BYTE_RANGE_LOCK_CONFLICT = 25; - public static final int SSH_FX_BYTE_RANGE_LOCK_REFUSED = 26; - public static final int SSH_FX_DELETE_PENDING = 27; - public static final int SSH_FX_FILE_CORRUPT = 28; - public static final int SSH_FX_OWNER_INVALID = 29; - public static final int SSH_FX_GROUP_INVALID = 30; - public static final int SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK = 31; - - private static final String[][] messages = { - - { "SSH_FX_OK", "Indicates successful completion of the operation." }, - { "SSH_FX_EOF", - "An attempt to read past the end-of-file was made; or, there are no more directory entries to return." }, - { "SSH_FX_NO_SUCH_FILE", "A reference was made to a file which does not exist." }, - { "SSH_FX_PERMISSION_DENIED", "The user does not have sufficient permissions to perform the operation." }, - { "SSH_FX_FAILURE", "An error occurred, but no specific error code exists to describe the failure." }, - { "SSH_FX_BAD_MESSAGE", "A badly formatted packet or other SFTP protocol incompatibility was detected." }, - { "SSH_FX_NO_CONNECTION", "There is no connection to the server." }, - { "SSH_FX_CONNECTION_LOST", "The connection to the server was lost." }, - { "SSH_FX_OP_UNSUPPORTED", - "An attempted operation could not be completed by the server because the server does not support the operation." }, - { "SSH_FX_INVALID_HANDLE", "The handle value was invalid." }, - { "SSH_FX_NO_SUCH_PATH", "The file path does not exist or is invalid." }, - { "SSH_FX_FILE_ALREADY_EXISTS", "The file already exists." }, - { "SSH_FX_WRITE_PROTECT", "The file is on read-only media, or the media is write protected." }, - { "SSH_FX_NO_MEDIA", - "The requested operation cannot be completed because there is no media available in the drive." }, - { "SSH_FX_NO_SPACE_ON_FILESYSTEM", - "The requested operation cannot be completed because there is insufficient free space on the filesystem." }, - { "SSH_FX_QUOTA_EXCEEDED", - "The operation cannot be completed because it would exceed the user's storage quota." }, - { - "SSH_FX_UNKNOWN_PRINCIPAL", - "A principal referenced by the request (either the 'owner', 'group', or 'who' field of an ACL), was unknown. The error specific data contains the problematic names." }, - { "SSH_FX_LOCK_CONFLICT", "The file could not be opened because it is locked by another process." }, - { "SSH_FX_DIR_NOT_EMPTY", "The directory is not empty." }, - { "SSH_FX_NOT_A_DIRECTORY", "The specified file is not a directory." }, - { "SSH_FX_INVALID_FILENAME", "The filename is not valid." }, - { "SSH_FX_LINK_LOOP", - "Too many symbolic links encountered or, an SSH_FXF_NOFOLLOW open encountered a symbolic link as the final component." }, - { "SSH_FX_CANNOT_DELETE", - "The file cannot be deleted. One possible reason is that the advisory READONLY attribute-bit is set." }, - { "SSH_FX_INVALID_PARAMETER", - "One of the parameters was out of range, or the parameters specified cannot be used together." }, - { "SSH_FX_FILE_IS_A_DIRECTORY", - "The specified file was a directory in a context where a directory cannot be used." }, - { "SSH_FX_BYTE_RANGE_LOCK_CONFLICT", - " A read or write operation failed because another process's mandatory byte-range lock overlaps with the request." }, - { "SSH_FX_BYTE_RANGE_LOCK_REFUSED", "A request for a byte range lock was refused." }, - { "SSH_FX_DELETE_PENDING", "An operation was attempted on a file for which a delete operation is pending." }, - { "SSH_FX_FILE_CORRUPT", "The file is corrupt; an filesystem integrity check should be run." }, - { "SSH_FX_OWNER_INVALID", "The principal specified can not be assigned as an owner of a file." }, - { "SSH_FX_GROUP_INVALID", "The principal specified can not be assigned as the primary group of a file." }, - { "SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK", - "The requested operation could not be completed because the specifed byte range lock has not been granted." }, - - }; - - public static final String[] getDescription(int errorCode) - { - if ((errorCode < 0) || (errorCode >= messages.length)) - return null; - - return messages[errorCode]; - } -} diff --git a/src/com/trilead/ssh2/sftp/OpenFlags.java b/src/com/trilead/ssh2/sftp/OpenFlags.java deleted file mode 100644 index b2979b9..0000000 --- a/src/com/trilead/ssh2/sftp/OpenFlags.java +++ /dev/null @@ -1,223 +0,0 @@ - -package com.trilead.ssh2.sftp; - -/** - * - * SFTP Open Flags. - * - * The following table is provided to assist in mapping POSIX semantics - * to equivalent SFTP file open parameters: - * <p> - * TODO: This comment should be moved to the open method. - * <p> - * <ul> - * <li>O_RDONLY - * <ul><li>desired-access = READ_DATA | READ_ATTRIBUTES</li></ul> - * </li> - * </ul> - * <ul> - * <li>O_WRONLY - * <ul><li>desired-access = WRITE_DATA | WRITE_ATTRIBUTES</li></ul> - * </li> - * </ul> - * <ul> - * <li>O_RDWR - * <ul><li>desired-access = READ_DATA | READ_ATTRIBUTES | WRITE_DATA | WRITE_ATTRIBUTES</li></ul> - * </li> - * </ul> - * <ul> - * <li>O_APPEND - * <ul> - * <li>desired-access = WRITE_DATA | WRITE_ATTRIBUTES | APPEND_DATA</li> - * <li>flags = SSH_FXF_ACCESS_APPEND_DATA and or SSH_FXF_ACCESS_APPEND_DATA_ATOMIC</li> - * </ul> - * </li> - * </ul> - * <ul> - * <li>O_CREAT - * <ul> - * <li>flags = SSH_FXF_OPEN_OR_CREATE</li> - * </ul> - * </li> - * </ul> - * <ul> - * <li>O_TRUNC - * <ul> - * <li>flags = SSH_FXF_TRUNCATE_EXISTING</li> - * </ul> - * </li> - * </ul> - * <ul> - * <li>O_TRUNC|O_CREATE - * <ul> - * <li>flags = SSH_FXF_CREATE_TRUNCATE</li> - * </ul> - * </li> - * </ul> - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: OpenFlags.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - */ -public class OpenFlags -{ - /** - * Disposition is a 3 bit field that controls how the file is opened. - * The server MUST support these bits (possible enumaration values: - * SSH_FXF_CREATE_NEW, SSH_FXF_CREATE_TRUNCATE, SSH_FXF_OPEN_EXISTING, - * SSH_FXF_OPEN_OR_CREATE or SSH_FXF_TRUNCATE_EXISTING). - */ - public static final int SSH_FXF_ACCESS_DISPOSITION = 0x00000007; - - /** - * A new file is created; if the file already exists, the server - * MUST return status SSH_FX_FILE_ALREADY_EXISTS. - */ - public static final int SSH_FXF_CREATE_NEW = 0x00000000; - - /** - * A new file is created; if the file already exists, it is opened - * and truncated. - */ - public static final int SSH_FXF_CREATE_TRUNCATE = 0x00000001; - - /** - * An existing file is opened. If the file does not exist, the - * server MUST return SSH_FX_NO_SUCH_FILE. If a directory in the - * path does not exist, the server SHOULD return - * SSH_FX_NO_SUCH_PATH. It is also acceptable if the server - * returns SSH_FX_NO_SUCH_FILE in this case. - */ - public static final int SSH_FXF_OPEN_EXISTING = 0x00000002; - - /** - * If the file exists, it is opened. If the file does not exist, - * it is created. - */ - public static final int SSH_FXF_OPEN_OR_CREATE = 0x00000003; - - /** - * An existing file is opened and truncated. If the file does not - * exist, the server MUST return the same error codes as defined - * for SSH_FXF_OPEN_EXISTING. - */ - public static final int SSH_FXF_TRUNCATE_EXISTING = 0x00000004; - - /** - * Data is always written at the end of the file. The offset field - * of the SSH_FXP_WRITE requests are ignored. - * <p> - * Data is not required to be appended atomically. This means that - * if multiple writers attempt to append data simultaneously, data - * from the first may be lost. However, data MAY be appended - * atomically. - */ - public static final int SSH_FXF_ACCESS_APPEND_DATA = 0x00000008; - - /** - * Data is always written at the end of the file. The offset field - * of the SSH_FXP_WRITE requests are ignored. - * <p> - * Data MUST be written atomically so that there is no chance that - * multiple appenders can collide and result in data being lost. - * <p> - * If both append flags are specified, the server SHOULD use atomic - * append if it is available, but SHOULD use non-atomic appends - * otherwise. The server SHOULD NOT fail the request in this case. - */ - public static final int SSH_FXF_ACCESS_APPEND_DATA_ATOMIC = 0x00000010; - - /** - * Indicates that the server should treat the file as text and - * convert it to the canonical newline convention in use. - * (See Determining Server Newline Convention in section 5.3 in the - * SFTP standard draft). - * <p> - * When a file is opened with this flag, the offset field in the read - * and write functions is ignored. - * <p> - * Servers MUST process multiple, parallel reads and writes correctly - * in this mode. Naturally, it is permissible for them to do this by - * serializing the requests. - * <p> - * Clients SHOULD use the SSH_FXF_ACCESS_APPEND_DATA flag to append - * data to a text file rather then using write with a calculated offset. - */ - public static final int SSH_FXF_ACCESS_TEXT_MODE = 0x00000020; - - /** - * The server MUST guarantee that no other handle has been opened - * with ACE4_READ_DATA access, and that no other handle will be - * opened with ACE4_READ_DATA access until the client closes the - * handle. (This MUST apply both to other clients and to other - * processes on the server.) - * <p> - * If there is a conflicting lock the server MUST return - * SSH_FX_LOCK_CONFLICT. If the server cannot make the locking - * guarantee, it MUST return SSH_FX_OP_UNSUPPORTED. - * <p> - * Other handles MAY be opened for ACE4_WRITE_DATA or any other - * combination of accesses, as long as ACE4_READ_DATA is not included - * in the mask. - */ - public static final int SSH_FXF_ACCESS_BLOCK_READ = 0x00000040; - - /** - * The server MUST guarantee that no other handle has been opened - * with ACE4_WRITE_DATA or ACE4_APPEND_DATA access, and that no other - * handle will be opened with ACE4_WRITE_DATA or ACE4_APPEND_DATA - * access until the client closes the handle. (This MUST apply both - * to other clients and to other processes on the server.) - * <p> - * If there is a conflicting lock the server MUST return - * SSH_FX_LOCK_CONFLICT. If the server cannot make the locking - * guarantee, it MUST return SSH_FX_OP_UNSUPPORTED. - * <p> - * Other handles MAY be opened for ACE4_READ_DATA or any other - * combination of accesses, as long as neither ACE4_WRITE_DATA nor - * ACE4_APPEND_DATA are included in the mask. - */ - public static final int SSH_FXF_ACCESS_BLOCK_WRITE = 0x00000080; - - /** - * The server MUST guarantee that no other handle has been opened - * with ACE4_DELETE access, opened with the - * SSH_FXF_ACCESS_DELETE_ON_CLOSE flag set, and that no other handle - * will be opened with ACE4_DELETE access or with the - * SSH_FXF_ACCESS_DELETE_ON_CLOSE flag set, and that the file itself - * is not deleted in any other way until the client closes the handle. - * <p> - * If there is a conflicting lock the server MUST return - * SSH_FX_LOCK_CONFLICT. If the server cannot make the locking - * guarantee, it MUST return SSH_FX_OP_UNSUPPORTED. - */ - public static final int SSH_FXF_ACCESS_BLOCK_DELETE = 0x00000100; - - /** - * If this bit is set, the above BLOCK modes are advisory. In advisory - * mode, only other accesses that specify a BLOCK mode need be - * considered when determining whether the BLOCK can be granted, - * and the server need not prevent I/O operations that violate the - * block mode. - * <p> - * The server MAY perform mandatory locking even if the BLOCK_ADVISORY - * bit is set. - */ - public static final int SSH_FXF_ACCESS_BLOCK_ADVISORY = 0x00000200; - - /** - * If the final component of the path is a symlink, then the open - * MUST fail, and the error SSH_FX_LINK_LOOP MUST be returned. - */ - public static final int SSH_FXF_ACCESS_NOFOLLOW = 0x00000400; - - /** - * The file should be deleted when the last handle to it is closed. - * (The last handle may not be an sftp-handle.) This MAY be emulated - * by a server if the OS doesn't support it by deleting the file when - * this handle is closed. - * <p> - * It is implementation specific whether the directory entry is - * removed immediately or when the handle is closed. - */ - public static final int SSH_FXF_ACCESS_DELETE_ON_CLOSE = 0x00000800; -} diff --git a/src/com/trilead/ssh2/sftp/Packet.java b/src/com/trilead/ssh2/sftp/Packet.java deleted file mode 100644 index 444af90..0000000 --- a/src/com/trilead/ssh2/sftp/Packet.java +++ /dev/null @@ -1,43 +0,0 @@ - -package com.trilead.ssh2.sftp; - -/** - * - * SFTP Paket Types - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Packet.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ - * - */ -public class Packet -{ - public static final int SSH_FXP_INIT = 1; - public static final int SSH_FXP_VERSION = 2; - public static final int SSH_FXP_OPEN = 3; - public static final int SSH_FXP_CLOSE = 4; - public static final int SSH_FXP_READ = 5; - public static final int SSH_FXP_WRITE = 6; - public static final int SSH_FXP_LSTAT = 7; - public static final int SSH_FXP_FSTAT = 8; - public static final int SSH_FXP_SETSTAT = 9; - public static final int SSH_FXP_FSETSTAT = 10; - public static final int SSH_FXP_OPENDIR = 11; - public static final int SSH_FXP_READDIR = 12; - public static final int SSH_FXP_REMOVE = 13; - public static final int SSH_FXP_MKDIR = 14; - public static final int SSH_FXP_RMDIR = 15; - public static final int SSH_FXP_REALPATH = 16; - public static final int SSH_FXP_STAT = 17; - public static final int SSH_FXP_RENAME = 18; - public static final int SSH_FXP_READLINK = 19; - public static final int SSH_FXP_SYMLINK = 20; - - public static final int SSH_FXP_STATUS = 101; - public static final int SSH_FXP_HANDLE = 102; - public static final int SSH_FXP_DATA = 103; - public static final int SSH_FXP_NAME = 104; - public static final int SSH_FXP_ATTRS = 105; - - public static final int SSH_FXP_EXTENDED = 200; - public static final int SSH_FXP_EXTENDED_REPLY = 201; -} diff --git a/src/com/trilead/ssh2/signature/DSASHA1Verify.java b/src/com/trilead/ssh2/signature/DSASHA1Verify.java deleted file mode 100644 index 6fb6ddb..0000000 --- a/src/com/trilead/ssh2/signature/DSASHA1Verify.java +++ /dev/null @@ -1,255 +0,0 @@ - -package com.trilead.ssh2.signature; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; - -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.packets.TypesWriter; - - -/** - * DSASHA1Verify. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: DSASHA1Verify.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class DSASHA1Verify -{ - private static final Logger log = Logger.getLogger(DSASHA1Verify.class); - - public static DSAPublicKey decodeSSHDSAPublicKey(byte[] key) throws IOException - { - TypesReader tr = new TypesReader(key); - - String key_format = tr.readString(); - - if (key_format.equals("ssh-dss") == false) - throw new IllegalArgumentException("This is not a ssh-dss public key!"); - - BigInteger p = tr.readMPINT(); - BigInteger q = tr.readMPINT(); - BigInteger g = tr.readMPINT(); - BigInteger y = tr.readMPINT(); - - if (tr.remain() != 0) - throw new IOException("Padding in DSA public key!"); - - try { - KeyFactory kf = KeyFactory.getInstance("DSA"); - - KeySpec ks = new DSAPublicKeySpec(y, p, q, g); - return (DSAPublicKey) kf.generatePublic(ks); - } catch (NoSuchAlgorithmException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (InvalidKeySpecException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } - } - - public static byte[] encodeSSHDSAPublicKey(DSAPublicKey pk) throws IOException - { - TypesWriter tw = new TypesWriter(); - - tw.writeString("ssh-dss"); - - DSAParams params = pk.getParams(); - tw.writeMPInt(params.getP()); - tw.writeMPInt(params.getQ()); - tw.writeMPInt(params.getG()); - tw.writeMPInt(pk.getY()); - - return tw.getBytes(); - } - - /** - * Convert from Java's signature ASN.1 encoding to the SSH spec. - * <p> - * Java ASN.1 encoding: - * <pre> - * SEQUENCE ::= { - * r INTEGER, - * s INTEGER - * } - * </pre> - */ - public static byte[] encodeSSHDSASignature(byte[] ds) - { - TypesWriter tw = new TypesWriter(); - - tw.writeString("ssh-dss"); - - int len, index; - - index = 3; - len = ds[index++] & 0xff; - byte[] r = new byte[len]; - System.arraycopy(ds, index, r, 0, r.length); - - index = index + len + 1; - len = ds[index++] & 0xff; - byte[] s = new byte[len]; - System.arraycopy(ds, index, s, 0, s.length); - - byte[] a40 = new byte[40]; - - /* Patch (unsigned) r and s into the target array. */ - - int r_copylen = (r.length < 20) ? r.length : 20; - int s_copylen = (s.length < 20) ? s.length : 20; - - System.arraycopy(r, r.length - r_copylen, a40, 20 - r_copylen, r_copylen); - System.arraycopy(s, s.length - s_copylen, a40, 40 - s_copylen, s_copylen); - - tw.writeString(a40, 0, 40); - - return tw.getBytes(); - } - - public static byte[] decodeSSHDSASignature(byte[] sig) throws IOException - { - byte[] rsArray = null; - - if (sig.length == 40) - { - /* OK, another broken SSH server. */ - rsArray = sig; - } - else - { - /* Hopefully a server obeying the standard... */ - TypesReader tr = new TypesReader(sig); - - String sig_format = tr.readString(); - if (sig_format.equals("ssh-dss") == false) - throw new IOException("Peer sent wrong signature format"); - - rsArray = tr.readByteString(); - - if (rsArray.length != 40) - throw new IOException("Peer sent corrupt signature"); - - if (tr.remain() != 0) - throw new IOException("Padding in DSA signature!"); - } - - int i = 0; - int j = 0; - byte[] tmp; - - if (rsArray[0] == 0 && rsArray[1] == 0 && rsArray[2] == 0) { - j = ((rsArray[i++] << 24) & 0xff000000) | ((rsArray[i++] << 16) & 0x00ff0000) - | ((rsArray[i++] << 8) & 0x0000ff00) | ((rsArray[i++]) & 0x000000ff); - i += j; - j = ((rsArray[i++] << 24) & 0xff000000) | ((rsArray[i++] << 16) & 0x00ff0000) - | ((rsArray[i++] << 8) & 0x0000ff00) | ((rsArray[i++]) & 0x000000ff); - tmp = new byte[j]; - System.arraycopy(rsArray, i, tmp, 0, j); - rsArray = tmp; - } - - /* ASN.1 */ - int frst = ((rsArray[0] & 0x80) != 0 ? 1 : 0); - int scnd = ((rsArray[20] & 0x80) != 0 ? 1 : 0); - - /* Calculate output length */ - int length = rsArray.length + 6 + frst + scnd; - tmp = new byte[length]; - - /* DER-encoding to match Java */ - tmp[0] = (byte) 0x30; - - if (rsArray.length != 40) - throw new IOException("Peer sent corrupt signature"); - /* Calculate length */ - tmp[1] = (byte) 0x2c; - tmp[1] += frst; - tmp[1] += scnd; - - /* First item */ - tmp[2] = (byte) 0x02; - - /* First item length */ - tmp[3] = (byte) 0x14; - tmp[3] += frst; - - /* Copy in the data for first item */ - System.arraycopy(rsArray, 0, tmp, 4 + frst, 20); - - /* Second item */ - tmp[4 + tmp[3]] = (byte) 0x02; - - /* Second item length */ - tmp[5 + tmp[3]] = (byte) 0x14; - tmp[5 + tmp[3]] += scnd; - - /* Copy in the data for the second item */ - System.arraycopy(rsArray, 20, tmp, 6 + tmp[3] + scnd, 20); - - /* Swap buffers */ - rsArray = tmp; - - return rsArray; - } - - public static boolean verifySignature(byte[] message, byte[] ds, DSAPublicKey dpk) throws IOException - { - try { - Signature s = Signature.getInstance("SHA1withDSA"); - s.initVerify(dpk); - s.update(message); - return s.verify(ds); - } catch (NoSuchAlgorithmException e) { - IOException ex = new IOException("No such algorithm"); - ex.initCause(e); - throw ex; - } catch (InvalidKeyException e) { - IOException ex = new IOException("No such algorithm"); - ex.initCause(e); - throw ex; - } catch (SignatureException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } - } - - public static byte[] generateSignature(byte[] message, DSAPrivateKey pk, SecureRandom rnd) throws IOException - { - try { - Signature s = Signature.getInstance("SHA1withDSA"); - s.initSign(pk); - s.update(message); - return s.sign(); - } catch (NoSuchAlgorithmException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (InvalidKeyException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (SignatureException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } - } -} diff --git a/src/com/trilead/ssh2/signature/ECDSASHA2Verify.java b/src/com/trilead/ssh2/signature/ECDSASHA2Verify.java deleted file mode 100644 index f139cdf..0000000 --- a/src/com/trilead/ssh2/signature/ECDSASHA2Verify.java +++ /dev/null @@ -1,487 +0,0 @@ -/** - * - */ -package com.trilead.ssh2.signature; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.ECFieldFp; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.EllipticCurve; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.util.Map; -import java.util.TreeMap; - -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.packets.TypesWriter; - -/** - * @author Kenny Root - * - */ -public class ECDSASHA2Verify { - private static final Logger log = Logger.getLogger(ECDSASHA2Verify.class); - - public static final String ECDSA_SHA2_PREFIX = "ecdsa-sha2-"; - - private static final String NISTP256 = "nistp256"; - private static final String NISTP256_OID = "1.2.840.10045.3.1.7"; - private static final String NISTP384 = "nistp384"; - private static final String NISTP384_OID = "1.3.132.0.34"; - private static final String NISTP521 = "nistp521"; - private static final String NISTP521_OID = "1.3.132.0.35"; - - private static final Map<String, ECParameterSpec> CURVES = new TreeMap<String, ECParameterSpec>(); - static { - CURVES.put(NISTP256, EllipticCurves.nistp256); - CURVES.put(NISTP384, EllipticCurves.nistp384); - CURVES.put(NISTP521, EllipticCurves.nistp521); - } - - private static final Map<Integer, String> CURVE_SIZES = new TreeMap<Integer, String>(); - static { - CURVE_SIZES.put(256, NISTP256); - CURVE_SIZES.put(384, NISTP384); - CURVE_SIZES.put(521, NISTP521); - } - - private static final Map<String, String> CURVE_OIDS = new TreeMap<String, String>(); - static { - CURVE_OIDS.put(NISTP256_OID, NISTP256); - CURVE_OIDS.put(NISTP384_OID, NISTP256); - CURVE_OIDS.put(NISTP521_OID, NISTP256); - } - - public static int[] getCurveSizes() { - int[] keys = new int[CURVE_SIZES.size()]; - int i = 0; - for (Integer n : CURVE_SIZES.keySet().toArray(new Integer[keys.length])) { - keys[i++] = n; - } - return keys; - } - - public static ECParameterSpec getCurveForSize(int size) { - final String name = CURVE_SIZES.get(size); - if (name == null) { - return null; - } - return CURVES.get(name); - } - - public static ECPublicKey decodeSSHECDSAPublicKey(byte[] key) throws IOException - { - TypesReader tr = new TypesReader(key); - - String key_format = tr.readString(); - - if (key_format.startsWith(ECDSA_SHA2_PREFIX) == false) - throw new IllegalArgumentException("This is not an ECDSA public key"); - - String curveName = tr.readString(); - byte[] groupBytes = tr.readByteString(); - - if (tr.remain() != 0) - throw new IOException("Padding in ECDSA public key!"); - - if (key_format.equals(ECDSA_SHA2_PREFIX + curveName) == false) { - throw new IOException("Key format is inconsistent with curve name: " + key_format - + " != " + curveName); - } - - ECParameterSpec params = CURVES.get(curveName); - if (params == null) { - throw new IOException("Curve is not supported: " + curveName); - } - - ECPoint group = ECDSASHA2Verify.decodeECPoint(groupBytes, params.getCurve()); - if (group == null) { - throw new IOException("Invalid ECDSA group"); - } - - KeySpec keySpec = new ECPublicKeySpec(group, params); - - try { - KeyFactory kf = KeyFactory.getInstance("EC"); - return (ECPublicKey) kf.generatePublic(keySpec); - } catch (NoSuchAlgorithmException nsae) { - IOException ioe = new IOException("No EC KeyFactory available"); - ioe.initCause(nsae); - throw ioe; - } catch (InvalidKeySpecException ikse) { - IOException ioe = new IOException("No EC KeyFactory available"); - ioe.initCause(ikse); - throw ioe; - } - } - - public static byte[] encodeSSHECDSAPublicKey(ECPublicKey key) throws IOException { - TypesWriter tw = new TypesWriter(); - - String curveName = getCurveName(key.getParams()); - - String keyFormat = ECDSA_SHA2_PREFIX + curveName; - - tw.writeString(keyFormat); - - tw.writeString(curveName); - - byte[] encoded = encodeECPoint(key.getW(), key.getParams().getCurve()); - tw.writeString(encoded, 0, encoded.length); - - return tw.getBytes(); - } - - public static String getCurveName(ECParameterSpec params) throws IOException { - int fieldSize = getCurveSize(params); - final String curveName = getCurveName(fieldSize); - if (curveName == null) { - throw new IOException("invalid curve size " + fieldSize); - } - return curveName; - } - - public static String getCurveName(int fieldSize) { - String curveName = CURVE_SIZES.get(fieldSize); - if (curveName == null) { - return null; - } - return curveName; - } - - public static int getCurveSize(ECParameterSpec params) { - return params.getCurve().getField().getFieldSize(); - } - - public static ECParameterSpec getCurveForOID(String oid) { - String name = CURVE_OIDS.get(oid); - if (name == null) - return null; - return CURVES.get(name); - } - - public static byte[] decodeSSHECDSASignature(byte[] sig) throws IOException { - byte[] rsArray = null; - - TypesReader tr = new TypesReader(sig); - - String sig_format = tr.readString(); - if (sig_format.startsWith(ECDSA_SHA2_PREFIX) == false) - throw new IOException("Peer sent wrong signature format"); - - String curveName = sig_format.substring(ECDSA_SHA2_PREFIX.length()); - if (CURVES.containsKey(curveName) == false) { - throw new IOException("Unsupported curve: " + curveName); - } - - rsArray = tr.readByteString(); - - if (tr.remain() != 0) - throw new IOException("Padding in ECDSA signature!"); - - byte[] rArray; - byte[] sArray; - { - TypesReader rsReader = new TypesReader(rsArray); - rArray = rsReader.readMPINT().toByteArray(); - sArray = rsReader.readMPINT().toByteArray(); - } - - int first = rArray.length; - int second = sArray.length; - - /* We can't have the high bit set, so add an extra zero at the beginning if so. */ - if ((rArray[0] & 0x80) != 0) { - first++; - } - if ((sArray[0] & 0x80) != 0) { - second++; - } - - /* Calculate total output length */ - ByteArrayOutputStream os = new ByteArrayOutputStream(6 + first + second); - - /* ASN.1 SEQUENCE tag */ - os.write(0x30); - - /* Size of SEQUENCE */ - writeLength(4 + first + second, os); - - /* ASN.1 INTEGER tag */ - os.write(0x02); - - /* "r" INTEGER length */ - writeLength(first, os); - - /* Copy in the "r" INTEGER */ - if (first != rArray.length) { - os.write(0x00); - } - os.write(rArray); - - /* ASN.1 INTEGER tag */ - os.write(0x02); - - /* "s" INTEGER length */ - writeLength(second, os); - - /* Copy in the "s" INTEGER */ - if (second != sArray.length) { - os.write(0x00); - } - os.write(sArray); - - return os.toByteArray(); - } - - private static final void writeLength(int length, OutputStream os) throws IOException { - if (length <= 0x7F) { - os.write(length); - return; - } - - int numOctets = 0; - int lenCopy = length; - while (lenCopy != 0) { - lenCopy >>>= 8; - numOctets++; - } - - os.write(0x80 | numOctets); - - for (int i = (numOctets - 1) * 8; i >= 0; i -= 8) { - os.write((byte) (length >> i)); - } - } - - public static byte[] encodeSSHECDSASignature(byte[] sig, ECParameterSpec params) throws IOException - { - TypesWriter tw = new TypesWriter(); - - String curveName = getCurveName(params); - tw.writeString(ECDSA_SHA2_PREFIX + curveName); - - if ((sig[0] != 0x30) || (sig[1] != sig.length - 2) || (sig[2] != 0x02)) { - throw new IOException("Invalid signature format"); - } - - int rLength = sig[3]; - if ((rLength + 6 > sig.length) || (sig[4 + rLength] != 0x02)) { - throw new IOException("Invalid signature format"); - } - - int sLength = sig[5 + rLength]; - if (6 + rLength + sLength > sig.length) { - throw new IOException("Invalid signature format"); - } - - byte[] rArray = new byte[rLength]; - byte[] sArray = new byte[sLength]; - - System.arraycopy(sig, 4, rArray, 0, rLength); - System.arraycopy(sig, 6 + rLength, sArray, 0, sLength); - - BigInteger r = new BigInteger(rArray); - BigInteger s = new BigInteger(sArray); - - // Write the <r,s> to its own types writer. - TypesWriter rsWriter = new TypesWriter(); - rsWriter.writeMPInt(r); - rsWriter.writeMPInt(s); - byte[] encoded = rsWriter.getBytes(); - tw.writeString(encoded, 0, encoded.length); - - return tw.getBytes(); - } - - public static byte[] generateSignature(byte[] message, ECPrivateKey pk) throws IOException - { - final String algo = getSignatureAlgorithmForParams(pk.getParams()); - - try { - Signature s = Signature.getInstance(algo); - s.initSign(pk); - s.update(message); - return s.sign(); - } catch (NoSuchAlgorithmException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (InvalidKeyException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (SignatureException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } - } - - public static boolean verifySignature(byte[] message, byte[] ds, ECPublicKey dpk) throws IOException - { - final String algo = getSignatureAlgorithmForParams(dpk.getParams()); - - try { - Signature s = Signature.getInstance(algo); - s.initVerify(dpk); - s.update(message); - return s.verify(ds); - } catch (NoSuchAlgorithmException e) { - IOException ex = new IOException("No such algorithm"); - ex.initCause(e); - throw ex; - } catch (InvalidKeyException e) { - IOException ex = new IOException("No such algorithm"); - ex.initCause(e); - throw ex; - } catch (SignatureException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } - } - - private static String getSignatureAlgorithmForParams(ECParameterSpec params) { - int size = getCurveSize(params); - if (size <= 256) { - return "SHA256withECDSA"; - } else if (size <= 384) { - return "SHA384withECDSA"; - } else { - return "SHA512withECDSA"; - } - } - - public static String getDigestAlgorithmForParams(ECParameterSpec params) { - int size = getCurveSize(params); - if (size <= 256) { - return "SHA256"; - } else if (size <= 384) { - return "SHA384"; - } else { - return "SHA512"; - } - } - - /** - * Decode an OctetString to EllipticCurvePoint according to SECG 2.3.4 - */ - public static ECPoint decodeECPoint(byte[] M, EllipticCurve curve) { - if (M.length == 0) { - return null; - } - - // M has len 2 ceil(log_2(q)/8) + 1 ? - int elementSize = (curve.getField().getFieldSize() + 7) / 8; - if (M.length != 2 * elementSize + 1) { - return null; - } - - // step 3.2 - if (M[0] != 0x04) { - return null; - } - - // Step 3.3 - byte[] xp = new byte[elementSize]; - System.arraycopy(M, 1, xp, 0, elementSize); - - // Step 3.4 - byte[] yp = new byte[elementSize]; - System.arraycopy(M, 1 + elementSize, yp, 0, elementSize); - - ECPoint P = new ECPoint(new BigInteger(1, xp), new BigInteger(1, yp)); - - // TODO check point 3.5 - - // Step 3.6 - return P; - } - - /** - * Encode EllipticCurvePoint to an OctetString - */ - public static byte[] encodeECPoint(ECPoint group, EllipticCurve curve) - { - // M has len 2 ceil(log_2(q)/8) + 1 ? - int elementSize = (curve.getField().getFieldSize() + 7) / 8; - byte[] M = new byte[2 * elementSize + 1]; - - // Uncompressed format - M[0] = 0x04; - - { - byte[] affineX = removeLeadingZeroes(group.getAffineX().toByteArray()); - System.arraycopy(affineX, 0, M, 1 + elementSize - affineX.length, affineX.length); - } - - { - byte[] affineY = removeLeadingZeroes(group.getAffineY().toByteArray()); - System.arraycopy(affineY, 0, M, 1 + elementSize + elementSize - affineY.length, - affineY.length); - } - - return M; - } - - private static byte[] removeLeadingZeroes(byte[] input) { - if (input[0] != 0x00) { - return input; - } - - int pos = 1; - while (pos < input.length - 1 && input[pos] == 0x00) { - pos++; - } - - byte[] output = new byte[input.length - pos]; - System.arraycopy(input, pos, output, 0, output.length); - return output; - } - - public static class EllipticCurves { - public static ECParameterSpec nistp256 = new ECParameterSpec( - new EllipticCurve( - new ECFieldFp(new BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16)), - new BigInteger("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16), - new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)), - new ECPoint(new BigInteger("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16), - new BigInteger("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16)), - new BigInteger("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16), - 1); - - public static ECParameterSpec nistp384 = new ECParameterSpec( - new EllipticCurve( - new ECFieldFp(new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", 16)), - new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", 16), - new BigInteger("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", 16)), - new ECPoint(new BigInteger("AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", 16), - new BigInteger("3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", 16)), - new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", 16), - 1); - - public static ECParameterSpec nistp521 = new ECParameterSpec( - new EllipticCurve( - new ECFieldFp(new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)), - new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16), - new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16)), - new ECPoint(new BigInteger("00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", 16), - new BigInteger("011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", 16)), - new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16), - 1); - } -} diff --git a/src/com/trilead/ssh2/signature/RSASHA1Verify.java b/src/com/trilead/ssh2/signature/RSASHA1Verify.java deleted file mode 100644 index 3406312..0000000 --- a/src/com/trilead/ssh2/signature/RSASHA1Verify.java +++ /dev/null @@ -1,180 +0,0 @@ - -package com.trilead.ssh2.signature; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.security.spec.RSAPublicKeySpec; - -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.packets.TypesWriter; - - -/** - * RSASHA1Verify. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: RSASHA1Verify.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public class RSASHA1Verify -{ - private static final Logger log = Logger.getLogger(RSASHA1Verify.class); - - public static RSAPublicKey decodeSSHRSAPublicKey(byte[] key) throws IOException - { - TypesReader tr = new TypesReader(key); - - String key_format = tr.readString(); - - if (key_format.equals("ssh-rsa") == false) - throw new IllegalArgumentException("This is not a ssh-rsa public key"); - - BigInteger e = tr.readMPINT(); - BigInteger n = tr.readMPINT(); - - if (tr.remain() != 0) - throw new IOException("Padding in RSA public key!"); - - KeySpec keySpec = new RSAPublicKeySpec(n, e); - - try { - KeyFactory kf = KeyFactory.getInstance("RSA"); - return (RSAPublicKey) kf.generatePublic(keySpec); - } catch (NoSuchAlgorithmException nsae) { - IOException ioe = new IOException("No RSA KeyFactory available"); - ioe.initCause(nsae); - throw ioe; - } catch (InvalidKeySpecException ikse) { - IOException ioe = new IOException("No RSA KeyFactory available"); - ioe.initCause(ikse); - throw ioe; - } - } - - public static byte[] encodeSSHRSAPublicKey(RSAPublicKey pk) throws IOException - { - TypesWriter tw = new TypesWriter(); - - tw.writeString("ssh-rsa"); - tw.writeMPInt(pk.getPublicExponent()); - tw.writeMPInt(pk.getModulus()); - - return tw.getBytes(); - } - - public static byte[] decodeSSHRSASignature(byte[] sig) throws IOException - { - TypesReader tr = new TypesReader(sig); - - String sig_format = tr.readString(); - - if (sig_format.equals("ssh-rsa") == false) - throw new IOException("Peer sent wrong signature format"); - - /* S is NOT an MPINT. "The value for 'rsa_signature_blob' is encoded as a string - * containing s (which is an integer, without lengths or padding, unsigned and in - * network byte order)." See also below. - */ - - byte[] s = tr.readByteString(); - - if (s.length == 0) - throw new IOException("Error in RSA signature, S is empty."); - - if (log.isEnabled()) - { - log.log(80, "Decoding ssh-rsa signature string (length: " + s.length + ")"); - } - - if (tr.remain() != 0) - throw new IOException("Padding in RSA signature!"); - - if (s[0] == 0 && s[1] == 0 && s[2] == 0) { - int i = 0; - int j = ((s[i++] << 24) & 0xff000000) | ((s[i++] << 16) & 0x00ff0000) - | ((s[i++] << 8) & 0x0000ff00) | ((s[i++]) & 0x000000ff); - i += j; - j = ((s[i++] << 24) & 0xff000000) | ((s[i++] << 16) & 0x00ff0000) - | ((s[i++] << 8) & 0x0000ff00) | ((s[i++]) & 0x000000ff); - byte[] tmp = new byte[j]; - System.arraycopy(s, i, tmp, 0, j); - sig = tmp; - } - - return s; - } - - public static byte[] encodeSSHRSASignature(byte[] s) throws IOException - { - TypesWriter tw = new TypesWriter(); - - tw.writeString("ssh-rsa"); - - /* S is NOT an MPINT. "The value for 'rsa_signature_blob' is encoded as a string - * containing s (which is an integer, without lengths or padding, unsigned and in - * network byte order)." - */ - - /* Remove first zero sign byte, if present */ - - if ((s.length > 1) && (s[0] == 0x00)) - tw.writeString(s, 1, s.length - 1); - else - tw.writeString(s, 0, s.length); - - return tw.getBytes(); - } - - public static byte[] generateSignature(byte[] message, RSAPrivateKey pk) throws IOException - { - try { - Signature s = Signature.getInstance("SHA1withRSA"); - s.initSign(pk); - s.update(message); - return s.sign(); - } catch (NoSuchAlgorithmException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (InvalidKeyException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (SignatureException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } - } - - public static boolean verifySignature(byte[] message, byte[] ds, RSAPublicKey dpk) throws IOException - { - try { - Signature s = Signature.getInstance("SHA1withRSA"); - s.initVerify(dpk); - s.update(message); - return s.verify(ds); - } catch (NoSuchAlgorithmException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (InvalidKeyException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } catch (SignatureException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; - } - } -} diff --git a/src/com/trilead/ssh2/transport/ClientServerHello.java b/src/com/trilead/ssh2/transport/ClientServerHello.java deleted file mode 100644 index d7a5ee5..0000000 --- a/src/com/trilead/ssh2/transport/ClientServerHello.java +++ /dev/null @@ -1,125 +0,0 @@ - -package com.trilead.ssh2.transport; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; - -import com.trilead.ssh2.Connection; - -/** - * ClientServerHello. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: ClientServerHello.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class ClientServerHello -{ - String server_line; - String client_line; - - String server_versioncomment; - - public final static int readLineRN(InputStream is, byte[] buffer) throws IOException - { - int pos = 0; - boolean need10 = false; - int len = 0; - while (true) - { - int c = is.read(); - if (c == -1) - throw new IOException("Premature connection close"); - - buffer[pos++] = (byte) c; - - if (c == 13) - { - need10 = true; - continue; - } - - if (c == 10) - break; - - if (need10 == true) - throw new IOException("Malformed line sent by the server, the line does not end correctly."); - - len++; - if (pos >= buffer.length) - throw new IOException("The server sent a too long line."); - } - - return len; - } - - public ClientServerHello(InputStream bi, OutputStream bo) throws IOException - { - client_line = "SSH-2.0-" + Connection.identification; - - bo.write((client_line + "\r\n").getBytes("ISO-8859-1")); - bo.flush(); - - byte[] serverVersion = new byte[512]; - - for (int i = 0; i < 50; i++) - { - int len = readLineRN(bi, serverVersion); - - server_line = new String(serverVersion, 0, len, "ISO-8859-1"); - - if (server_line.startsWith("SSH-")) - break; - } - - if (server_line.startsWith("SSH-") == false) - throw new IOException( - "Malformed server identification string. There was no line starting with 'SSH-' amongst the first 50 lines."); - - if (server_line.startsWith("SSH-1.99-")) - server_versioncomment = server_line.substring(9); - else if (server_line.startsWith("SSH-2.0-")) - server_versioncomment = server_line.substring(8); - else - throw new IOException("Server uses incompatible protocol, it is not SSH-2 compatible."); - } - - /** - * @return Returns the client_versioncomment. - */ - public byte[] getClientString() - { - byte[] result; - - try - { - result = client_line.getBytes("ISO-8859-1"); - } - catch (UnsupportedEncodingException ign) - { - result = client_line.getBytes(); - } - - return result; - } - - /** - * @return Returns the server_versioncomment. - */ - public byte[] getServerString() - { - byte[] result; - - try - { - result = server_line.getBytes("ISO-8859-1"); - } - catch (UnsupportedEncodingException ign) - { - result = server_line.getBytes(); - } - - return result; - } -} diff --git a/src/com/trilead/ssh2/transport/KexManager.java b/src/com/trilead/ssh2/transport/KexManager.java deleted file mode 100644 index cd26530..0000000 --- a/src/com/trilead/ssh2/transport/KexManager.java +++ /dev/null @@ -1,671 +0,0 @@ - -package com.trilead.ssh2.transport; - -import java.io.IOException; -import java.security.SecureRandom; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.util.Set; -import java.util.TreeSet; - -import com.trilead.ssh2.ConnectionInfo; -import com.trilead.ssh2.DHGexParameters; -import com.trilead.ssh2.ServerHostKeyVerifier; -import com.trilead.ssh2.compression.CompressionFactory; -import com.trilead.ssh2.compression.ICompressor; -import com.trilead.ssh2.crypto.CryptoWishList; -import com.trilead.ssh2.crypto.KeyMaterial; -import com.trilead.ssh2.crypto.cipher.BlockCipher; -import com.trilead.ssh2.crypto.cipher.BlockCipherFactory; -import com.trilead.ssh2.crypto.dh.DhGroupExchange; -import com.trilead.ssh2.crypto.dh.GenericDhExchange; -import com.trilead.ssh2.crypto.digest.MAC; -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.PacketKexDHInit; -import com.trilead.ssh2.packets.PacketKexDHReply; -import com.trilead.ssh2.packets.PacketKexDhGexGroup; -import com.trilead.ssh2.packets.PacketKexDhGexInit; -import com.trilead.ssh2.packets.PacketKexDhGexReply; -import com.trilead.ssh2.packets.PacketKexDhGexRequest; -import com.trilead.ssh2.packets.PacketKexDhGexRequestOld; -import com.trilead.ssh2.packets.PacketKexInit; -import com.trilead.ssh2.packets.PacketNewKeys; -import com.trilead.ssh2.packets.Packets; -import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.ECDSASHA2Verify; -import com.trilead.ssh2.signature.RSASHA1Verify; - - -/** - * KexManager. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: KexManager.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class KexManager -{ - private static final Logger log = Logger.getLogger(KexManager.class); - - private static final Set<String> HOSTKEY_ALGS = new TreeSet<String>(); - static { - HOSTKEY_ALGS.add("ecdsa-sha2-nistp256"); - HOSTKEY_ALGS.add("ecdsa-sha2-nistp384"); - HOSTKEY_ALGS.add("ecdsa-sha2-nistp521"); - HOSTKEY_ALGS.add("ssh-rsa"); - HOSTKEY_ALGS.add("ssh-dsa"); - } - - private static final Set<String> KEX_ALGS = new TreeSet<String>(); - static { - KEX_ALGS.add("ecdh-sha2-nistp256"); - KEX_ALGS.add("ecdh-sha2-nistp384"); - KEX_ALGS.add("ecdh-sha2-nistp521"); - KEX_ALGS.add("diffie-hellman-group-exchange-sha256"); - KEX_ALGS.add("diffie-hellman-group-exchange-sha1"); - KEX_ALGS.add("diffie-hellman-group14-sha1"); - KEX_ALGS.add("diffie-hellman-group1-sha1"); - } - - KexState kxs; - int kexCount = 0; - KeyMaterial km; - byte[] sessionId; - ClientServerHello csh; - - final Object accessLock = new Object(); - ConnectionInfo lastConnInfo = null; - - boolean connectionClosed = false; - - boolean ignore_next_kex_packet = false; - - final TransportManager tm; - - CryptoWishList nextKEXcryptoWishList; - DHGexParameters nextKEXdhgexParameters; - - ServerHostKeyVerifier verifier; - final String hostname; - final int port; - final SecureRandom rnd; - - public KexManager(TransportManager tm, ClientServerHello csh, CryptoWishList initialCwl, String hostname, int port, - ServerHostKeyVerifier keyVerifier, SecureRandom rnd) - { - this.tm = tm; - this.csh = csh; - this.nextKEXcryptoWishList = initialCwl; - this.nextKEXdhgexParameters = new DHGexParameters(); - this.hostname = hostname; - this.port = port; - this.verifier = keyVerifier; - this.rnd = rnd; - } - - public ConnectionInfo getOrWaitForConnectionInfo(int minKexCount) throws IOException - { - synchronized (accessLock) - { - while (true) - { - if ((lastConnInfo != null) && (lastConnInfo.keyExchangeCounter >= minKexCount)) - return lastConnInfo; - - if (connectionClosed) - throw (IOException) new IOException("Key exchange was not finished, connection is closed.") - .initCause(tm.getReasonClosedCause()); - - try - { - accessLock.wait(); - } - catch (InterruptedException e) - { - } - } - } - } - - private String getFirstMatch(String[] client, String[] server) throws NegotiateException - { - if (client == null || server == null) - throw new IllegalArgumentException(); - - if (client.length == 0) - return null; - - for (int i = 0; i < client.length; i++) - { - for (int j = 0; j < server.length; j++) - { - if (client[i].equals(server[j])) - return client[i]; - } - } - throw new NegotiateException(); - } - - private boolean compareFirstOfNameList(String[] a, String[] b) - { - if (a == null || b == null) - throw new IllegalArgumentException(); - - if ((a.length == 0) && (b.length == 0)) - return true; - - if ((a.length == 0) || (b.length == 0)) - return false; - - return (a[0].equals(b[0])); - } - - private boolean isGuessOK(KexParameters cpar, KexParameters spar) - { - if (cpar == null || spar == null) - throw new IllegalArgumentException(); - - if (compareFirstOfNameList(cpar.kex_algorithms, spar.kex_algorithms) == false) - { - return false; - } - - if (compareFirstOfNameList(cpar.server_host_key_algorithms, spar.server_host_key_algorithms) == false) - { - return false; - } - - /* - * We do NOT check here if the other algorithms can be agreed on, this - * is just a check if kex_algorithms and server_host_key_algorithms were - * guessed right! - */ - - return true; - } - - private NegotiatedParameters mergeKexParameters(KexParameters client, KexParameters server) - { - NegotiatedParameters np = new NegotiatedParameters(); - - try - { - np.kex_algo = getFirstMatch(client.kex_algorithms, server.kex_algorithms); - - log.log(20, "kex_algo=" + np.kex_algo); - - np.server_host_key_algo = getFirstMatch(client.server_host_key_algorithms, - server.server_host_key_algorithms); - - log.log(20, "server_host_key_algo=" + np.server_host_key_algo); - - np.enc_algo_client_to_server = getFirstMatch(client.encryption_algorithms_client_to_server, - server.encryption_algorithms_client_to_server); - np.enc_algo_server_to_client = getFirstMatch(client.encryption_algorithms_server_to_client, - server.encryption_algorithms_server_to_client); - - log.log(20, "enc_algo_client_to_server=" + np.enc_algo_client_to_server); - log.log(20, "enc_algo_server_to_client=" + np.enc_algo_server_to_client); - - np.mac_algo_client_to_server = getFirstMatch(client.mac_algorithms_client_to_server, - server.mac_algorithms_client_to_server); - np.mac_algo_server_to_client = getFirstMatch(client.mac_algorithms_server_to_client, - server.mac_algorithms_server_to_client); - - log.log(20, "mac_algo_client_to_server=" + np.mac_algo_client_to_server); - log.log(20, "mac_algo_server_to_client=" + np.mac_algo_server_to_client); - - np.comp_algo_client_to_server = getFirstMatch(client.compression_algorithms_client_to_server, - server.compression_algorithms_client_to_server); - np.comp_algo_server_to_client = getFirstMatch(client.compression_algorithms_server_to_client, - server.compression_algorithms_server_to_client); - - log.log(20, "comp_algo_client_to_server=" + np.comp_algo_client_to_server); - log.log(20, "comp_algo_server_to_client=" + np.comp_algo_server_to_client); - - } - catch (NegotiateException e) - { - return null; - } - - try - { - np.lang_client_to_server = getFirstMatch(client.languages_client_to_server, - server.languages_client_to_server); - } - catch (NegotiateException e1) - { - np.lang_client_to_server = null; - } - - try - { - np.lang_server_to_client = getFirstMatch(client.languages_server_to_client, - server.languages_server_to_client); - } - catch (NegotiateException e2) - { - np.lang_server_to_client = null; - } - - if (isGuessOK(client, server)) - np.guessOK = true; - - return np; - } - - public synchronized void initiateKEX(CryptoWishList cwl, DHGexParameters dhgex) throws IOException - { - nextKEXcryptoWishList = cwl; - nextKEXdhgexParameters = dhgex; - - if (kxs == null) - { - kxs = new KexState(); - - kxs.dhgexParameters = nextKEXdhgexParameters; - PacketKexInit kp = new PacketKexInit(nextKEXcryptoWishList); - kxs.localKEX = kp; - tm.sendKexMessage(kp.getPayload()); - } - } - - private boolean establishKeyMaterial() - { - try - { - int mac_cs_key_len = MAC.getKeyLen(kxs.np.mac_algo_client_to_server); - int enc_cs_key_len = BlockCipherFactory.getKeySize(kxs.np.enc_algo_client_to_server); - int enc_cs_block_len = BlockCipherFactory.getBlockSize(kxs.np.enc_algo_client_to_server); - - int mac_sc_key_len = MAC.getKeyLen(kxs.np.mac_algo_server_to_client); - int enc_sc_key_len = BlockCipherFactory.getKeySize(kxs.np.enc_algo_server_to_client); - int enc_sc_block_len = BlockCipherFactory.getBlockSize(kxs.np.enc_algo_server_to_client); - - km = KeyMaterial.create(kxs.hashAlgo, kxs.H, kxs.K, sessionId, enc_cs_key_len, enc_cs_block_len, mac_cs_key_len, - enc_sc_key_len, enc_sc_block_len, mac_sc_key_len); - } - catch (IllegalArgumentException e) - { - return false; - } - return true; - } - - private void finishKex() throws IOException - { - if (sessionId == null) - sessionId = kxs.H; - - establishKeyMaterial(); - - /* Tell the other side that we start using the new material */ - - PacketNewKeys ign = new PacketNewKeys(); - tm.sendKexMessage(ign.getPayload()); - - BlockCipher cbc; - MAC mac; - ICompressor comp; - - try - { - cbc = BlockCipherFactory.createCipher(kxs.np.enc_algo_client_to_server, true, km.enc_key_client_to_server, - km.initial_iv_client_to_server); - - mac = new MAC(kxs.np.mac_algo_client_to_server, km.integrity_key_client_to_server); - - comp = CompressionFactory.createCompressor(kxs.np.comp_algo_client_to_server); - - } - catch (IllegalArgumentException e1) - { - throw new IOException("Fatal error during MAC startup!"); - } - - tm.changeSendCipher(cbc, mac); - tm.changeSendCompression(comp); - tm.kexFinished(); - } - - public static final String[] getDefaultServerHostkeyAlgorithmList() - { - return HOSTKEY_ALGS.toArray(new String[HOSTKEY_ALGS.size()]); - } - - public static final void checkServerHostkeyAlgorithmsList(String[] algos) - { - for (int i = 0; i < algos.length; i++) - { - if (!HOSTKEY_ALGS.contains(algos[i])) - throw new IllegalArgumentException("Unknown server host key algorithm '" + algos[i] + "'"); - } - } - - public static final String[] getDefaultKexAlgorithmList() - { - return KEX_ALGS.toArray(new String[KEX_ALGS.size()]); - } - - public static final void checkKexAlgorithmList(String[] algos) - { - for (int i = 0; i < algos.length; i++) - { - if (!KEX_ALGS.contains(algos[i])) - throw new IllegalArgumentException("Unknown kex algorithm '" + algos[i] + "'"); - } - } - - private boolean verifySignature(byte[] sig, byte[] hostkey) throws IOException - { - if (kxs.np.server_host_key_algo.startsWith("ecdsa-sha2-")) - { - byte[] rs = ECDSASHA2Verify.decodeSSHECDSASignature(sig); - ECPublicKey epk = ECDSASHA2Verify.decodeSSHECDSAPublicKey(hostkey); - - log.log(50, "Verifying ecdsa signature"); - - return ECDSASHA2Verify.verifySignature(kxs.H, rs, epk); - } - - if (kxs.np.server_host_key_algo.equals("ssh-rsa")) - { - byte[] rs = RSASHA1Verify.decodeSSHRSASignature(sig); - RSAPublicKey rpk = RSASHA1Verify.decodeSSHRSAPublicKey(hostkey); - - log.log(50, "Verifying ssh-rsa signature"); - - return RSASHA1Verify.verifySignature(kxs.H, rs, rpk); - } - - if (kxs.np.server_host_key_algo.equals("ssh-dss")) - { - byte[] ds = DSASHA1Verify.decodeSSHDSASignature(sig); - DSAPublicKey dpk = DSASHA1Verify.decodeSSHDSAPublicKey(hostkey); - - log.log(50, "Verifying ssh-dss signature"); - - return DSASHA1Verify.verifySignature(kxs.H, ds, dpk); - } - - throw new IOException("Unknown server host key algorithm '" + kxs.np.server_host_key_algo + "'"); - } - - public synchronized void handleMessage(byte[] msg, int msglen) throws IOException - { - PacketKexInit kip; - - if (msg == null) - { - synchronized (accessLock) - { - connectionClosed = true; - accessLock.notifyAll(); - return; - } - } - - if ((kxs == null) && (msg[0] != Packets.SSH_MSG_KEXINIT)) - throw new IOException("Unexpected KEX message (type " + msg[0] + ")"); - - if (ignore_next_kex_packet) - { - ignore_next_kex_packet = false; - return; - } - - if (msg[0] == Packets.SSH_MSG_KEXINIT) - { - if ((kxs != null) && (kxs.state != 0)) - throw new IOException("Unexpected SSH_MSG_KEXINIT message during on-going kex exchange!"); - - if (kxs == null) - { - /* - * Ah, OK, peer wants to do KEX. Let's be nice and play - * together. - */ - kxs = new KexState(); - kxs.dhgexParameters = nextKEXdhgexParameters; - kip = new PacketKexInit(nextKEXcryptoWishList); - kxs.localKEX = kip; - tm.sendKexMessage(kip.getPayload()); - } - - kip = new PacketKexInit(msg, 0, msglen); - kxs.remoteKEX = kip; - - kxs.np = mergeKexParameters(kxs.localKEX.getKexParameters(), kxs.remoteKEX.getKexParameters()); - - if (kxs.np == null) - throw new IOException("Cannot negotiate, proposals do not match."); - - if (kxs.remoteKEX.isFirst_kex_packet_follows() && (kxs.np.guessOK == false)) - { - /* - * Guess was wrong, we need to ignore the next kex packet. - */ - - ignore_next_kex_packet = true; - } - - if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1") - || kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha256")) - { - if (kxs.dhgexParameters.getMin_group_len() == 0 || csh.server_versioncomment.matches("OpenSSH_2\\.([0-4]\\.|5\\.[0-2]).*")) - { - PacketKexDhGexRequestOld dhgexreq = new PacketKexDhGexRequestOld(kxs.dhgexParameters); - tm.sendKexMessage(dhgexreq.getPayload()); - } - else - { - PacketKexDhGexRequest dhgexreq = new PacketKexDhGexRequest(kxs.dhgexParameters); - tm.sendKexMessage(dhgexreq.getPayload()); - } - if (kxs.np.kex_algo.endsWith("sha1")) { - kxs.hashAlgo = "SHA1"; - } else { - kxs.hashAlgo = "SHA-256"; - } - kxs.state = 1; - return; - } - - if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") - || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1") - || kxs.np.kex_algo.equals("ecdh-sha2-nistp256") - || kxs.np.kex_algo.equals("ecdh-sha2-nistp384") - || kxs.np.kex_algo.equals("ecdh-sha2-nistp521")) { - kxs.dhx = GenericDhExchange.getInstance(kxs.np.kex_algo); - - kxs.dhx.init(kxs.np.kex_algo); - kxs.hashAlgo = kxs.dhx.getHashAlgo(); - - PacketKexDHInit kp = new PacketKexDHInit(kxs.dhx.getE()); - tm.sendKexMessage(kp.getPayload()); - kxs.state = 1; - return; - } - - throw new IllegalStateException("Unknown KEX method!"); - } - - if (msg[0] == Packets.SSH_MSG_NEWKEYS) - { - if (km == null) - throw new IOException("Peer sent SSH_MSG_NEWKEYS, but I have no key material ready!"); - - BlockCipher cbc; - MAC mac; - ICompressor comp; - - try - { - cbc = BlockCipherFactory.createCipher(kxs.np.enc_algo_server_to_client, false, - km.enc_key_server_to_client, km.initial_iv_server_to_client); - - mac = new MAC(kxs.np.mac_algo_server_to_client, km.integrity_key_server_to_client); - - comp = CompressionFactory.createCompressor(kxs.np.comp_algo_server_to_client); - } - catch (IllegalArgumentException e1) - { - throw new IOException("Fatal error during MAC startup!"); - } - - tm.changeRecvCipher(cbc, mac); - tm.changeRecvCompression(comp); - - ConnectionInfo sci = new ConnectionInfo(); - - kexCount++; - - sci.keyExchangeAlgorithm = kxs.np.kex_algo; - sci.keyExchangeCounter = kexCount; - sci.clientToServerCryptoAlgorithm = kxs.np.enc_algo_client_to_server; - sci.serverToClientCryptoAlgorithm = kxs.np.enc_algo_server_to_client; - sci.clientToServerMACAlgorithm = kxs.np.mac_algo_client_to_server; - sci.serverToClientMACAlgorithm = kxs.np.mac_algo_server_to_client; - sci.serverHostKeyAlgorithm = kxs.np.server_host_key_algo; - sci.serverHostKey = kxs.hostkey; - - synchronized (accessLock) - { - lastConnInfo = sci; - accessLock.notifyAll(); - } - - kxs = null; - return; - } - - if ((kxs == null) || (kxs.state == 0)) - throw new IOException("Unexpected Kex submessage!"); - - if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1") - || kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha256")) - { - if (kxs.state == 1) - { - PacketKexDhGexGroup dhgexgrp = new PacketKexDhGexGroup(msg, 0, msglen); - kxs.dhgx = new DhGroupExchange(dhgexgrp.getP(), dhgexgrp.getG()); - kxs.dhgx.init(rnd); - PacketKexDhGexInit dhgexinit = new PacketKexDhGexInit(kxs.dhgx.getE()); - tm.sendKexMessage(dhgexinit.getPayload()); - kxs.state = 2; - return; - } - - if (kxs.state == 2) - { - PacketKexDhGexReply dhgexrpl = new PacketKexDhGexReply(msg, 0, msglen); - - kxs.hostkey = dhgexrpl.getHostKey(); - - if (verifier != null) - { - boolean vres = false; - - try - { - vres = verifier.verifyServerHostKey(hostname, port, kxs.np.server_host_key_algo, kxs.hostkey); - } - catch (Exception e) - { - throw (IOException) new IOException( - "The server hostkey was not accepted by the verifier callback.").initCause(e); - } - - if (vres == false) - throw new IOException("The server hostkey was not accepted by the verifier callback"); - } - - kxs.dhgx.setF(dhgexrpl.getF()); - - try - { - kxs.H = kxs.dhgx.calculateH(kxs.hashAlgo, - csh.getClientString(), csh.getServerString(), - kxs.localKEX.getPayload(), kxs.remoteKEX.getPayload(), - dhgexrpl.getHostKey(), kxs.dhgexParameters); - } - catch (IllegalArgumentException e) - { - throw (IOException) new IOException("KEX error.").initCause(e); - } - - boolean res = verifySignature(dhgexrpl.getSignature(), kxs.hostkey); - - if (res == false) - throw new IOException("Hostkey signature sent by remote is wrong!"); - - kxs.K = kxs.dhgx.getK(); - - finishKex(); - kxs.state = -1; - return; - } - - throw new IllegalStateException("Illegal State in KEX Exchange!"); - } - - if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") - || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1") - || kxs.np.kex_algo.equals("ecdh-sha2-nistp256") - || kxs.np.kex_algo.equals("ecdh-sha2-nistp384") - || kxs.np.kex_algo.equals("ecdh-sha2-nistp521")) - { - if (kxs.state == 1) - { - - PacketKexDHReply dhr = new PacketKexDHReply(msg, 0, msglen); - - kxs.hostkey = dhr.getHostKey(); - - if (verifier != null) - { - boolean vres = false; - - try - { - vres = verifier.verifyServerHostKey(hostname, port, kxs.np.server_host_key_algo, kxs.hostkey); - } - catch (Exception e) - { - throw (IOException) new IOException( - "The server hostkey was not accepted by the verifier callback.").initCause(e); - } - - if (vres == false) - throw new IOException("The server hostkey was not accepted by the verifier callback"); - } - - kxs.dhx.setF(dhr.getF()); - - try - { - kxs.H = kxs.dhx.calculateH(csh.getClientString(), csh.getServerString(), kxs.localKEX.getPayload(), - kxs.remoteKEX.getPayload(), dhr.getHostKey()); - } - catch (IllegalArgumentException e) - { - throw (IOException) new IOException("KEX error.").initCause(e); - } - - boolean res = verifySignature(dhr.getSignature(), kxs.hostkey); - - if (res == false) - throw new IOException("Hostkey signature sent by remote is wrong!"); - - kxs.K = kxs.dhx.getK(); - - finishKex(); - kxs.state = -1; - return; - } - } - - throw new IllegalStateException("Unkown KEX method! (" + kxs.np.kex_algo + ")"); - } -} diff --git a/src/com/trilead/ssh2/transport/KexParameters.java b/src/com/trilead/ssh2/transport/KexParameters.java deleted file mode 100644 index 70bcf3e..0000000 --- a/src/com/trilead/ssh2/transport/KexParameters.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.trilead.ssh2.transport; - -/** - * KexParameters. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: KexParameters.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class KexParameters -{ - public byte[] cookie; - public String[] kex_algorithms; - public String[] server_host_key_algorithms; - public String[] encryption_algorithms_client_to_server; - public String[] encryption_algorithms_server_to_client; - public String[] mac_algorithms_client_to_server; - public String[] mac_algorithms_server_to_client; - public String[] compression_algorithms_client_to_server; - public String[] compression_algorithms_server_to_client; - public String[] languages_client_to_server; - public String[] languages_server_to_client; - public boolean first_kex_packet_follows; - public int reserved_field1; -} diff --git a/src/com/trilead/ssh2/transport/KexState.java b/src/com/trilead/ssh2/transport/KexState.java deleted file mode 100644 index 8611f3f..0000000 --- a/src/com/trilead/ssh2/transport/KexState.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.trilead.ssh2.transport; - - -import java.math.BigInteger; - -import com.trilead.ssh2.DHGexParameters; -import com.trilead.ssh2.crypto.dh.DhGroupExchange; -import com.trilead.ssh2.crypto.dh.GenericDhExchange; -import com.trilead.ssh2.packets.PacketKexInit; - -/** - * KexState. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: KexState.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public class KexState -{ - public PacketKexInit localKEX; - public PacketKexInit remoteKEX; - public NegotiatedParameters np; - public int state = 0; - - public BigInteger K; - public byte[] H; - - public byte[] hostkey; - - public String hashAlgo; - public GenericDhExchange dhx; - public DhGroupExchange dhgx; - public DHGexParameters dhgexParameters; -} diff --git a/src/com/trilead/ssh2/transport/MessageHandler.java b/src/com/trilead/ssh2/transport/MessageHandler.java deleted file mode 100644 index 039d473..0000000 --- a/src/com/trilead/ssh2/transport/MessageHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.trilead.ssh2.transport; - -import java.io.IOException; - -/** - * MessageHandler. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: MessageHandler.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public interface MessageHandler -{ - public void handleMessage(byte[] msg, int msglen) throws IOException; -} diff --git a/src/com/trilead/ssh2/transport/NegotiateException.java b/src/com/trilead/ssh2/transport/NegotiateException.java deleted file mode 100644 index ff53097..0000000 --- a/src/com/trilead/ssh2/transport/NegotiateException.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.trilead.ssh2.transport; - -/** - * NegotiateException. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: NegotiateException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class NegotiateException extends Exception -{ - private static final long serialVersionUID = 3689910669428143157L; -} diff --git a/src/com/trilead/ssh2/transport/NegotiatedParameters.java b/src/com/trilead/ssh2/transport/NegotiatedParameters.java deleted file mode 100644 index e9f3a0a..0000000 --- a/src/com/trilead/ssh2/transport/NegotiatedParameters.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.trilead.ssh2.transport; - -/** - * NegotiatedParameters. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: NegotiatedParameters.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public class NegotiatedParameters -{ - public boolean guessOK; - public String kex_algo; - public String server_host_key_algo; - public String enc_algo_client_to_server; - public String enc_algo_server_to_client; - public String mac_algo_client_to_server; - public String mac_algo_server_to_client; - public String comp_algo_client_to_server; - public String comp_algo_server_to_client; - public String lang_client_to_server; - public String lang_server_to_client; -} diff --git a/src/com/trilead/ssh2/transport/TransportConnection.java b/src/com/trilead/ssh2/transport/TransportConnection.java deleted file mode 100644 index 906c3c9..0000000 --- a/src/com/trilead/ssh2/transport/TransportConnection.java +++ /dev/null @@ -1,343 +0,0 @@ - -package com.trilead.ssh2.transport; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SecureRandom; - -import com.trilead.ssh2.compression.ICompressor; -import com.trilead.ssh2.crypto.cipher.BlockCipher; -import com.trilead.ssh2.crypto.cipher.CipherInputStream; -import com.trilead.ssh2.crypto.cipher.CipherOutputStream; -import com.trilead.ssh2.crypto.cipher.NullCipher; -import com.trilead.ssh2.crypto.digest.MAC; -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.Packets; - - -/** - * TransportConnection. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: TransportConnection.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ - */ -public class TransportConnection -{ - private static final Logger log = Logger.getLogger(TransportConnection.class); - - int send_seq_number = 0; - - int recv_seq_number = 0; - - CipherInputStream cis; - - CipherOutputStream cos; - - boolean useRandomPadding = false; - - /* Depends on current MAC and CIPHER */ - - MAC send_mac; - - byte[] send_mac_buffer; - - int send_padd_blocksize = 8; - - MAC recv_mac; - - byte[] recv_mac_buffer; - - byte[] recv_mac_buffer_cmp; - - int recv_padd_blocksize = 8; - - ICompressor recv_comp = null; - - ICompressor send_comp = null; - - boolean can_recv_compress = false; - - boolean can_send_compress = false; - - byte[] recv_comp_buffer; - - byte[] send_comp_buffer; - - /* won't change */ - - final byte[] send_padding_buffer = new byte[256]; - - final byte[] send_packet_header_buffer = new byte[5]; - - final byte[] recv_padding_buffer = new byte[256]; - - final byte[] recv_packet_header_buffer = new byte[5]; - - boolean recv_packet_header_present = false; - - ClientServerHello csh; - - final SecureRandom rnd; - - public TransportConnection(InputStream is, OutputStream os, SecureRandom rnd) - { - this.cis = new CipherInputStream(new NullCipher(), is); - this.cos = new CipherOutputStream(new NullCipher(), os); - this.rnd = rnd; - } - - public void changeRecvCipher(BlockCipher bc, MAC mac) - { - cis.changeCipher(bc); - recv_mac = mac; - recv_mac_buffer = (mac != null) ? new byte[mac.size()] : null; - recv_mac_buffer_cmp = (mac != null) ? new byte[mac.size()] : null; - recv_padd_blocksize = bc.getBlockSize(); - if (recv_padd_blocksize < 8) - recv_padd_blocksize = 8; - } - - public void changeSendCipher(BlockCipher bc, MAC mac) - { - if ((bc instanceof NullCipher) == false) - { - /* Only use zero byte padding for the first few packets */ - useRandomPadding = true; - /* Once we start encrypting, there is no way back */ - } - - cos.changeCipher(bc); - send_mac = mac; - send_mac_buffer = (mac != null) ? new byte[mac.size()] : null; - send_padd_blocksize = bc.getBlockSize(); - if (send_padd_blocksize < 8) - send_padd_blocksize = 8; - } - - public void changeRecvCompression(ICompressor comp) - { - recv_comp = comp; - - if (comp != null) { - recv_comp_buffer = new byte[comp.getBufferSize()]; - can_recv_compress |= recv_comp.canCompressPreauth(); - } - } - - public void changeSendCompression(ICompressor comp) - { - send_comp = comp; - - if (comp != null) { - send_comp_buffer = new byte[comp.getBufferSize()]; - can_send_compress |= send_comp.canCompressPreauth(); - } - } - - public void sendMessage(byte[] message) throws IOException - { - sendMessage(message, 0, message.length, 0); - } - - public void sendMessage(byte[] message, int off, int len) throws IOException - { - sendMessage(message, off, len, 0); - } - - public int getPacketOverheadEstimate() - { - // return an estimate for the paket overhead (for send operations) - return 5 + 4 + (send_padd_blocksize - 1) + send_mac_buffer.length; - } - - public void sendMessage(byte[] message, int off, int len, int padd) throws IOException - { - if (padd < 4) - padd = 4; - else if (padd > 64) - padd = 64; - - if (send_comp != null && can_send_compress) { - if (send_comp_buffer.length < message.length + 1024) - send_comp_buffer = new byte[message.length + 1024]; - len = send_comp.compress(message, off, len, send_comp_buffer); - message = send_comp_buffer; - } - - int packet_len = 5 + len + padd; /* Minimum allowed padding is 4 */ - - int slack = packet_len % send_padd_blocksize; - - if (slack != 0) - { - packet_len += (send_padd_blocksize - slack); - } - - if (packet_len < 16) - packet_len = 16; - - int padd_len = packet_len - (5 + len); - - if (useRandomPadding) - { - for (int i = 0; i < padd_len; i = i + 4) - { - /* - * don't waste calls to rnd.nextInt() (by using only 8bit of the - * output). just believe me: even though we may write here up to 3 - * bytes which won't be used, there is no "buffer overflow" (i.e., - * arrayindexoutofbounds). the padding buffer is big enough =) (256 - * bytes, and that is bigger than any current cipher block size + 64). - */ - - int r = rnd.nextInt(); - send_padding_buffer[i] = (byte) r; - send_padding_buffer[i + 1] = (byte) (r >> 8); - send_padding_buffer[i + 2] = (byte) (r >> 16); - send_padding_buffer[i + 3] = (byte) (r >> 24); - } - } - else - { - /* use zero padding for unencrypted traffic */ - for (int i = 0; i < padd_len; i++) - send_padding_buffer[i] = 0; - /* Actually this code is paranoid: we never filled any - * bytes into the padding buffer so far, therefore it should - * consist of zeros only. - */ - } - - send_packet_header_buffer[0] = (byte) ((packet_len - 4) >> 24); - send_packet_header_buffer[1] = (byte) ((packet_len - 4) >> 16); - send_packet_header_buffer[2] = (byte) ((packet_len - 4) >> 8); - send_packet_header_buffer[3] = (byte) ((packet_len - 4)); - send_packet_header_buffer[4] = (byte) padd_len; - - cos.write(send_packet_header_buffer, 0, 5); - cos.write(message, off, len); - cos.write(send_padding_buffer, 0, padd_len); - - if (send_mac != null) - { - send_mac.initMac(send_seq_number); - send_mac.update(send_packet_header_buffer, 0, 5); - send_mac.update(message, off, len); - send_mac.update(send_padding_buffer, 0, padd_len); - - send_mac.getMac(send_mac_buffer, 0); - cos.writePlain(send_mac_buffer, 0, send_mac_buffer.length); - } - - cos.flush(); - - if (log.isEnabled()) - { - log.log(90, "Sent " + Packets.getMessageName(message[off] & 0xff) + " " + len + " bytes payload"); - } - - send_seq_number++; - } - - public int peekNextMessageLength() throws IOException - { - if (recv_packet_header_present == false) - { - cis.read(recv_packet_header_buffer, 0, 5); - recv_packet_header_present = true; - } - - int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24) - | ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8) - | ((recv_packet_header_buffer[3] & 0xff)); - - int padding_length = recv_packet_header_buffer[4] & 0xff; - - if (packet_length > 35000 || packet_length < 12) - throw new IOException("Illegal packet size! (" + packet_length + ")"); - - int payload_length = packet_length - padding_length - 1; - - if (payload_length < 0) - throw new IOException("Illegal padding_length in packet from remote (" + padding_length + ")"); - - return payload_length; - } - - public int receiveMessage(byte buffer[], int off, int len) throws IOException - { - if (recv_packet_header_present == false) - { - cis.read(recv_packet_header_buffer, 0, 5); - } - else - recv_packet_header_present = false; - - int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24) - | ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8) - | ((recv_packet_header_buffer[3] & 0xff)); - - int padding_length = recv_packet_header_buffer[4] & 0xff; - - if (packet_length > 35000 || packet_length < 12) - throw new IOException("Illegal packet size! (" + packet_length + ")"); - - int payload_length = packet_length - padding_length - 1; - - if (payload_length < 0) - throw new IOException("Illegal padding_length in packet from remote (" + padding_length + ")"); - - if (payload_length >= len) - throw new IOException("Receive buffer too small (" + len + ", need " + payload_length + ")"); - - cis.read(buffer, off, payload_length); - cis.read(recv_padding_buffer, 0, padding_length); - - if (recv_mac != null) - { - cis.readPlain(recv_mac_buffer, 0, recv_mac_buffer.length); - - recv_mac.initMac(recv_seq_number); - recv_mac.update(recv_packet_header_buffer, 0, 5); - recv_mac.update(buffer, off, payload_length); - recv_mac.update(recv_padding_buffer, 0, padding_length); - recv_mac.getMac(recv_mac_buffer_cmp, 0); - - for (int i = 0; i < recv_mac_buffer.length; i++) - { - if (recv_mac_buffer[i] != recv_mac_buffer_cmp[i]) - throw new IOException("Remote sent corrupt MAC."); - } - } - - recv_seq_number++; - - if (log.isEnabled()) - { - log.log(90, "Received " + Packets.getMessageName(buffer[off] & 0xff) + " " + payload_length - + " bytes payload"); - } - - if (recv_comp != null && can_recv_compress) { - int[] uncomp_len = new int[] { payload_length }; - buffer = recv_comp.uncompress(buffer, off, uncomp_len); - - if (buffer == null) { - throw new IOException("Error while inflating remote data"); - } else { - return uncomp_len[0]; - } - } else { - return payload_length; - } - } - - /** - * - */ - public void startCompression() { - can_recv_compress = true; - can_send_compress = true; - } -} diff --git a/src/com/trilead/ssh2/transport/TransportManager.java b/src/com/trilead/ssh2/transport/TransportManager.java deleted file mode 100644 index 2e88126..0000000 --- a/src/com/trilead/ssh2/transport/TransportManager.java +++ /dev/null @@ -1,802 +0,0 @@ - -package com.trilead.ssh2.transport; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.security.SecureRandom; -import java.util.Vector; - -import com.trilead.ssh2.ConnectionInfo; -import com.trilead.ssh2.ConnectionMonitor; -import com.trilead.ssh2.DHGexParameters; -import com.trilead.ssh2.HTTPProxyData; -import com.trilead.ssh2.HTTPProxyException; -import com.trilead.ssh2.ProxyData; -import com.trilead.ssh2.ServerHostKeyVerifier; -import com.trilead.ssh2.compression.ICompressor; -import com.trilead.ssh2.crypto.Base64; -import com.trilead.ssh2.crypto.CryptoWishList; -import com.trilead.ssh2.crypto.cipher.BlockCipher; -import com.trilead.ssh2.crypto.digest.MAC; -import com.trilead.ssh2.log.Logger; -import com.trilead.ssh2.packets.PacketDisconnect; -import com.trilead.ssh2.packets.Packets; -import com.trilead.ssh2.packets.TypesReader; -import com.trilead.ssh2.util.Tokenizer; - - -/* - * Yes, the "standard" is a big mess. On one side, the say that arbitary channel - * packets are allowed during kex exchange, on the other side we need to blindly - * ignore the next _packet_ if the KEX guess was wrong. Where do we know from that - * the next packet is not a channel data packet? Yes, we could check if it is in - * the KEX range. But the standard says nothing about this. The OpenSSH guys - * block local "normal" traffic during KEX. That's fine - however, they assume - * that the other side is doing the same. During re-key, if they receive traffic - * other than KEX, they become horribly irritated and kill the connection. Since - * we are very likely going to communicate with OpenSSH servers, we have to play - * the same game - even though we could do better. - * - * btw: having stdout and stderr on the same channel, with a shared window, is - * also a VERY good idea... =( - */ - -/** - * TransportManager. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: TransportManager.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ - */ -public class TransportManager -{ - private static final Logger log = Logger.getLogger(TransportManager.class); - - class HandlerEntry - { - MessageHandler mh; - int low; - int high; - } - - private final Vector<byte[]> asynchronousQueue = new Vector<byte[]>(); - private Thread asynchronousThread = null; - - class AsynchronousWorker extends Thread - { - public void run() - { - while (true) - { - byte[] msg = null; - - synchronized (asynchronousQueue) - { - if (asynchronousQueue.size() == 0) - { - /* After the queue is empty for about 2 seconds, stop this thread */ - - try - { - asynchronousQueue.wait(2000); - } - catch (InterruptedException e) - { - /* OKOK, if somebody interrupts us, then we may die earlier. */ - } - - if (asynchronousQueue.size() == 0) - { - asynchronousThread = null; - return; - } - } - - msg = asynchronousQueue.remove(0); - } - - /* The following invocation may throw an IOException. - * There is no point in handling it - it simply means - * that the connection has a problem and we should stop - * sending asynchronously messages. We do not need to signal that - * we have exited (asynchronousThread = null): further - * messages in the queue cannot be sent by this or any - * other thread. - * Other threads will sooner or later (when receiving or - * sending the next message) get the same IOException and - * get to the same conclusion. - */ - - try - { - sendMessage(msg); - } - catch (IOException e) - { - return; - } - } - } - } - - String hostname; - int port; - final Socket sock = new Socket(); - - Object connectionSemaphore = new Object(); - - boolean flagKexOngoing = false; - boolean connectionClosed = false; - - Throwable reasonClosedCause = null; - - TransportConnection tc; - KexManager km; - - Vector<HandlerEntry> messageHandlers = new Vector<HandlerEntry>(); - - Thread receiveThread; - - Vector connectionMonitors = new Vector(); - boolean monitorsWereInformed = false; - - /** - * There were reports that there are JDKs which use - * the resolver even though one supplies a dotted IP - * address in the Socket constructor. That is why we - * try to generate the InetAdress "by hand". - * - * @param host - * @return the InetAddress - * @throws UnknownHostException - */ - private InetAddress createInetAddress(String host) throws UnknownHostException - { - /* Check if it is a dotted IP4 address */ - - InetAddress addr = parseIPv4Address(host); - - if (addr != null) - return addr; - - return InetAddress.getByName(host); - } - - private InetAddress parseIPv4Address(String host) throws UnknownHostException - { - if (host == null) - return null; - - String[] quad = Tokenizer.parseTokens(host, '.'); - - if ((quad == null) || (quad.length != 4)) - return null; - - byte[] addr = new byte[4]; - - for (int i = 0; i < 4; i++) - { - int part = 0; - - if ((quad[i].length() == 0) || (quad[i].length() > 3)) - return null; - - for (int k = 0; k < quad[i].length(); k++) - { - char c = quad[i].charAt(k); - - /* No, Character.isDigit is not the same */ - if ((c < '0') || (c > '9')) - return null; - - part = part * 10 + (c - '0'); - } - - if (part > 255) /* 300.1.2.3 is invalid =) */ - return null; - - addr[i] = (byte) part; - } - - return InetAddress.getByAddress(host, addr); - } - - public TransportManager(String host, int port) throws IOException - { - this.hostname = host; - this.port = port; - } - - public int getPacketOverheadEstimate() - { - return tc.getPacketOverheadEstimate(); - } - - public void setTcpNoDelay(boolean state) throws IOException - { - sock.setTcpNoDelay(state); - } - - public void setSoTimeout(int timeout) throws IOException - { - sock.setSoTimeout(timeout); - } - - public ConnectionInfo getConnectionInfo(int kexNumber) throws IOException - { - return km.getOrWaitForConnectionInfo(kexNumber); - } - - public Throwable getReasonClosedCause() - { - synchronized (connectionSemaphore) - { - return reasonClosedCause; - } - } - - public byte[] getSessionIdentifier() - { - return km.sessionId; - } - - public void close(Throwable cause, boolean useDisconnectPacket) - { - if (useDisconnectPacket == false) - { - /* OK, hard shutdown - do not aquire the semaphore, - * perhaps somebody is inside (and waits until the remote - * side is ready to accept new data). */ - - try - { - sock.close(); - } - catch (IOException ignore) - { - } - - /* OK, whoever tried to send data, should now agree that - * there is no point in further waiting =) - * It is safe now to aquire the semaphore. - */ - } - - synchronized (connectionSemaphore) - { - if (connectionClosed == false) - { - if (useDisconnectPacket == true) - { - try - { - byte[] msg = new PacketDisconnect(Packets.SSH_DISCONNECT_BY_APPLICATION, cause.getMessage(), "") - .getPayload(); - if (tc != null) - tc.sendMessage(msg); - } - catch (IOException ignore) - { - } - - try - { - sock.close(); - } - catch (IOException ignore) - { - } - } - - connectionClosed = true; - reasonClosedCause = cause; /* may be null */ - } - connectionSemaphore.notifyAll(); - } - - /* No check if we need to inform the monitors */ - - Vector monitors = null; - - synchronized (this) - { - /* Short term lock to protect "connectionMonitors" - * and "monitorsWereInformed" - * (they may be modified concurrently) - */ - - if (monitorsWereInformed == false) - { - monitorsWereInformed = true; - monitors = (Vector) connectionMonitors.clone(); - } - } - - if (monitors != null) - { - for (int i = 0; i < monitors.size(); i++) - { - try - { - ConnectionMonitor cmon = (ConnectionMonitor) monitors.elementAt(i); - cmon.connectionLost(reasonClosedCause); - } - catch (Exception ignore) - { - } - } - } - } - - private void establishConnection(ProxyData proxyData, int connectTimeout) throws IOException - { - /* See the comment for createInetAddress() */ - - if (proxyData == null) - { - InetAddress addr = createInetAddress(hostname); - sock.connect(new InetSocketAddress(addr, port), connectTimeout); - sock.setSoTimeout(0); - return; - } - - if (proxyData instanceof HTTPProxyData) - { - HTTPProxyData pd = (HTTPProxyData) proxyData; - - /* At the moment, we only support HTTP proxies */ - - InetAddress addr = createInetAddress(pd.proxyHost); - sock.connect(new InetSocketAddress(addr, pd.proxyPort), connectTimeout); - sock.setSoTimeout(0); - - /* OK, now tell the proxy where we actually want to connect to */ - - StringBuffer sb = new StringBuffer(); - - sb.append("CONNECT "); - sb.append(hostname); - sb.append(':'); - sb.append(port); - sb.append(" HTTP/1.0\r\n"); - - if ((pd.proxyUser != null) && (pd.proxyPass != null)) - { - String credentials = pd.proxyUser + ":" + pd.proxyPass; - char[] encoded = Base64.encode(credentials.getBytes("ISO-8859-1")); - sb.append("Proxy-Authorization: Basic "); - sb.append(encoded); - sb.append("\r\n"); - } - - if (pd.requestHeaderLines != null) - { - for (int i = 0; i < pd.requestHeaderLines.length; i++) - { - if (pd.requestHeaderLines[i] != null) - { - sb.append(pd.requestHeaderLines[i]); - sb.append("\r\n"); - } - } - } - - sb.append("\r\n"); - - OutputStream out = sock.getOutputStream(); - - out.write(sb.toString().getBytes("ISO-8859-1")); - out.flush(); - - /* Now parse the HTTP response */ - - byte[] buffer = new byte[1024]; - InputStream in = sock.getInputStream(); - - int len = ClientServerHello.readLineRN(in, buffer); - - String httpReponse = new String(buffer, 0, len, "ISO-8859-1"); - - if (httpReponse.startsWith("HTTP/") == false) - throw new IOException("The proxy did not send back a valid HTTP response."); - - /* "HTTP/1.X XYZ X" => 14 characters minimum */ - - if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' ')) - throw new IOException("The proxy did not send back a valid HTTP response."); - - int errorCode = 0; - - try - { - errorCode = Integer.parseInt(httpReponse.substring(9, 12)); - } - catch (NumberFormatException ignore) - { - throw new IOException("The proxy did not send back a valid HTTP response."); - } - - if ((errorCode < 0) || (errorCode > 999)) - throw new IOException("The proxy did not send back a valid HTTP response."); - - if (errorCode != 200) - { - throw new HTTPProxyException(httpReponse.substring(13), errorCode); - } - - /* OK, read until empty line */ - - while (true) - { - len = ClientServerHello.readLineRN(in, buffer); - if (len == 0) - break; - } - return; - } - - throw new IOException("Unsupported ProxyData"); - } - - public void initialize(CryptoWishList cwl, ServerHostKeyVerifier verifier, DHGexParameters dhgex, - int connectTimeout, SecureRandom rnd, ProxyData proxyData) throws IOException - { - /* First, establish the TCP connection to the SSH-2 server */ - - establishConnection(proxyData, connectTimeout); - - /* Parse the server line and say hello - important: this information is later needed for the - * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object - * for later use. - */ - - ClientServerHello csh = new ClientServerHello(sock.getInputStream(), sock.getOutputStream()); - - tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), rnd); - - km = new KexManager(this, csh, cwl, hostname, port, verifier, rnd); - km.initiateKEX(cwl, dhgex); - - receiveThread = new Thread(new Runnable() - { - public void run() - { - try - { - receiveLoop(); - } - catch (IOException e) - { - close(e, false); - - if (log.isEnabled()) - log.log(10, "Receive thread: error in receiveLoop: " + e.getMessage()); - } - - if (log.isEnabled()) - log.log(50, "Receive thread: back from receiveLoop"); - - /* Tell all handlers that it is time to say goodbye */ - - if (km != null) - { - try - { - km.handleMessage(null, 0); - } - catch (IOException e) - { - } - } - - for (int i = 0; i < messageHandlers.size(); i++) - { - HandlerEntry he = messageHandlers.elementAt(i); - try - { - he.mh.handleMessage(null, 0); - } - catch (Exception ignore) - { - } - } - } - }); - - receiveThread.setDaemon(true); - receiveThread.start(); - } - - public void registerMessageHandler(MessageHandler mh, int low, int high) - { - HandlerEntry he = new HandlerEntry(); - he.mh = mh; - he.low = low; - he.high = high; - - synchronized (messageHandlers) - { - messageHandlers.addElement(he); - } - } - - public void removeMessageHandler(MessageHandler mh, int low, int high) - { - synchronized (messageHandlers) - { - for (int i = 0; i < messageHandlers.size(); i++) - { - HandlerEntry he = messageHandlers.elementAt(i); - if ((he.mh == mh) && (he.low == low) && (he.high == high)) - { - messageHandlers.removeElementAt(i); - break; - } - } - } - } - - public void sendKexMessage(byte[] msg) throws IOException - { - synchronized (connectionSemaphore) - { - if (connectionClosed) - { - throw (IOException) new IOException("Sorry, this connection is closed.").initCause(reasonClosedCause); - } - - flagKexOngoing = true; - - try - { - tc.sendMessage(msg); - } - catch (IOException e) - { - close(e, false); - throw e; - } - } - } - - public void kexFinished() throws IOException - { - synchronized (connectionSemaphore) - { - flagKexOngoing = false; - connectionSemaphore.notifyAll(); - } - } - - public void forceKeyExchange(CryptoWishList cwl, DHGexParameters dhgex) throws IOException - { - km.initiateKEX(cwl, dhgex); - } - - public void changeRecvCipher(BlockCipher bc, MAC mac) - { - tc.changeRecvCipher(bc, mac); - } - - public void changeSendCipher(BlockCipher bc, MAC mac) - { - tc.changeSendCipher(bc, mac); - } - - /** - * @param comp - */ - public void changeRecvCompression(ICompressor comp) { - tc.changeRecvCompression(comp); - } - - /** - * @param comp - */ - public void changeSendCompression(ICompressor comp) { - tc.changeSendCompression(comp); - } - - /** - * - */ - public void startCompression() { - tc.startCompression(); - } - - public void sendAsynchronousMessage(byte[] msg) throws IOException - { - synchronized (asynchronousQueue) - { - asynchronousQueue.addElement(msg); - - /* This limit should be flexible enough. We need this, otherwise the peer - * can flood us with global requests (and other stuff where we have to reply - * with an asynchronous message) and (if the server just sends data and does not - * read what we send) this will probably put us in a low memory situation - * (our send queue would grow and grow and...) */ - - if (asynchronousQueue.size() > 100) - throw new IOException("Error: the peer is not consuming our asynchronous replies."); - - /* Check if we have an asynchronous sending thread */ - - if (asynchronousThread == null) - { - asynchronousThread = new AsynchronousWorker(); - asynchronousThread.setDaemon(true); - asynchronousThread.start(); - - /* The thread will stop after 2 seconds of inactivity (i.e., empty queue) */ - } - } - } - - public void setConnectionMonitors(Vector monitors) - { - synchronized (this) - { - connectionMonitors = (Vector) monitors.clone(); - } - } - - public void sendMessage(byte[] msg) throws IOException - { - if (Thread.currentThread() == receiveThread) - throw new IOException("Assertion error: sendMessage may never be invoked by the receiver thread!"); - - synchronized (connectionSemaphore) - { - while (true) - { - if (connectionClosed) - { - throw (IOException) new IOException("Sorry, this connection is closed.") - .initCause(reasonClosedCause); - } - - if (flagKexOngoing == false) - break; - - try - { - connectionSemaphore.wait(); - } - catch (InterruptedException e) - { - } - } - - try - { - tc.sendMessage(msg); - } - catch (IOException e) - { - close(e, false); - throw e; - } - } - } - - public void receiveLoop() throws IOException - { - byte[] msg = new byte[35000]; - - while (true) - { - int msglen = tc.receiveMessage(msg, 0, msg.length); - - int type = msg[0] & 0xff; - - if (type == Packets.SSH_MSG_IGNORE) - continue; - - if (type == Packets.SSH_MSG_DEBUG) - { - if (log.isEnabled()) - { - TypesReader tr = new TypesReader(msg, 0, msglen); - tr.readByte(); - tr.readBoolean(); - StringBuffer debugMessageBuffer = new StringBuffer(); - debugMessageBuffer.append(tr.readString("UTF-8")); - - for (int i = 0; i < debugMessageBuffer.length(); i++) - { - char c = debugMessageBuffer.charAt(i); - - if ((c >= 32) && (c <= 126)) - continue; - debugMessageBuffer.setCharAt(i, '\uFFFD'); - } - - log.log(50, "DEBUG Message from remote: '" + debugMessageBuffer.toString() + "'"); - } - continue; - } - - if (type == Packets.SSH_MSG_UNIMPLEMENTED) - { - throw new IOException("Peer sent UNIMPLEMENTED message, that should not happen."); - } - - if (type == Packets.SSH_MSG_DISCONNECT) - { - TypesReader tr = new TypesReader(msg, 0, msglen); - tr.readByte(); - int reason_code = tr.readUINT32(); - StringBuffer reasonBuffer = new StringBuffer(); - reasonBuffer.append(tr.readString("UTF-8")); - - /* - * Do not get fooled by servers that send abnormal long error - * messages - */ - - if (reasonBuffer.length() > 255) - { - reasonBuffer.setLength(255); - reasonBuffer.setCharAt(254, '.'); - reasonBuffer.setCharAt(253, '.'); - reasonBuffer.setCharAt(252, '.'); - } - - /* - * Also, check that the server did not send charcaters that may - * screw up the receiver -> restrict to reasonable US-ASCII - * subset -> "printable characters" (ASCII 32 - 126). Replace - * all others with 0xFFFD (UNICODE replacement character). - */ - - for (int i = 0; i < reasonBuffer.length(); i++) - { - char c = reasonBuffer.charAt(i); - - if ((c >= 32) && (c <= 126)) - continue; - reasonBuffer.setCharAt(i, '\uFFFD'); - } - - throw new IOException("Peer sent DISCONNECT message (reason code " + reason_code + "): " - + reasonBuffer.toString()); - } - - /* - * Is it a KEX Packet? - */ - - if ((type == Packets.SSH_MSG_KEXINIT) || (type == Packets.SSH_MSG_NEWKEYS) - || ((type >= 30) && (type <= 49))) - { - km.handleMessage(msg, msglen); - continue; - } - - if (type == Packets.SSH_MSG_USERAUTH_SUCCESS) { - tc.startCompression(); - } - - MessageHandler mh = null; - - for (int i = 0; i < messageHandlers.size(); i++) - { - HandlerEntry he = messageHandlers.elementAt(i); - if ((he.low <= type) && (type <= he.high)) - { - mh = he.mh; - break; - } - } - - if (mh == null) - throw new IOException("Unexpected SSH message (type " + type + ")"); - - mh.handleMessage(msg, msglen); - } - } -} diff --git a/src/com/trilead/ssh2/util/TimeoutService.java b/src/com/trilead/ssh2/util/TimeoutService.java deleted file mode 100644 index 3d52161..0000000 --- a/src/com/trilead/ssh2/util/TimeoutService.java +++ /dev/null @@ -1,149 +0,0 @@ - -package com.trilead.ssh2.util; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Collections; -import java.util.LinkedList; - -import com.trilead.ssh2.log.Logger; - - -/** - * TimeoutService (beta). Here you can register a timeout. - * <p> - * Implemented having large scale programs in mind: if you open many concurrent SSH connections - * that rely on timeouts, then there will be only one timeout thread. Once all timeouts - * have expired/are cancelled, the thread will (sooner or later) exit. - * Only after new timeouts arrive a new thread (singleton) will be instantiated. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: TimeoutService.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public class TimeoutService -{ - private static final Logger log = Logger.getLogger(TimeoutService.class); - - public static class TimeoutToken implements Comparable - { - private long runTime; - private Runnable handler; - - private TimeoutToken(long runTime, Runnable handler) - { - this.runTime = runTime; - this.handler = handler; - } - - public int compareTo(Object o) - { - TimeoutToken t = (TimeoutToken) o; - if (runTime > t.runTime) - return 1; - if (runTime == t.runTime) - return 0; - return -1; - } - } - - private static class TimeoutThread extends Thread - { - public void run() - { - synchronized (todolist) - { - while (true) - { - if (todolist.size() == 0) - { - timeoutThread = null; - return; - } - - long now = System.currentTimeMillis(); - - TimeoutToken tt = (TimeoutToken) todolist.getFirst(); - - if (tt.runTime > now) - { - /* Not ready yet, sleep a little bit */ - - try - { - todolist.wait(tt.runTime - now); - } - catch (InterruptedException e) - { - } - - /* We cannot simply go on, since it could be that the token - * was removed (cancelled) or another one has been inserted in - * the meantime. - */ - - continue; - } - - todolist.removeFirst(); - - try - { - tt.handler.run(); - } - catch (Exception e) - { - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - log.log(20, "Exeception in Timeout handler:" + e.getMessage() + "(" + sw.toString() + ")"); - } - } - } - } - } - - /* The list object is also used for locking purposes */ - private static final LinkedList todolist = new LinkedList(); - - private static Thread timeoutThread = null; - - /** - * It is assumed that the passed handler will not execute for a long time. - * - * @param runTime - * @param handler - * @return a TimeoutToken that can be used to cancel the timeout. - */ - public static final TimeoutToken addTimeoutHandler(long runTime, Runnable handler) - { - TimeoutToken token = new TimeoutToken(runTime, handler); - - synchronized (todolist) - { - todolist.add(token); - Collections.sort(todolist); - - if (timeoutThread != null) - timeoutThread.interrupt(); - else - { - timeoutThread = new TimeoutThread(); - timeoutThread.setDaemon(true); - timeoutThread.start(); - } - } - - return token; - } - - public static final void cancelTimeoutHandler(TimeoutToken token) - { - synchronized (todolist) - { - todolist.remove(token); - - if (timeoutThread != null) - timeoutThread.interrupt(); - } - } - -} diff --git a/src/com/trilead/ssh2/util/Tokenizer.java b/src/com/trilead/ssh2/util/Tokenizer.java deleted file mode 100644 index dfd480b..0000000 --- a/src/com/trilead/ssh2/util/Tokenizer.java +++ /dev/null @@ -1,51 +0,0 @@ - -package com.trilead.ssh2.util; - -/** - * Tokenizer. Why? Because StringTokenizer is not available in J2ME. - * - * @author Christian Plattner, plattner@trilead.com - * @version $Id: Tokenizer.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ - */ -public class Tokenizer -{ - /** - * Exists because StringTokenizer is not available in J2ME. - * Returns an array with at least 1 entry. - * - * @param source must be non-null - * @param delimiter - * @return an array of Strings - */ - public static String[] parseTokens(String source, char delimiter) - { - int numtoken = 1; - - for (int i = 0; i < source.length(); i++) - { - if (source.charAt(i) == delimiter) - numtoken++; - } - - String list[] = new String[numtoken]; - int nextfield = 0; - - for (int i = 0; i < numtoken; i++) - { - if (nextfield >= source.length()) - { - list[i] = ""; - } - else - { - int idx = source.indexOf(delimiter, nextfield); - if (idx == -1) - idx = source.length(); - list[i] = source.substring(nextfield, idx); - nextfield = idx + 1; - } - } - - return list; - } -} diff --git a/src/de/mud/telnet/TelnetProtocolHandler.java b/src/de/mud/telnet/TelnetProtocolHandler.java deleted file mode 100644 index 74f08bb..0000000 --- a/src/de/mud/telnet/TelnetProtocolHandler.java +++ /dev/null @@ -1,678 +0,0 @@ -/* - * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform". - * - * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved. - * - * Please visit http://javatelnet.org/ for updates and contact. - * - * --LICENSE NOTICE-- - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * --LICENSE NOTICE-- - * - */ - -package de.mud.telnet; - -import java.io.IOException; -/** - * This is a telnet protocol handler. The handler needs implementations - * for several methods to handle the telnet options and to be able to - * read and write the buffer. - * <P> - * <B>Maintainer:</B> Marcus Meissner - * - * @version $Id: TelnetProtocolHandler.java 503 2005-10-24 07:34:13Z marcus $ - * @author Matthias L. Jugel, Marcus Meissner - */ -public abstract class TelnetProtocolHandler { - /** contains the current revision id */ - public final static String ID = "$Id: TelnetProtocolHandler.java 503 2005-10-24 07:34:13Z marcus $"; - - /** debug level */ - private final static int debug = 0; - - /** temporary buffer for data-telnetstuff-data transformation */ - private byte[] tempbuf = new byte[0]; - - /** the data sent on pressing <RETURN> \n */ - private byte[] crlf = new byte[2]; - /** the data sent on pressing <LineFeed> \r */ - private byte[] cr = new byte[2]; - - /** - * Create a new telnet protocol handler. - */ - public TelnetProtocolHandler() { - reset(); - - crlf[0] = 13; crlf[1] = 10; - cr[0] = 13; cr[1] = 0; - } - - /** - * Get the current terminal type for TTYPE telnet option. - * @return the string id of the terminal - */ - protected abstract String getTerminalType(); - - /** - * Get the current window size of the terminal for the - * NAWS telnet option. - * @return the size of the terminal as Dimension - */ - protected abstract int[] getWindowSize(); - - /** - * Set the local echo option of telnet. - * @param echo true for local echo, false for no local echo - */ - protected abstract void setLocalEcho(boolean echo); - - /** - * Generate an EOR (end of record) request. For use by prompt displaying. - */ - protected abstract void notifyEndOfRecord(); - - /** - * Send data to the remote host. - * @param b array of bytes to send - */ - protected abstract void write(byte[] b) throws IOException; - - /** - * Read the charset name from terminal. - */ - protected abstract String getCharsetName(); - - /** - * Send one byte to the remote host. - * @param b the byte to be sent - * @see #write(byte[] b) - */ - private static byte[] one = new byte[1]; - private void write(byte b) throws IOException { - one[0] = b; - write(one); - } - - /** - * Reset the protocol handler. This may be necessary after the - * connection was closed or some other problem occured. - */ - public void reset() { - neg_state = 0; - receivedDX = new byte[256]; - sentDX = new byte[256]; - receivedWX = new byte[256]; - sentWX = new byte[256]; - } - - // =================================================================== - // the actual negotiation handling for the telnet protocol follows: - // =================================================================== - - /** state variable for telnet negotiation reader */ - private byte neg_state = 0; - - /** constants for the negotiation state */ - private final static byte STATE_DATA = 0; - private final static byte STATE_IAC = 1; - private final static byte STATE_IACSB = 2; - private final static byte STATE_IACWILL = 3; - private final static byte STATE_IACDO = 4; - private final static byte STATE_IACWONT = 5; - private final static byte STATE_IACDONT = 6; - private final static byte STATE_IACSBIAC = 7; - private final static byte STATE_IACSBDATA = 8; - private final static byte STATE_IACSBDATAIAC = 9; - - /** What IAC SB <xx> we are handling right now */ - private byte current_sb; - - /** current SB negotiation buffer */ - private byte[] sbbuf; - - /** IAC - init sequence for telnet negotiation. */ - private final static byte IAC = (byte)255; - /** [IAC] End Of Record */ - private final static byte EOR = (byte)239; - /** [IAC] WILL */ - private final static byte WILL = (byte)251; - /** [IAC] WONT */ - private final static byte WONT = (byte)252; - /** [IAC] DO */ - private final static byte DO = (byte)253; - /** [IAC] DONT */ - private final static byte DONT = (byte)254; - /** [IAC] Sub Begin */ - private final static byte SB = (byte)250; - /** [IAC] Sub End */ - private final static byte SE = (byte)240; - /** Telnet option: binary mode */ - private final static byte TELOPT_BINARY= (byte)0; /* binary mode */ - /** Telnet option: echo text */ - private final static byte TELOPT_ECHO = (byte)1; /* echo on/off */ - /** Telnet option: sga */ - private final static byte TELOPT_SGA = (byte)3; /* supress go ahead */ - /** Telnet option: End Of Record */ - private final static byte TELOPT_EOR = (byte)25; /* end of record */ - /** Telnet option: Negotiate About Window Size */ - private final static byte TELOPT_NAWS = (byte)31; /* NA-WindowSize*/ - /** Telnet option: Terminal Type */ - private final static byte TELOPT_TTYPE = (byte)24; /* terminal type */ - /** Telnet option: CHARSET */ - private final static byte TELOPT_CHARSET= (byte)42; /* charset */ - - private final static byte[] IACWILL = { IAC, WILL }; - private final static byte[] IACWONT = { IAC, WONT }; - private final static byte[] IACDO = { IAC, DO }; - private final static byte[] IACDONT = { IAC, DONT }; - private final static byte[] IACSB = { IAC, SB }; - private final static byte[] IACSE = { IAC, SE }; - - private final static byte CHARSET_ACCEPTED = (byte)2; - private final static byte CHARSET_REJECTED = (byte)3; - - /** Telnet option qualifier 'IS' */ - private final static byte TELQUAL_IS = (byte)0; - /** Telnet option qualifier 'SEND' */ - private final static byte TELQUAL_SEND = (byte)1; - - /** What IAC DO(NT) request do we have received already ? */ - private byte[] receivedDX; - /** What IAC WILL/WONT request do we have received already ? */ - private byte[] receivedWX; - /** What IAC DO/DONT request do we have sent already ? */ - private byte[] sentDX; - /** What IAC WILL/WONT request do we have sent already ? */ - private byte[] sentWX; - - /** - * Send a Telnet Escape character (IAC <code>) - */ - public void sendTelnetControl(byte code) - throws IOException { - byte[] b = new byte[2]; - - b[0] = IAC; - b[1] = code; - write(b); - } - - /** - * Send the new Window Size (via NAWS) - */ - public void setWindowSize(int columns,int rows) - throws IOException { - if(debug > 2) System.err.println("sending NAWS"); - - if (receivedDX[TELOPT_NAWS] != DO) { - System.err.println("not allowed to send NAWS? (DONT NAWS)"); - return; - } - write(IAC);write(SB);write(TELOPT_NAWS); - write((byte) (columns >> 8)); - write((byte) (columns & 0xff)); - write((byte) (rows >> 8)); - write((byte) (rows & 0xff)); - write(IAC);write(SE); - } - - - /** - * Handle an incoming IAC SB <type> <bytes> IAC SE - * @param type type of SB - * @param sbata byte array as <bytes> - */ - private void handle_sb(byte type, byte[] sbdata) - throws IOException { - if(debug > 1) - System.err.println("TelnetIO.handle_sb("+type+")"); - switch (type) { - case TELOPT_TTYPE: - if (sbdata.length>0 && sbdata[0]==TELQUAL_SEND) { - write(IACSB);write(TELOPT_TTYPE);write(TELQUAL_IS); - /* FIXME: need more logic here if we use - * more than one terminal type - */ - String ttype = getTerminalType(); - if(ttype == null) ttype = "dumb"; - write(ttype.getBytes()); - write(IACSE); - } - break; - case TELOPT_CHARSET: - System.out.println("Got SB CHARSET"); - - String charsetStr = new String(sbdata, "US-ASCII"); - if (charsetStr.startsWith("TTABLE ")) { - charsetStr = charsetStr.substring(7); - } - String[] charsets = charsetStr.split(charsetStr.substring(0,0)); - String myCharset = getCharsetName(); - for (String charset : charsets) { - if (charset.equals(myCharset)) { - write(IACSB);write(TELOPT_CHARSET);write(CHARSET_ACCEPTED); - write(charset.getBytes()); - write(IACSE); - System.out.println("Sent our charset!"); - return; - } - } - write(IACSB);write(TELOPT_CHARSET);write(CHARSET_REJECTED); - write(IACSE); - break; - } - } - - /** - * Do not send any notifications at startup. We do not know, - * whether the remote client understands telnet protocol handling, - * so we are silent. - * (This used to send IAC WILL SGA, but this is false for a compliant - * client.) - */ - public void startup() throws IOException { - } - /** - * Transpose special telnet codes like 0xff or newlines to values - * that are compliant to the protocol. This method will also send - * the buffer immediately after transposing the data. - * @param buf the data buffer to be sent - */ - public void transpose(byte[] buf) throws IOException { - int i; - - byte[] nbuf,xbuf; - int nbufptr=0; - nbuf = new byte[buf.length*2]; // FIXME: buffer overflows possible - - for (i = 0; i < buf.length ; i++) { - switch (buf[i]) { - // Escape IAC twice in stream ... to be telnet protocol compliant - // this is there in binary and non-binary mode. - case IAC: - nbuf[nbufptr++]=IAC; - nbuf[nbufptr++]=IAC; - break; - // We need to heed RFC 854. LF (\n) is 10, CR (\r) is 13 - // we assume that the Terminal sends \n for lf+cr and \r for just cr - // linefeed+carriage return is CR LF */ - case 10: // \n - if (receivedDX[TELOPT_BINARY + 128 ] != DO) { - while (nbuf.length - nbufptr < crlf.length) { - xbuf = new byte[nbuf.length*2]; - System.arraycopy(nbuf,0,xbuf,0,nbufptr); - nbuf = xbuf; - } - for (int j=0;j<crlf.length;j++) - nbuf[nbufptr++]=crlf[j]; - break; - } else { - // copy verbatim in binary mode. - nbuf[nbufptr++]=buf[i]; - } - break; - // carriage return is CR NUL */ - case 13: // \r - if (receivedDX[TELOPT_BINARY + 128 ] != DO) { - while (nbuf.length - nbufptr < cr.length) { - xbuf = new byte[nbuf.length*2]; - System.arraycopy(nbuf,0,xbuf,0,nbufptr); - nbuf = xbuf; - } - for (int j=0;j<cr.length;j++) - nbuf[nbufptr++]=cr[j]; - } else { - // copy verbatim in binary mode. - nbuf[nbufptr++]=buf[i]; - } - break; - // all other characters are just copied - default: - nbuf[nbufptr++]=buf[i]; - break; - } - } - xbuf = new byte[nbufptr]; - System.arraycopy(nbuf,0,xbuf,0,nbufptr); - write(xbuf); - } - - public void setCRLF(String xcrlf) { crlf = xcrlf.getBytes(); } - public void setCR(String xcr) { cr = xcr.getBytes(); } - - /** - * Handle telnet protocol negotiation. The buffer will be parsed - * and necessary actions are taken according to the telnet protocol. - * See <A HREF="RFC-Telnet-URL">RFC-Telnet</A> - * @param nbuf the byte buffer put out after negotiation - * @return number of bytes processed, 0 for none, and -1 for end of buffer. - */ - public int negotiate(byte nbuf[], int offset) - throws IOException - { - int count = tempbuf.length; - byte[] buf = tempbuf; - byte sendbuf[] = new byte[3]; - byte b,reply; - int boffset = 0, noffset = offset; - boolean dobreak = false; - - if (count == 0) // buffer is empty. - return -1; - - while(!dobreak && (boffset < count) && (noffset < nbuf.length)) { - b=buf[boffset++]; - // of course, byte is a signed entity (-128 -> 127) - // but apparently the SGI Netscape 3.0 doesn't seem - // to care and provides happily values up to 255 - if (b>=128) - b=(byte)(b-256); - if(debug > 2) { - Byte B = new Byte(b); - System.err.print("byte: " + B.intValue()+ " "); - } - switch (neg_state) { - case STATE_DATA: - if (b==IAC) { - neg_state = STATE_IAC; - dobreak = true; // leave the loop so we can sync. - } else - nbuf[noffset++]=b; - break; - case STATE_IAC: - switch (b) { - case IAC: - if(debug > 2) System.err.print("IAC "); - neg_state = STATE_DATA; - nbuf[noffset++]=IAC; - break; - case WILL: - if(debug > 2) System.err.print("WILL "); - neg_state = STATE_IACWILL; - break; - case WONT: - if(debug > 2) System.err.print("WONT "); - neg_state = STATE_IACWONT; - break; - case DONT: - if(debug > 2) System.err.print("DONT "); - neg_state = STATE_IACDONT; - break; - case DO: - if(debug > 2) System.err.print("DO "); - neg_state = STATE_IACDO; - break; - case EOR: - if(debug > 1) System.err.print("EOR "); - notifyEndOfRecord(); - dobreak = true; // leave the loop so we can sync. - neg_state = STATE_DATA; - break; - case SB: - if(debug > 2) System.err.print("SB "); - neg_state = STATE_IACSB; - break; - default: - if(debug > 2) System.err.print("<UNKNOWN "+b+" > "); - neg_state = STATE_DATA; - break; - } - break; - case STATE_IACWILL: - switch(b) { - case TELOPT_ECHO: - if(debug > 2) System.err.println("ECHO"); - reply = DO; - setLocalEcho(false); - break; - case TELOPT_SGA: - if(debug > 2) System.err.println("SGA"); - reply = DO; - break; - case TELOPT_EOR: - if(debug > 2) System.err.println("EOR"); - reply = DO; - break; - case TELOPT_BINARY: - if(debug > 2) System.err.println("BINARY"); - reply = DO; - break; - default: - if(debug > 2) System.err.println("<UNKNOWN,"+b+">"); - reply = DONT; - break; - } - if(debug > 1) System.err.println("<"+b+", WILL ="+WILL+">"); - if (reply != sentDX[b+128] || WILL != receivedWX[b+128]) { - sendbuf[0]=IAC; - sendbuf[1]=reply; - sendbuf[2]=b; - write(sendbuf); - sentDX[b+128] = reply; - receivedWX[b+128] = WILL; - } - neg_state = STATE_DATA; - break; - case STATE_IACWONT: - switch(b) { - case TELOPT_ECHO: - if(debug > 2) System.err.println("ECHO"); - setLocalEcho(true); - reply = DONT; - break; - case TELOPT_SGA: - if(debug > 2) System.err.println("SGA"); - reply = DONT; - break; - case TELOPT_EOR: - if(debug > 2) System.err.println("EOR"); - reply = DONT; - break; - case TELOPT_BINARY: - if(debug > 2) System.err.println("BINARY"); - reply = DONT; - break; - default: - if(debug > 2) System.err.println("<UNKNOWN,"+b+">"); - reply = DONT; - break; - } - if(reply != sentDX[b+128] || WONT != receivedWX[b+128]) { - sendbuf[0]=IAC; - sendbuf[1]=reply; - sendbuf[2]=b; - write(sendbuf); - sentDX[b+128] = reply; - receivedWX[b+128] = WILL; - } - neg_state = STATE_DATA; - break; - case STATE_IACDO: - switch (b) { - case TELOPT_ECHO: - if(debug > 2) System.err.println("ECHO"); - reply = WILL; - setLocalEcho(true); - break; - case TELOPT_SGA: - if(debug > 2) System.err.println("SGA"); - reply = WILL; - break; - case TELOPT_TTYPE: - if(debug > 2) System.err.println("TTYPE"); - reply = WILL; - break; - case TELOPT_BINARY: - if(debug > 2) System.err.println("BINARY"); - reply = WILL; - break; - case TELOPT_NAWS: - if(debug > 2) System.err.println("NAWS"); - int[] size = getWindowSize(); - receivedDX[b] = DO; - if(size == null) { - // this shouldn't happen - write(IAC); - write(WONT); - write(TELOPT_NAWS); - reply = WONT; - sentWX[b] = WONT; - break; - } - reply = WILL; - sentWX[b] = WILL; - sendbuf[0]=IAC; - sendbuf[1]=WILL; - sendbuf[2]=TELOPT_NAWS; - write(sendbuf); - write(IAC);write(SB);write(TELOPT_NAWS); - write((byte) (size[0] >> 8)); - write((byte) (size[0] & 0xff)); - write((byte) (size[1] >> 8)); - write((byte) (size[1] & 0xff)); - write(IAC);write(SE); - break; - default: - if(debug > 2) System.err.println("<UNKNOWN,"+b+">"); - reply = WONT; - break; - } - if(reply != sentWX[128+b] || DO != receivedDX[128+b]) { - sendbuf[0]=IAC; - sendbuf[1]=reply; - sendbuf[2]=b; - write(sendbuf); - sentWX[b+128] = reply; - receivedDX[b+128] = DO; - } - neg_state = STATE_DATA; - break; - case STATE_IACDONT: - switch (b) { - case TELOPT_ECHO: - if(debug > 2) System.err.println("ECHO"); - reply = WONT; - setLocalEcho(false); - break; - case TELOPT_SGA: - if(debug > 2) System.err.println("SGA"); - reply = WONT; - break; - case TELOPT_NAWS: - if(debug > 2) System.err.println("NAWS"); - reply = WONT; - break; - case TELOPT_BINARY: - if(debug > 2) System.err.println("BINARY"); - reply = WONT; - break; - default: - if(debug > 2) System.err.println("<UNKNOWN,"+b+">"); - reply = WONT; - break; - } - if(reply != sentWX[b+128] || DONT != receivedDX[b+128]) { - write(IAC);write(reply);write(b); - sentWX[b+128] = reply; - receivedDX[b+128] = DONT; - } - neg_state = STATE_DATA; - break; - case STATE_IACSBIAC: - if(debug > 2) System.err.println(""+b+" "); - if (b == IAC) { - sbbuf = new byte[0]; - current_sb = b; - neg_state = STATE_IACSBDATA; - } else { - System.err.println("(bad) "+b+" "); - neg_state = STATE_DATA; - } - break; - case STATE_IACSB: - if(debug > 2) System.err.println(""+b+" "); - switch (b) { - case IAC: - neg_state = STATE_IACSBIAC; - break; - default: - current_sb = b; - sbbuf = new byte[0]; - neg_state = STATE_IACSBDATA; - break; - } - break; - case STATE_IACSBDATA: - if (debug > 2) System.err.println(""+b+" "); - switch (b) { - case IAC: - neg_state = STATE_IACSBDATAIAC; - break; - default: - byte[] xsb = new byte[sbbuf.length+1]; - System.arraycopy(sbbuf,0,xsb,0,sbbuf.length); - sbbuf = xsb; - sbbuf[sbbuf.length-1] = b; - break; - } - break; - case STATE_IACSBDATAIAC: - if (debug > 2) System.err.println(""+b+" "); - switch (b) { - case IAC: - neg_state = STATE_IACSBDATA; - byte[] xsb = new byte[sbbuf.length+1]; - System.arraycopy(sbbuf,0,xsb,0,sbbuf.length); - sbbuf = xsb; - sbbuf[sbbuf.length-1] = IAC; - break; - case SE: - handle_sb(current_sb,sbbuf); - current_sb = 0; - neg_state = STATE_DATA; - break; - case SB: - handle_sb(current_sb,sbbuf); - neg_state = STATE_IACSB; - break; - default: - neg_state = STATE_DATA; - break; - } - break; - default: - if (debug > 1) - System.err.println("This should not happen: "+neg_state+" "); - neg_state = STATE_DATA; - break; - } - } - // shrink tempbuf to new processed size. - byte[] xb = new byte[count-boffset]; - System.arraycopy(tempbuf,boffset,xb,0,count-boffset); - tempbuf = xb; - return noffset - offset; - } - - public void inputfeed(byte[] b, int offset, int len) { - byte[] xb = new byte[tempbuf.length+len]; - - System.arraycopy(tempbuf,0,xb,0,tempbuf.length); - System.arraycopy(b,offset,xb,tempbuf.length,len); - tempbuf = xb; - } -} diff --git a/src/de/mud/terminal/Precomposer.java b/src/de/mud/terminal/Precomposer.java deleted file mode 100644 index edad64c..0000000 --- a/src/de/mud/terminal/Precomposer.java +++ /dev/null @@ -1,1052 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package de.mud.terminal; - -/** - * @author Kenny Root - * This data was taken from xterm's precompose.c - */ -public class Precomposer { - public final static char precompositions[][] = { - { 0x226E, 0x003C, 0x0338}, - { 0x2260, 0x003D, 0x0338}, - { 0x226F, 0x003E, 0x0338}, - { 0x00C0, 0x0041, 0x0300}, - { 0x00C1, 0x0041, 0x0301}, - { 0x00C2, 0x0041, 0x0302}, - { 0x00C3, 0x0041, 0x0303}, - { 0x0100, 0x0041, 0x0304}, - { 0x0102, 0x0041, 0x0306}, - { 0x0226, 0x0041, 0x0307}, - { 0x00C4, 0x0041, 0x0308}, - { 0x1EA2, 0x0041, 0x0309}, - { 0x00C5, 0x0041, 0x030A}, - { 0x01CD, 0x0041, 0x030C}, - { 0x0200, 0x0041, 0x030F}, - { 0x0202, 0x0041, 0x0311}, - { 0x1EA0, 0x0041, 0x0323}, - { 0x1E00, 0x0041, 0x0325}, - { 0x0104, 0x0041, 0x0328}, - { 0x1E02, 0x0042, 0x0307}, - { 0x1E04, 0x0042, 0x0323}, - { 0x1E06, 0x0042, 0x0331}, - { 0x0106, 0x0043, 0x0301}, - { 0x0108, 0x0043, 0x0302}, - { 0x010A, 0x0043, 0x0307}, - { 0x010C, 0x0043, 0x030C}, - { 0x00C7, 0x0043, 0x0327}, - { 0x1E0A, 0x0044, 0x0307}, - { 0x010E, 0x0044, 0x030C}, - { 0x1E0C, 0x0044, 0x0323}, - { 0x1E10, 0x0044, 0x0327}, - { 0x1E12, 0x0044, 0x032D}, - { 0x1E0E, 0x0044, 0x0331}, - { 0x00C8, 0x0045, 0x0300}, - { 0x00C9, 0x0045, 0x0301}, - { 0x00CA, 0x0045, 0x0302}, - { 0x1EBC, 0x0045, 0x0303}, - { 0x0112, 0x0045, 0x0304}, - { 0x0114, 0x0045, 0x0306}, - { 0x0116, 0x0045, 0x0307}, - { 0x00CB, 0x0045, 0x0308}, - { 0x1EBA, 0x0045, 0x0309}, - { 0x011A, 0x0045, 0x030C}, - { 0x0204, 0x0045, 0x030F}, - { 0x0206, 0x0045, 0x0311}, - { 0x1EB8, 0x0045, 0x0323}, - { 0x0228, 0x0045, 0x0327}, - { 0x0118, 0x0045, 0x0328}, - { 0x1E18, 0x0045, 0x032D}, - { 0x1E1A, 0x0045, 0x0330}, - { 0x1E1E, 0x0046, 0x0307}, - { 0x01F4, 0x0047, 0x0301}, - { 0x011C, 0x0047, 0x0302}, - { 0x1E20, 0x0047, 0x0304}, - { 0x011E, 0x0047, 0x0306}, - { 0x0120, 0x0047, 0x0307}, - { 0x01E6, 0x0047, 0x030C}, - { 0x0122, 0x0047, 0x0327}, - { 0x0124, 0x0048, 0x0302}, - { 0x1E22, 0x0048, 0x0307}, - { 0x1E26, 0x0048, 0x0308}, - { 0x021E, 0x0048, 0x030C}, - { 0x1E24, 0x0048, 0x0323}, - { 0x1E28, 0x0048, 0x0327}, - { 0x1E2A, 0x0048, 0x032E}, - { 0x00CC, 0x0049, 0x0300}, - { 0x00CD, 0x0049, 0x0301}, - { 0x00CE, 0x0049, 0x0302}, - { 0x0128, 0x0049, 0x0303}, - { 0x012A, 0x0049, 0x0304}, - { 0x012C, 0x0049, 0x0306}, - { 0x0130, 0x0049, 0x0307}, - { 0x00CF, 0x0049, 0x0308}, - { 0x1EC8, 0x0049, 0x0309}, - { 0x01CF, 0x0049, 0x030C}, - { 0x0208, 0x0049, 0x030F}, - { 0x020A, 0x0049, 0x0311}, - { 0x1ECA, 0x0049, 0x0323}, - { 0x012E, 0x0049, 0x0328}, - { 0x1E2C, 0x0049, 0x0330}, - { 0x0134, 0x004A, 0x0302}, - { 0x1E30, 0x004B, 0x0301}, - { 0x01E8, 0x004B, 0x030C}, - { 0x1E32, 0x004B, 0x0323}, - { 0x0136, 0x004B, 0x0327}, - { 0x1E34, 0x004B, 0x0331}, - { 0x0139, 0x004C, 0x0301}, - { 0x013D, 0x004C, 0x030C}, - { 0x1E36, 0x004C, 0x0323}, - { 0x013B, 0x004C, 0x0327}, - { 0x1E3C, 0x004C, 0x032D}, - { 0x1E3A, 0x004C, 0x0331}, - { 0x1E3E, 0x004D, 0x0301}, - { 0x1E40, 0x004D, 0x0307}, - { 0x1E42, 0x004D, 0x0323}, - { 0x01F8, 0x004E, 0x0300}, - { 0x0143, 0x004E, 0x0301}, - { 0x00D1, 0x004E, 0x0303}, - { 0x1E44, 0x004E, 0x0307}, - { 0x0147, 0x004E, 0x030C}, - { 0x1E46, 0x004E, 0x0323}, - { 0x0145, 0x004E, 0x0327}, - { 0x1E4A, 0x004E, 0x032D}, - { 0x1E48, 0x004E, 0x0331}, - { 0x00D2, 0x004F, 0x0300}, - { 0x00D3, 0x004F, 0x0301}, - { 0x00D4, 0x004F, 0x0302}, - { 0x00D5, 0x004F, 0x0303}, - { 0x014C, 0x004F, 0x0304}, - { 0x014E, 0x004F, 0x0306}, - { 0x022E, 0x004F, 0x0307}, - { 0x00D6, 0x004F, 0x0308}, - { 0x1ECE, 0x004F, 0x0309}, - { 0x0150, 0x004F, 0x030B}, - { 0x01D1, 0x004F, 0x030C}, - { 0x020C, 0x004F, 0x030F}, - { 0x020E, 0x004F, 0x0311}, - { 0x01A0, 0x004F, 0x031B}, - { 0x1ECC, 0x004F, 0x0323}, - { 0x01EA, 0x004F, 0x0328}, - { 0x1E54, 0x0050, 0x0301}, - { 0x1E56, 0x0050, 0x0307}, - { 0x0154, 0x0052, 0x0301}, - { 0x1E58, 0x0052, 0x0307}, - { 0x0158, 0x0052, 0x030C}, - { 0x0210, 0x0052, 0x030F}, - { 0x0212, 0x0052, 0x0311}, - { 0x1E5A, 0x0052, 0x0323}, - { 0x0156, 0x0052, 0x0327}, - { 0x1E5E, 0x0052, 0x0331}, - { 0x015A, 0x0053, 0x0301}, - { 0x015C, 0x0053, 0x0302}, - { 0x1E60, 0x0053, 0x0307}, - { 0x0160, 0x0053, 0x030C}, - { 0x1E62, 0x0053, 0x0323}, - { 0x0218, 0x0053, 0x0326}, - { 0x015E, 0x0053, 0x0327}, - { 0x1E6A, 0x0054, 0x0307}, - { 0x0164, 0x0054, 0x030C}, - { 0x1E6C, 0x0054, 0x0323}, - { 0x021A, 0x0054, 0x0326}, - { 0x0162, 0x0054, 0x0327}, - { 0x1E70, 0x0054, 0x032D}, - { 0x1E6E, 0x0054, 0x0331}, - { 0x00D9, 0x0055, 0x0300}, - { 0x00DA, 0x0055, 0x0301}, - { 0x00DB, 0x0055, 0x0302}, - { 0x0168, 0x0055, 0x0303}, - { 0x016A, 0x0055, 0x0304}, - { 0x016C, 0x0055, 0x0306}, - { 0x00DC, 0x0055, 0x0308}, - { 0x1EE6, 0x0055, 0x0309}, - { 0x016E, 0x0055, 0x030A}, - { 0x0170, 0x0055, 0x030B}, - { 0x01D3, 0x0055, 0x030C}, - { 0x0214, 0x0055, 0x030F}, - { 0x0216, 0x0055, 0x0311}, - { 0x01AF, 0x0055, 0x031B}, - { 0x1EE4, 0x0055, 0x0323}, - { 0x1E72, 0x0055, 0x0324}, - { 0x0172, 0x0055, 0x0328}, - { 0x1E76, 0x0055, 0x032D}, - { 0x1E74, 0x0055, 0x0330}, - { 0x1E7C, 0x0056, 0x0303}, - { 0x1E7E, 0x0056, 0x0323}, - { 0x1E80, 0x0057, 0x0300}, - { 0x1E82, 0x0057, 0x0301}, - { 0x0174, 0x0057, 0x0302}, - { 0x1E86, 0x0057, 0x0307}, - { 0x1E84, 0x0057, 0x0308}, - { 0x1E88, 0x0057, 0x0323}, - { 0x1E8A, 0x0058, 0x0307}, - { 0x1E8C, 0x0058, 0x0308}, - { 0x1EF2, 0x0059, 0x0300}, - { 0x00DD, 0x0059, 0x0301}, - { 0x0176, 0x0059, 0x0302}, - { 0x1EF8, 0x0059, 0x0303}, - { 0x0232, 0x0059, 0x0304}, - { 0x1E8E, 0x0059, 0x0307}, - { 0x0178, 0x0059, 0x0308}, - { 0x1EF6, 0x0059, 0x0309}, - { 0x1EF4, 0x0059, 0x0323}, - { 0x0179, 0x005A, 0x0301}, - { 0x1E90, 0x005A, 0x0302}, - { 0x017B, 0x005A, 0x0307}, - { 0x017D, 0x005A, 0x030C}, - { 0x1E92, 0x005A, 0x0323}, - { 0x1E94, 0x005A, 0x0331}, - { 0x00E0, 0x0061, 0x0300}, - { 0x00E1, 0x0061, 0x0301}, - { 0x00E2, 0x0061, 0x0302}, - { 0x00E3, 0x0061, 0x0303}, - { 0x0101, 0x0061, 0x0304}, - { 0x0103, 0x0061, 0x0306}, - { 0x0227, 0x0061, 0x0307}, - { 0x00E4, 0x0061, 0x0308}, - { 0x1EA3, 0x0061, 0x0309}, - { 0x00E5, 0x0061, 0x030A}, - { 0x01CE, 0x0061, 0x030C}, - { 0x0201, 0x0061, 0x030F}, - { 0x0203, 0x0061, 0x0311}, - { 0x1EA1, 0x0061, 0x0323}, - { 0x1E01, 0x0061, 0x0325}, - { 0x0105, 0x0061, 0x0328}, - { 0x1E03, 0x0062, 0x0307}, - { 0x1E05, 0x0062, 0x0323}, - { 0x1E07, 0x0062, 0x0331}, - { 0x0107, 0x0063, 0x0301}, - { 0x0109, 0x0063, 0x0302}, - { 0x010B, 0x0063, 0x0307}, - { 0x010D, 0x0063, 0x030C}, - { 0x00E7, 0x0063, 0x0327}, - { 0x1E0B, 0x0064, 0x0307}, - { 0x010F, 0x0064, 0x030C}, - { 0x1E0D, 0x0064, 0x0323}, - { 0x1E11, 0x0064, 0x0327}, - { 0x1E13, 0x0064, 0x032D}, - { 0x1E0F, 0x0064, 0x0331}, - { 0x00E8, 0x0065, 0x0300}, - { 0x00E9, 0x0065, 0x0301}, - { 0x00EA, 0x0065, 0x0302}, - { 0x1EBD, 0x0065, 0x0303}, - { 0x0113, 0x0065, 0x0304}, - { 0x0115, 0x0065, 0x0306}, - { 0x0117, 0x0065, 0x0307}, - { 0x00EB, 0x0065, 0x0308}, - { 0x1EBB, 0x0065, 0x0309}, - { 0x011B, 0x0065, 0x030C}, - { 0x0205, 0x0065, 0x030F}, - { 0x0207, 0x0065, 0x0311}, - { 0x1EB9, 0x0065, 0x0323}, - { 0x0229, 0x0065, 0x0327}, - { 0x0119, 0x0065, 0x0328}, - { 0x1E19, 0x0065, 0x032D}, - { 0x1E1B, 0x0065, 0x0330}, - { 0x1E1F, 0x0066, 0x0307}, - { 0x01F5, 0x0067, 0x0301}, - { 0x011D, 0x0067, 0x0302}, - { 0x1E21, 0x0067, 0x0304}, - { 0x011F, 0x0067, 0x0306}, - { 0x0121, 0x0067, 0x0307}, - { 0x01E7, 0x0067, 0x030C}, - { 0x0123, 0x0067, 0x0327}, - { 0x0125, 0x0068, 0x0302}, - { 0x1E23, 0x0068, 0x0307}, - { 0x1E27, 0x0068, 0x0308}, - { 0x021F, 0x0068, 0x030C}, - { 0x1E25, 0x0068, 0x0323}, - { 0x1E29, 0x0068, 0x0327}, - { 0x1E2B, 0x0068, 0x032E}, - { 0x1E96, 0x0068, 0x0331}, - { 0x00EC, 0x0069, 0x0300}, - { 0x00ED, 0x0069, 0x0301}, - { 0x00EE, 0x0069, 0x0302}, - { 0x0129, 0x0069, 0x0303}, - { 0x012B, 0x0069, 0x0304}, - { 0x012D, 0x0069, 0x0306}, - { 0x00EF, 0x0069, 0x0308}, - { 0x1EC9, 0x0069, 0x0309}, - { 0x01D0, 0x0069, 0x030C}, - { 0x0209, 0x0069, 0x030F}, - { 0x020B, 0x0069, 0x0311}, - { 0x1ECB, 0x0069, 0x0323}, - { 0x012F, 0x0069, 0x0328}, - { 0x1E2D, 0x0069, 0x0330}, - { 0x0135, 0x006A, 0x0302}, - { 0x01F0, 0x006A, 0x030C}, - { 0x1E31, 0x006B, 0x0301}, - { 0x01E9, 0x006B, 0x030C}, - { 0x1E33, 0x006B, 0x0323}, - { 0x0137, 0x006B, 0x0327}, - { 0x1E35, 0x006B, 0x0331}, - { 0x013A, 0x006C, 0x0301}, - { 0x013E, 0x006C, 0x030C}, - { 0x1E37, 0x006C, 0x0323}, - { 0x013C, 0x006C, 0x0327}, - { 0x1E3D, 0x006C, 0x032D}, - { 0x1E3B, 0x006C, 0x0331}, - { 0x1E3F, 0x006D, 0x0301}, - { 0x1E41, 0x006D, 0x0307}, - { 0x1E43, 0x006D, 0x0323}, - { 0x01F9, 0x006E, 0x0300}, - { 0x0144, 0x006E, 0x0301}, - { 0x00F1, 0x006E, 0x0303}, - { 0x1E45, 0x006E, 0x0307}, - { 0x0148, 0x006E, 0x030C}, - { 0x1E47, 0x006E, 0x0323}, - { 0x0146, 0x006E, 0x0327}, - { 0x1E4B, 0x006E, 0x032D}, - { 0x1E49, 0x006E, 0x0331}, - { 0x00F2, 0x006F, 0x0300}, - { 0x00F3, 0x006F, 0x0301}, - { 0x00F4, 0x006F, 0x0302}, - { 0x00F5, 0x006F, 0x0303}, - { 0x014D, 0x006F, 0x0304}, - { 0x014F, 0x006F, 0x0306}, - { 0x022F, 0x006F, 0x0307}, - { 0x00F6, 0x006F, 0x0308}, - { 0x1ECF, 0x006F, 0x0309}, - { 0x0151, 0x006F, 0x030B}, - { 0x01D2, 0x006F, 0x030C}, - { 0x020D, 0x006F, 0x030F}, - { 0x020F, 0x006F, 0x0311}, - { 0x01A1, 0x006F, 0x031B}, - { 0x1ECD, 0x006F, 0x0323}, - { 0x01EB, 0x006F, 0x0328}, - { 0x1E55, 0x0070, 0x0301}, - { 0x1E57, 0x0070, 0x0307}, - { 0x0155, 0x0072, 0x0301}, - { 0x1E59, 0x0072, 0x0307}, - { 0x0159, 0x0072, 0x030C}, - { 0x0211, 0x0072, 0x030F}, - { 0x0213, 0x0072, 0x0311}, - { 0x1E5B, 0x0072, 0x0323}, - { 0x0157, 0x0072, 0x0327}, - { 0x1E5F, 0x0072, 0x0331}, - { 0x015B, 0x0073, 0x0301}, - { 0x015D, 0x0073, 0x0302}, - { 0x1E61, 0x0073, 0x0307}, - { 0x0161, 0x0073, 0x030C}, - { 0x1E63, 0x0073, 0x0323}, - { 0x0219, 0x0073, 0x0326}, - { 0x015F, 0x0073, 0x0327}, - { 0x1E6B, 0x0074, 0x0307}, - { 0x1E97, 0x0074, 0x0308}, - { 0x0165, 0x0074, 0x030C}, - { 0x1E6D, 0x0074, 0x0323}, - { 0x021B, 0x0074, 0x0326}, - { 0x0163, 0x0074, 0x0327}, - { 0x1E71, 0x0074, 0x032D}, - { 0x1E6F, 0x0074, 0x0331}, - { 0x00F9, 0x0075, 0x0300}, - { 0x00FA, 0x0075, 0x0301}, - { 0x00FB, 0x0075, 0x0302}, - { 0x0169, 0x0075, 0x0303}, - { 0x016B, 0x0075, 0x0304}, - { 0x016D, 0x0075, 0x0306}, - { 0x00FC, 0x0075, 0x0308}, - { 0x1EE7, 0x0075, 0x0309}, - { 0x016F, 0x0075, 0x030A}, - { 0x0171, 0x0075, 0x030B}, - { 0x01D4, 0x0075, 0x030C}, - { 0x0215, 0x0075, 0x030F}, - { 0x0217, 0x0075, 0x0311}, - { 0x01B0, 0x0075, 0x031B}, - { 0x1EE5, 0x0075, 0x0323}, - { 0x1E73, 0x0075, 0x0324}, - { 0x0173, 0x0075, 0x0328}, - { 0x1E77, 0x0075, 0x032D}, - { 0x1E75, 0x0075, 0x0330}, - { 0x1E7D, 0x0076, 0x0303}, - { 0x1E7F, 0x0076, 0x0323}, - { 0x1E81, 0x0077, 0x0300}, - { 0x1E83, 0x0077, 0x0301}, - { 0x0175, 0x0077, 0x0302}, - { 0x1E87, 0x0077, 0x0307}, - { 0x1E85, 0x0077, 0x0308}, - { 0x1E98, 0x0077, 0x030A}, - { 0x1E89, 0x0077, 0x0323}, - { 0x1E8B, 0x0078, 0x0307}, - { 0x1E8D, 0x0078, 0x0308}, - { 0x1EF3, 0x0079, 0x0300}, - { 0x00FD, 0x0079, 0x0301}, - { 0x0177, 0x0079, 0x0302}, - { 0x1EF9, 0x0079, 0x0303}, - { 0x0233, 0x0079, 0x0304}, - { 0x1E8F, 0x0079, 0x0307}, - { 0x00FF, 0x0079, 0x0308}, - { 0x1EF7, 0x0079, 0x0309}, - { 0x1E99, 0x0079, 0x030A}, - { 0x1EF5, 0x0079, 0x0323}, - { 0x017A, 0x007A, 0x0301}, - { 0x1E91, 0x007A, 0x0302}, - { 0x017C, 0x007A, 0x0307}, - { 0x017E, 0x007A, 0x030C}, - { 0x1E93, 0x007A, 0x0323}, - { 0x1E95, 0x007A, 0x0331}, - { 0x1FED, 0x00A8, 0x0300}, - { 0x0385, 0x00A8, 0x0301}, - { 0x1FC1, 0x00A8, 0x0342}, - { 0x1EA6, 0x00C2, 0x0300}, - { 0x1EA4, 0x00C2, 0x0301}, - { 0x1EAA, 0x00C2, 0x0303}, - { 0x1EA8, 0x00C2, 0x0309}, - { 0x01DE, 0x00C4, 0x0304}, - { 0x01FA, 0x00C5, 0x0301}, - { 0x01FC, 0x00C6, 0x0301}, - { 0x01E2, 0x00C6, 0x0304}, - { 0x1E08, 0x00C7, 0x0301}, - { 0x1EC0, 0x00CA, 0x0300}, - { 0x1EBE, 0x00CA, 0x0301}, - { 0x1EC4, 0x00CA, 0x0303}, - { 0x1EC2, 0x00CA, 0x0309}, - { 0x1E2E, 0x00CF, 0x0301}, - { 0x1ED2, 0x00D4, 0x0300}, - { 0x1ED0, 0x00D4, 0x0301}, - { 0x1ED6, 0x00D4, 0x0303}, - { 0x1ED4, 0x00D4, 0x0309}, - { 0x1E4C, 0x00D5, 0x0301}, - { 0x022C, 0x00D5, 0x0304}, - { 0x1E4E, 0x00D5, 0x0308}, - { 0x022A, 0x00D6, 0x0304}, - { 0x01FE, 0x00D8, 0x0301}, - { 0x01DB, 0x00DC, 0x0300}, - { 0x01D7, 0x00DC, 0x0301}, - { 0x01D5, 0x00DC, 0x0304}, - { 0x01D9, 0x00DC, 0x030C}, - { 0x1EA7, 0x00E2, 0x0300}, - { 0x1EA5, 0x00E2, 0x0301}, - { 0x1EAB, 0x00E2, 0x0303}, - { 0x1EA9, 0x00E2, 0x0309}, - { 0x01DF, 0x00E4, 0x0304}, - { 0x01FB, 0x00E5, 0x0301}, - { 0x01FD, 0x00E6, 0x0301}, - { 0x01E3, 0x00E6, 0x0304}, - { 0x1E09, 0x00E7, 0x0301}, - { 0x1EC1, 0x00EA, 0x0300}, - { 0x1EBF, 0x00EA, 0x0301}, - { 0x1EC5, 0x00EA, 0x0303}, - { 0x1EC3, 0x00EA, 0x0309}, - { 0x1E2F, 0x00EF, 0x0301}, - { 0x1ED3, 0x00F4, 0x0300}, - { 0x1ED1, 0x00F4, 0x0301}, - { 0x1ED7, 0x00F4, 0x0303}, - { 0x1ED5, 0x00F4, 0x0309}, - { 0x1E4D, 0x00F5, 0x0301}, - { 0x022D, 0x00F5, 0x0304}, - { 0x1E4F, 0x00F5, 0x0308}, - { 0x022B, 0x00F6, 0x0304}, - { 0x01FF, 0x00F8, 0x0301}, - { 0x01DC, 0x00FC, 0x0300}, - { 0x01D8, 0x00FC, 0x0301}, - { 0x01D6, 0x00FC, 0x0304}, - { 0x01DA, 0x00FC, 0x030C}, - { 0x1EB0, 0x0102, 0x0300}, - { 0x1EAE, 0x0102, 0x0301}, - { 0x1EB4, 0x0102, 0x0303}, - { 0x1EB2, 0x0102, 0x0309}, - { 0x1EB1, 0x0103, 0x0300}, - { 0x1EAF, 0x0103, 0x0301}, - { 0x1EB5, 0x0103, 0x0303}, - { 0x1EB3, 0x0103, 0x0309}, - { 0x1E14, 0x0112, 0x0300}, - { 0x1E16, 0x0112, 0x0301}, - { 0x1E15, 0x0113, 0x0300}, - { 0x1E17, 0x0113, 0x0301}, - { 0x1E50, 0x014C, 0x0300}, - { 0x1E52, 0x014C, 0x0301}, - { 0x1E51, 0x014D, 0x0300}, - { 0x1E53, 0x014D, 0x0301}, - { 0x1E64, 0x015A, 0x0307}, - { 0x1E65, 0x015B, 0x0307}, - { 0x1E66, 0x0160, 0x0307}, - { 0x1E67, 0x0161, 0x0307}, - { 0x1E78, 0x0168, 0x0301}, - { 0x1E79, 0x0169, 0x0301}, - { 0x1E7A, 0x016A, 0x0308}, - { 0x1E7B, 0x016B, 0x0308}, - { 0x1E9B, 0x017F, 0x0307}, - { 0x1EDC, 0x01A0, 0x0300}, - { 0x1EDA, 0x01A0, 0x0301}, - { 0x1EE0, 0x01A0, 0x0303}, - { 0x1EDE, 0x01A0, 0x0309}, - { 0x1EE2, 0x01A0, 0x0323}, - { 0x1EDD, 0x01A1, 0x0300}, - { 0x1EDB, 0x01A1, 0x0301}, - { 0x1EE1, 0x01A1, 0x0303}, - { 0x1EDF, 0x01A1, 0x0309}, - { 0x1EE3, 0x01A1, 0x0323}, - { 0x1EEA, 0x01AF, 0x0300}, - { 0x1EE8, 0x01AF, 0x0301}, - { 0x1EEE, 0x01AF, 0x0303}, - { 0x1EEC, 0x01AF, 0x0309}, - { 0x1EF0, 0x01AF, 0x0323}, - { 0x1EEB, 0x01B0, 0x0300}, - { 0x1EE9, 0x01B0, 0x0301}, - { 0x1EEF, 0x01B0, 0x0303}, - { 0x1EED, 0x01B0, 0x0309}, - { 0x1EF1, 0x01B0, 0x0323}, - { 0x01EE, 0x01B7, 0x030C}, - { 0x01EC, 0x01EA, 0x0304}, - { 0x01ED, 0x01EB, 0x0304}, - { 0x01E0, 0x0226, 0x0304}, - { 0x01E1, 0x0227, 0x0304}, - { 0x1E1C, 0x0228, 0x0306}, - { 0x1E1D, 0x0229, 0x0306}, - { 0x0230, 0x022E, 0x0304}, - { 0x0231, 0x022F, 0x0304}, - { 0x01EF, 0x0292, 0x030C}, - { 0x0344, 0x0308, 0x0301}, - { 0x1FBA, 0x0391, 0x0300}, - { 0x0386, 0x0391, 0x0301}, - { 0x1FB9, 0x0391, 0x0304}, - { 0x1FB8, 0x0391, 0x0306}, - { 0x1F08, 0x0391, 0x0313}, - { 0x1F09, 0x0391, 0x0314}, - { 0x1FBC, 0x0391, 0x0345}, - { 0x1FC8, 0x0395, 0x0300}, - { 0x0388, 0x0395, 0x0301}, - { 0x1F18, 0x0395, 0x0313}, - { 0x1F19, 0x0395, 0x0314}, - { 0x1FCA, 0x0397, 0x0300}, - { 0x0389, 0x0397, 0x0301}, - { 0x1F28, 0x0397, 0x0313}, - { 0x1F29, 0x0397, 0x0314}, - { 0x1FCC, 0x0397, 0x0345}, - { 0x1FDA, 0x0399, 0x0300}, - { 0x038A, 0x0399, 0x0301}, - { 0x1FD9, 0x0399, 0x0304}, - { 0x1FD8, 0x0399, 0x0306}, - { 0x03AA, 0x0399, 0x0308}, - { 0x1F38, 0x0399, 0x0313}, - { 0x1F39, 0x0399, 0x0314}, - { 0x1FF8, 0x039F, 0x0300}, - { 0x038C, 0x039F, 0x0301}, - { 0x1F48, 0x039F, 0x0313}, - { 0x1F49, 0x039F, 0x0314}, - { 0x1FEC, 0x03A1, 0x0314}, - { 0x1FEA, 0x03A5, 0x0300}, - { 0x038E, 0x03A5, 0x0301}, - { 0x1FE9, 0x03A5, 0x0304}, - { 0x1FE8, 0x03A5, 0x0306}, - { 0x03AB, 0x03A5, 0x0308}, - { 0x1F59, 0x03A5, 0x0314}, - { 0x1FFA, 0x03A9, 0x0300}, - { 0x038F, 0x03A9, 0x0301}, - { 0x1F68, 0x03A9, 0x0313}, - { 0x1F69, 0x03A9, 0x0314}, - { 0x1FFC, 0x03A9, 0x0345}, - { 0x1FB4, 0x03AC, 0x0345}, - { 0x1FC4, 0x03AE, 0x0345}, - { 0x1F70, 0x03B1, 0x0300}, - { 0x03AC, 0x03B1, 0x0301}, - { 0x1FB1, 0x03B1, 0x0304}, - { 0x1FB0, 0x03B1, 0x0306}, - { 0x1F00, 0x03B1, 0x0313}, - { 0x1F01, 0x03B1, 0x0314}, - { 0x1FB6, 0x03B1, 0x0342}, - { 0x1FB3, 0x03B1, 0x0345}, - { 0x1F72, 0x03B5, 0x0300}, - { 0x03AD, 0x03B5, 0x0301}, - { 0x1F10, 0x03B5, 0x0313}, - { 0x1F11, 0x03B5, 0x0314}, - { 0x1F74, 0x03B7, 0x0300}, - { 0x03AE, 0x03B7, 0x0301}, - { 0x1F20, 0x03B7, 0x0313}, - { 0x1F21, 0x03B7, 0x0314}, - { 0x1FC6, 0x03B7, 0x0342}, - { 0x1FC3, 0x03B7, 0x0345}, - { 0x1F76, 0x03B9, 0x0300}, - { 0x03AF, 0x03B9, 0x0301}, - { 0x1FD1, 0x03B9, 0x0304}, - { 0x1FD0, 0x03B9, 0x0306}, - { 0x03CA, 0x03B9, 0x0308}, - { 0x1F30, 0x03B9, 0x0313}, - { 0x1F31, 0x03B9, 0x0314}, - { 0x1FD6, 0x03B9, 0x0342}, - { 0x1F78, 0x03BF, 0x0300}, - { 0x03CC, 0x03BF, 0x0301}, - { 0x1F40, 0x03BF, 0x0313}, - { 0x1F41, 0x03BF, 0x0314}, - { 0x1FE4, 0x03C1, 0x0313}, - { 0x1FE5, 0x03C1, 0x0314}, - { 0x1F7A, 0x03C5, 0x0300}, - { 0x03CD, 0x03C5, 0x0301}, - { 0x1FE1, 0x03C5, 0x0304}, - { 0x1FE0, 0x03C5, 0x0306}, - { 0x03CB, 0x03C5, 0x0308}, - { 0x1F50, 0x03C5, 0x0313}, - { 0x1F51, 0x03C5, 0x0314}, - { 0x1FE6, 0x03C5, 0x0342}, - { 0x1F7C, 0x03C9, 0x0300}, - { 0x03CE, 0x03C9, 0x0301}, - { 0x1F60, 0x03C9, 0x0313}, - { 0x1F61, 0x03C9, 0x0314}, - { 0x1FF6, 0x03C9, 0x0342}, - { 0x1FF3, 0x03C9, 0x0345}, - { 0x1FD2, 0x03CA, 0x0300}, - { 0x0390, 0x03CA, 0x0301}, - { 0x1FD7, 0x03CA, 0x0342}, - { 0x1FE2, 0x03CB, 0x0300}, - { 0x03B0, 0x03CB, 0x0301}, - { 0x1FE7, 0x03CB, 0x0342}, - { 0x1FF4, 0x03CE, 0x0345}, - { 0x03D3, 0x03D2, 0x0301}, - { 0x03D4, 0x03D2, 0x0308}, - { 0x0407, 0x0406, 0x0308}, - { 0x04D0, 0x0410, 0x0306}, - { 0x04D2, 0x0410, 0x0308}, - { 0x0403, 0x0413, 0x0301}, - { 0x0400, 0x0415, 0x0300}, - { 0x04D6, 0x0415, 0x0306}, - { 0x0401, 0x0415, 0x0308}, - { 0x04C1, 0x0416, 0x0306}, - { 0x04DC, 0x0416, 0x0308}, - { 0x04DE, 0x0417, 0x0308}, - { 0x040D, 0x0418, 0x0300}, - { 0x04E2, 0x0418, 0x0304}, - { 0x0419, 0x0418, 0x0306}, - { 0x04E4, 0x0418, 0x0308}, - { 0x040C, 0x041A, 0x0301}, - { 0x04E6, 0x041E, 0x0308}, - { 0x04EE, 0x0423, 0x0304}, - { 0x040E, 0x0423, 0x0306}, - { 0x04F0, 0x0423, 0x0308}, - { 0x04F2, 0x0423, 0x030B}, - { 0x04F4, 0x0427, 0x0308}, - { 0x04F8, 0x042B, 0x0308}, - { 0x04EC, 0x042D, 0x0308}, - { 0x04D1, 0x0430, 0x0306}, - { 0x04D3, 0x0430, 0x0308}, - { 0x0453, 0x0433, 0x0301}, - { 0x0450, 0x0435, 0x0300}, - { 0x04D7, 0x0435, 0x0306}, - { 0x0451, 0x0435, 0x0308}, - { 0x04C2, 0x0436, 0x0306}, - { 0x04DD, 0x0436, 0x0308}, - { 0x04DF, 0x0437, 0x0308}, - { 0x045D, 0x0438, 0x0300}, - { 0x04E3, 0x0438, 0x0304}, - { 0x0439, 0x0438, 0x0306}, - { 0x04E5, 0x0438, 0x0308}, - { 0x045C, 0x043A, 0x0301}, - { 0x04E7, 0x043E, 0x0308}, - { 0x04EF, 0x0443, 0x0304}, - { 0x045E, 0x0443, 0x0306}, - { 0x04F1, 0x0443, 0x0308}, - { 0x04F3, 0x0443, 0x030B}, - { 0x04F5, 0x0447, 0x0308}, - { 0x04F9, 0x044B, 0x0308}, - { 0x04ED, 0x044D, 0x0308}, - { 0x0457, 0x0456, 0x0308}, - { 0x0476, 0x0474, 0x030F}, - { 0x0477, 0x0475, 0x030F}, - { 0x04DA, 0x04D8, 0x0308}, - { 0x04DB, 0x04D9, 0x0308}, - { 0x04EA, 0x04E8, 0x0308}, - { 0x04EB, 0x04E9, 0x0308}, - { 0xFB2E, 0x05D0, 0x05B7}, - { 0xFB2F, 0x05D0, 0x05B8}, - { 0xFB30, 0x05D0, 0x05BC}, - { 0xFB31, 0x05D1, 0x05BC}, - { 0xFB4C, 0x05D1, 0x05BF}, - { 0xFB32, 0x05D2, 0x05BC}, - { 0xFB33, 0x05D3, 0x05BC}, - { 0xFB34, 0x05D4, 0x05BC}, - { 0xFB4B, 0x05D5, 0x05B9}, - { 0xFB35, 0x05D5, 0x05BC}, - { 0xFB36, 0x05D6, 0x05BC}, - { 0xFB38, 0x05D8, 0x05BC}, - { 0xFB1D, 0x05D9, 0x05B4}, - { 0xFB39, 0x05D9, 0x05BC}, - { 0xFB3A, 0x05DA, 0x05BC}, - { 0xFB3B, 0x05DB, 0x05BC}, - { 0xFB4D, 0x05DB, 0x05BF}, - { 0xFB3C, 0x05DC, 0x05BC}, - { 0xFB3E, 0x05DE, 0x05BC}, - { 0xFB40, 0x05E0, 0x05BC}, - { 0xFB41, 0x05E1, 0x05BC}, - { 0xFB43, 0x05E3, 0x05BC}, - { 0xFB44, 0x05E4, 0x05BC}, - { 0xFB4E, 0x05E4, 0x05BF}, - { 0xFB46, 0x05E6, 0x05BC}, - { 0xFB47, 0x05E7, 0x05BC}, - { 0xFB48, 0x05E8, 0x05BC}, - { 0xFB49, 0x05E9, 0x05BC}, - { 0xFB2A, 0x05E9, 0x05C1}, - { 0xFB2B, 0x05E9, 0x05C2}, - { 0xFB4A, 0x05EA, 0x05BC}, - { 0xFB1F, 0x05F2, 0x05B7}, - { 0x0622, 0x0627, 0x0653}, - { 0x0623, 0x0627, 0x0654}, - { 0x0625, 0x0627, 0x0655}, - { 0x0624, 0x0648, 0x0654}, - { 0x0626, 0x064A, 0x0654}, - { 0x06C2, 0x06C1, 0x0654}, - { 0x06D3, 0x06D2, 0x0654}, - { 0x06C0, 0x06D5, 0x0654}, - { 0x0958, 0x0915, 0x093C}, - { 0x0959, 0x0916, 0x093C}, - { 0x095A, 0x0917, 0x093C}, - { 0x095B, 0x091C, 0x093C}, - { 0x095C, 0x0921, 0x093C}, - { 0x095D, 0x0922, 0x093C}, - { 0x0929, 0x0928, 0x093C}, - { 0x095E, 0x092B, 0x093C}, - { 0x095F, 0x092F, 0x093C}, - { 0x0931, 0x0930, 0x093C}, - { 0x0934, 0x0933, 0x093C}, - { 0x09DC, 0x09A1, 0x09BC}, - { 0x09DD, 0x09A2, 0x09BC}, - { 0x09DF, 0x09AF, 0x09BC}, - { 0x09CB, 0x09C7, 0x09BE}, - { 0x09CC, 0x09C7, 0x09D7}, - { 0x0A59, 0x0A16, 0x0A3C}, - { 0x0A5A, 0x0A17, 0x0A3C}, - { 0x0A5B, 0x0A1C, 0x0A3C}, - { 0x0A5E, 0x0A2B, 0x0A3C}, - { 0x0A33, 0x0A32, 0x0A3C}, - { 0x0A36, 0x0A38, 0x0A3C}, - { 0x0B5C, 0x0B21, 0x0B3C}, - { 0x0B5D, 0x0B22, 0x0B3C}, - { 0x0B4B, 0x0B47, 0x0B3E}, - { 0x0B48, 0x0B47, 0x0B56}, - { 0x0B4C, 0x0B47, 0x0B57}, - { 0x0B94, 0x0B92, 0x0BD7}, - { 0x0BCA, 0x0BC6, 0x0BBE}, - { 0x0BCC, 0x0BC6, 0x0BD7}, - { 0x0BCB, 0x0BC7, 0x0BBE}, - { 0x0C48, 0x0C46, 0x0C56}, - { 0x0CC0, 0x0CBF, 0x0CD5}, - { 0x0CCA, 0x0CC6, 0x0CC2}, - { 0x0CC7, 0x0CC6, 0x0CD5}, - { 0x0CC8, 0x0CC6, 0x0CD6}, - { 0x0CCB, 0x0CCA, 0x0CD5}, - { 0x0D4A, 0x0D46, 0x0D3E}, - { 0x0D4C, 0x0D46, 0x0D57}, - { 0x0D4B, 0x0D47, 0x0D3E}, - { 0x0DDA, 0x0DD9, 0x0DCA}, - { 0x0DDC, 0x0DD9, 0x0DCF}, - { 0x0DDE, 0x0DD9, 0x0DDF}, - { 0x0DDD, 0x0DDC, 0x0DCA}, - { 0x0F69, 0x0F40, 0x0FB5}, - { 0x0F43, 0x0F42, 0x0FB7}, - { 0x0F4D, 0x0F4C, 0x0FB7}, - { 0x0F52, 0x0F51, 0x0FB7}, - { 0x0F57, 0x0F56, 0x0FB7}, - { 0x0F5C, 0x0F5B, 0x0FB7}, - { 0x0F73, 0x0F71, 0x0F72}, - { 0x0F75, 0x0F71, 0x0F74}, - { 0x0F81, 0x0F71, 0x0F80}, - { 0x0FB9, 0x0F90, 0x0FB5}, - { 0x0F93, 0x0F92, 0x0FB7}, - { 0x0F9D, 0x0F9C, 0x0FB7}, - { 0x0FA2, 0x0FA1, 0x0FB7}, - { 0x0FA7, 0x0FA6, 0x0FB7}, - { 0x0FAC, 0x0FAB, 0x0FB7}, - { 0x0F76, 0x0FB2, 0x0F80}, - { 0x0F78, 0x0FB3, 0x0F80}, - { 0x1026, 0x1025, 0x102E}, - { 0x1B06, 0x1B05, 0x1B35}, - { 0x1B08, 0x1B07, 0x1B35}, - { 0x1B0A, 0x1B09, 0x1B35}, - { 0x1B0C, 0x1B0B, 0x1B35}, - { 0x1B0E, 0x1B0D, 0x1B35}, - { 0x1B12, 0x1B11, 0x1B35}, - { 0x1B3B, 0x1B3A, 0x1B35}, - { 0x1B3D, 0x1B3C, 0x1B35}, - { 0x1B40, 0x1B3E, 0x1B35}, - { 0x1B41, 0x1B3F, 0x1B35}, - { 0x1B43, 0x1B42, 0x1B35}, - { 0x1E38, 0x1E36, 0x0304}, - { 0x1E39, 0x1E37, 0x0304}, - { 0x1E5C, 0x1E5A, 0x0304}, - { 0x1E5D, 0x1E5B, 0x0304}, - { 0x1E68, 0x1E62, 0x0307}, - { 0x1E69, 0x1E63, 0x0307}, - { 0x1EAC, 0x1EA0, 0x0302}, - { 0x1EB6, 0x1EA0, 0x0306}, - { 0x1EAD, 0x1EA1, 0x0302}, - { 0x1EB7, 0x1EA1, 0x0306}, - { 0x1EC6, 0x1EB8, 0x0302}, - { 0x1EC7, 0x1EB9, 0x0302}, - { 0x1ED8, 0x1ECC, 0x0302}, - { 0x1ED9, 0x1ECD, 0x0302}, - { 0x1F02, 0x1F00, 0x0300}, - { 0x1F04, 0x1F00, 0x0301}, - { 0x1F06, 0x1F00, 0x0342}, - { 0x1F80, 0x1F00, 0x0345}, - { 0x1F03, 0x1F01, 0x0300}, - { 0x1F05, 0x1F01, 0x0301}, - { 0x1F07, 0x1F01, 0x0342}, - { 0x1F81, 0x1F01, 0x0345}, - { 0x1F82, 0x1F02, 0x0345}, - { 0x1F83, 0x1F03, 0x0345}, - { 0x1F84, 0x1F04, 0x0345}, - { 0x1F85, 0x1F05, 0x0345}, - { 0x1F86, 0x1F06, 0x0345}, - { 0x1F87, 0x1F07, 0x0345}, - { 0x1F0A, 0x1F08, 0x0300}, - { 0x1F0C, 0x1F08, 0x0301}, - { 0x1F0E, 0x1F08, 0x0342}, - { 0x1F88, 0x1F08, 0x0345}, - { 0x1F0B, 0x1F09, 0x0300}, - { 0x1F0D, 0x1F09, 0x0301}, - { 0x1F0F, 0x1F09, 0x0342}, - { 0x1F89, 0x1F09, 0x0345}, - { 0x1F8A, 0x1F0A, 0x0345}, - { 0x1F8B, 0x1F0B, 0x0345}, - { 0x1F8C, 0x1F0C, 0x0345}, - { 0x1F8D, 0x1F0D, 0x0345}, - { 0x1F8E, 0x1F0E, 0x0345}, - { 0x1F8F, 0x1F0F, 0x0345}, - { 0x1F12, 0x1F10, 0x0300}, - { 0x1F14, 0x1F10, 0x0301}, - { 0x1F13, 0x1F11, 0x0300}, - { 0x1F15, 0x1F11, 0x0301}, - { 0x1F1A, 0x1F18, 0x0300}, - { 0x1F1C, 0x1F18, 0x0301}, - { 0x1F1B, 0x1F19, 0x0300}, - { 0x1F1D, 0x1F19, 0x0301}, - { 0x1F22, 0x1F20, 0x0300}, - { 0x1F24, 0x1F20, 0x0301}, - { 0x1F26, 0x1F20, 0x0342}, - { 0x1F90, 0x1F20, 0x0345}, - { 0x1F23, 0x1F21, 0x0300}, - { 0x1F25, 0x1F21, 0x0301}, - { 0x1F27, 0x1F21, 0x0342}, - { 0x1F91, 0x1F21, 0x0345}, - { 0x1F92, 0x1F22, 0x0345}, - { 0x1F93, 0x1F23, 0x0345}, - { 0x1F94, 0x1F24, 0x0345}, - { 0x1F95, 0x1F25, 0x0345}, - { 0x1F96, 0x1F26, 0x0345}, - { 0x1F97, 0x1F27, 0x0345}, - { 0x1F2A, 0x1F28, 0x0300}, - { 0x1F2C, 0x1F28, 0x0301}, - { 0x1F2E, 0x1F28, 0x0342}, - { 0x1F98, 0x1F28, 0x0345}, - { 0x1F2B, 0x1F29, 0x0300}, - { 0x1F2D, 0x1F29, 0x0301}, - { 0x1F2F, 0x1F29, 0x0342}, - { 0x1F99, 0x1F29, 0x0345}, - { 0x1F9A, 0x1F2A, 0x0345}, - { 0x1F9B, 0x1F2B, 0x0345}, - { 0x1F9C, 0x1F2C, 0x0345}, - { 0x1F9D, 0x1F2D, 0x0345}, - { 0x1F9E, 0x1F2E, 0x0345}, - { 0x1F9F, 0x1F2F, 0x0345}, - { 0x1F32, 0x1F30, 0x0300}, - { 0x1F34, 0x1F30, 0x0301}, - { 0x1F36, 0x1F30, 0x0342}, - { 0x1F33, 0x1F31, 0x0300}, - { 0x1F35, 0x1F31, 0x0301}, - { 0x1F37, 0x1F31, 0x0342}, - { 0x1F3A, 0x1F38, 0x0300}, - { 0x1F3C, 0x1F38, 0x0301}, - { 0x1F3E, 0x1F38, 0x0342}, - { 0x1F3B, 0x1F39, 0x0300}, - { 0x1F3D, 0x1F39, 0x0301}, - { 0x1F3F, 0x1F39, 0x0342}, - { 0x1F42, 0x1F40, 0x0300}, - { 0x1F44, 0x1F40, 0x0301}, - { 0x1F43, 0x1F41, 0x0300}, - { 0x1F45, 0x1F41, 0x0301}, - { 0x1F4A, 0x1F48, 0x0300}, - { 0x1F4C, 0x1F48, 0x0301}, - { 0x1F4B, 0x1F49, 0x0300}, - { 0x1F4D, 0x1F49, 0x0301}, - { 0x1F52, 0x1F50, 0x0300}, - { 0x1F54, 0x1F50, 0x0301}, - { 0x1F56, 0x1F50, 0x0342}, - { 0x1F53, 0x1F51, 0x0300}, - { 0x1F55, 0x1F51, 0x0301}, - { 0x1F57, 0x1F51, 0x0342}, - { 0x1F5B, 0x1F59, 0x0300}, - { 0x1F5D, 0x1F59, 0x0301}, - { 0x1F5F, 0x1F59, 0x0342}, - { 0x1F62, 0x1F60, 0x0300}, - { 0x1F64, 0x1F60, 0x0301}, - { 0x1F66, 0x1F60, 0x0342}, - { 0x1FA0, 0x1F60, 0x0345}, - { 0x1F63, 0x1F61, 0x0300}, - { 0x1F65, 0x1F61, 0x0301}, - { 0x1F67, 0x1F61, 0x0342}, - { 0x1FA1, 0x1F61, 0x0345}, - { 0x1FA2, 0x1F62, 0x0345}, - { 0x1FA3, 0x1F63, 0x0345}, - { 0x1FA4, 0x1F64, 0x0345}, - { 0x1FA5, 0x1F65, 0x0345}, - { 0x1FA6, 0x1F66, 0x0345}, - { 0x1FA7, 0x1F67, 0x0345}, - { 0x1F6A, 0x1F68, 0x0300}, - { 0x1F6C, 0x1F68, 0x0301}, - { 0x1F6E, 0x1F68, 0x0342}, - { 0x1FA8, 0x1F68, 0x0345}, - { 0x1F6B, 0x1F69, 0x0300}, - { 0x1F6D, 0x1F69, 0x0301}, - { 0x1F6F, 0x1F69, 0x0342}, - { 0x1FA9, 0x1F69, 0x0345}, - { 0x1FAA, 0x1F6A, 0x0345}, - { 0x1FAB, 0x1F6B, 0x0345}, - { 0x1FAC, 0x1F6C, 0x0345}, - { 0x1FAD, 0x1F6D, 0x0345}, - { 0x1FAE, 0x1F6E, 0x0345}, - { 0x1FAF, 0x1F6F, 0x0345}, - { 0x1FB2, 0x1F70, 0x0345}, - { 0x1FC2, 0x1F74, 0x0345}, - { 0x1FF2, 0x1F7C, 0x0345}, - { 0x1FB7, 0x1FB6, 0x0345}, - { 0x1FCD, 0x1FBF, 0x0300}, - { 0x1FCE, 0x1FBF, 0x0301}, - { 0x1FCF, 0x1FBF, 0x0342}, - { 0x1FC7, 0x1FC6, 0x0345}, - { 0x1FF7, 0x1FF6, 0x0345}, - { 0x1FDD, 0x1FFE, 0x0300}, - { 0x1FDE, 0x1FFE, 0x0301}, - { 0x1FDF, 0x1FFE, 0x0342}, - { 0x219A, 0x2190, 0x0338}, - { 0x219B, 0x2192, 0x0338}, - { 0x21AE, 0x2194, 0x0338}, - { 0x21CD, 0x21D0, 0x0338}, - { 0x21CF, 0x21D2, 0x0338}, - { 0x21CE, 0x21D4, 0x0338}, - { 0x2204, 0x2203, 0x0338}, - { 0x2209, 0x2208, 0x0338}, - { 0x220C, 0x220B, 0x0338}, - { 0x2224, 0x2223, 0x0338}, - { 0x2226, 0x2225, 0x0338}, - { 0x2241, 0x223C, 0x0338}, - { 0x2244, 0x2243, 0x0338}, - { 0x2247, 0x2245, 0x0338}, - { 0x2249, 0x2248, 0x0338}, - { 0x226D, 0x224D, 0x0338}, - { 0x2262, 0x2261, 0x0338}, - { 0x2270, 0x2264, 0x0338}, - { 0x2271, 0x2265, 0x0338}, - { 0x2274, 0x2272, 0x0338}, - { 0x2275, 0x2273, 0x0338}, - { 0x2278, 0x2276, 0x0338}, - { 0x2279, 0x2277, 0x0338}, - { 0x2280, 0x227A, 0x0338}, - { 0x2281, 0x227B, 0x0338}, - { 0x22E0, 0x227C, 0x0338}, - { 0x22E1, 0x227D, 0x0338}, - { 0x2284, 0x2282, 0x0338}, - { 0x2285, 0x2283, 0x0338}, - { 0x2288, 0x2286, 0x0338}, - { 0x2289, 0x2287, 0x0338}, - { 0x22E2, 0x2291, 0x0338}, - { 0x22E3, 0x2292, 0x0338}, - { 0x22AC, 0x22A2, 0x0338}, - { 0x22AD, 0x22A8, 0x0338}, - { 0x22AE, 0x22A9, 0x0338}, - { 0x22AF, 0x22AB, 0x0338}, - { 0x22EA, 0x22B2, 0x0338}, - { 0x22EB, 0x22B3, 0x0338}, - { 0x22EC, 0x22B4, 0x0338}, - { 0x22ED, 0x22B5, 0x0338}, - { 0x2ADC, 0x2ADD, 0x0338}, - { 0x3094, 0x3046, 0x3099}, - { 0x304C, 0x304B, 0x3099}, - { 0x304E, 0x304D, 0x3099}, - { 0x3050, 0x304F, 0x3099}, - { 0x3052, 0x3051, 0x3099}, - { 0x3054, 0x3053, 0x3099}, - { 0x3056, 0x3055, 0x3099}, - { 0x3058, 0x3057, 0x3099}, - { 0x305A, 0x3059, 0x3099}, - { 0x305C, 0x305B, 0x3099}, - { 0x305E, 0x305D, 0x3099}, - { 0x3060, 0x305F, 0x3099}, - { 0x3062, 0x3061, 0x3099}, - { 0x3065, 0x3064, 0x3099}, - { 0x3067, 0x3066, 0x3099}, - { 0x3069, 0x3068, 0x3099}, - { 0x3070, 0x306F, 0x3099}, - { 0x3071, 0x306F, 0x309A}, - { 0x3073, 0x3072, 0x3099}, - { 0x3074, 0x3072, 0x309A}, - { 0x3076, 0x3075, 0x3099}, - { 0x3077, 0x3075, 0x309A}, - { 0x3079, 0x3078, 0x3099}, - { 0x307A, 0x3078, 0x309A}, - { 0x307C, 0x307B, 0x3099}, - { 0x307D, 0x307B, 0x309A}, - { 0x309E, 0x309D, 0x3099}, - { 0x30F4, 0x30A6, 0x3099}, - { 0x30AC, 0x30AB, 0x3099}, - { 0x30AE, 0x30AD, 0x3099}, - { 0x30B0, 0x30AF, 0x3099}, - { 0x30B2, 0x30B1, 0x3099}, - { 0x30B4, 0x30B3, 0x3099}, - { 0x30B6, 0x30B5, 0x3099}, - { 0x30B8, 0x30B7, 0x3099}, - { 0x30BA, 0x30B9, 0x3099}, - { 0x30BC, 0x30BB, 0x3099}, - { 0x30BE, 0x30BD, 0x3099}, - { 0x30C0, 0x30BF, 0x3099}, - { 0x30C2, 0x30C1, 0x3099}, - { 0x30C5, 0x30C4, 0x3099}, - { 0x30C7, 0x30C6, 0x3099}, - { 0x30C9, 0x30C8, 0x3099}, - { 0x30D0, 0x30CF, 0x3099}, - { 0x30D1, 0x30CF, 0x309A}, - { 0x30D3, 0x30D2, 0x3099}, - { 0x30D4, 0x30D2, 0x309A}, - { 0x30D6, 0x30D5, 0x3099}, - { 0x30D7, 0x30D5, 0x309A}, - { 0x30D9, 0x30D8, 0x3099}, - { 0x30DA, 0x30D8, 0x309A}, - { 0x30DC, 0x30DB, 0x3099}, - { 0x30DD, 0x30DB, 0x309A}, - { 0x30F7, 0x30EF, 0x3099}, - { 0x30F8, 0x30F0, 0x3099}, - { 0x30F9, 0x30F1, 0x3099}, - { 0x30FA, 0x30F2, 0x3099}, - { 0x30FE, 0x30FD, 0x3099}, - { 0xFB2C, 0xFB49, 0x05C1}, - { 0xFB2D, 0xFB49, 0x05C2}, - }; - - private static final int UNICODE_SHIFT = 21; - - public static char precompose(char base, char comb) { - int min = 0; - int max = precompositions.length - 1; - int mid; - - long sought = base << UNICODE_SHIFT | comb; - long that; - - while (max >= min) { - mid = (min + max) / 2; - that = precompositions[mid][1] << UNICODE_SHIFT | precompositions[mid][2]; - if (that < sought) - min = mid + 1; - else if (that > sought) - max = mid - 1; - else - return precompositions[mid][0]; - } - - // No match; return character without combiner - return base; - } -} diff --git a/src/de/mud/terminal/VDUBuffer.java b/src/de/mud/terminal/VDUBuffer.java deleted file mode 100644 index 93e3ccf..0000000 --- a/src/de/mud/terminal/VDUBuffer.java +++ /dev/null @@ -1,854 +0,0 @@ -/* - * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform". - * - * (c) Matthias L. Jugel, Marcus Mei�ner 1996-2005. All Rights Reserved. - * - * Please visit http://javatelnet.org/ for updates and contact. - * - * --LICENSE NOTICE-- - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * --LICENSE NOTICE-- - * - */ - -package de.mud.terminal; - -import java.util.Arrays; - -/** - * Implementation of a Video Display Unit (VDU) buffer. This class contains - * all methods to manipulate the buffer that stores characters and their - * attributes as well as the regions displayed. - * - * @author Matthias L. Jugel, Marcus Meißner - * @version $Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $ - */ -public class VDUBuffer { - - /** The current version id tag */ - public final static String ID = "$Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $"; - - /** Enable debug messages. */ - public final static int debug = 0; - - public int height, width; /* rows and columns */ - public boolean[] update; /* contains the lines that need update */ - public char[][] charArray; /* contains the characters */ - public int[][] charAttributes; /* contains character attrs */ - public int bufSize; - public int maxBufSize; /* buffer sizes */ - public int screenBase; /* the actual screen start */ - public int windowBase; /* where the start displaying */ - public int scrollMarker; /* marks the last line inserted */ - - private int topMargin; /* top scroll margin */ - private int bottomMargin; /* bottom scroll margin */ - - // cursor variables - protected boolean showcursor = true; - protected int cursorX, cursorY; - - /** Scroll up when inserting a line. */ - public final static boolean SCROLL_UP = false; - /** Scroll down when inserting a line. */ - public final static boolean SCROLL_DOWN = true; - - /* Attributes bit-field usage: - * - * 8421 8421 8421 8421 8421 8421 8421 8421 - * |||| |||| |||| |||| |||| |||| |||| |||`- Bold - * |||| |||| |||| |||| |||| |||| |||| ||`-- Underline - * |||| |||| |||| |||| |||| |||| |||| |`--- Invert - * |||| |||| |||| |||| |||| |||| |||| `---- Low - * |||| |||| |||| |||| |||| |||| |||`------ Invisible - * |||| |||| |||| |||| ||`+-++++-+++------- Foreground Color - * |||| |||| |`++-++++-++------------------ Background Color - * |||| |||| `----------------------------- Fullwidth character - * `+++-++++------------------------------- Reserved for future use - */ - - /** Make character normal. */ - public final static int NORMAL = 0x00; - /** Make character bold. */ - public final static int BOLD = 0x01; - /** Underline character. */ - public final static int UNDERLINE = 0x02; - /** Invert character. */ - public final static int INVERT = 0x04; - /** Lower intensity character. */ - public final static int LOW = 0x08; - /** Invisible character. */ - public final static int INVISIBLE = 0x10; - /** Unicode full-width character (CJK, et al.) */ - public final static int FULLWIDTH = 0x8000000; - - /** how much to left shift the foreground color */ - public final static int COLOR_FG_SHIFT = 5; - /** how much to left shift the background color */ - public final static int COLOR_BG_SHIFT = 14; - /** color mask */ - public final static int COLOR = 0x7fffe0; /* 0000 0000 0111 1111 1111 1111 1110 0000 */ - /** foreground color mask */ - public final static int COLOR_FG = 0x3fe0; /* 0000 0000 0000 0000 0011 1111 1110 0000 */ - /** background color mask */ - public final static int COLOR_BG = 0x7fc000; /* 0000 0000 0111 1111 1100 0000 0000 0000 */ - - /** - * Create a new video display buffer with the passed width and height in - * characters. - * @param width the length of the character lines - * @param height the amount of lines on the screen - */ - public VDUBuffer(int width, int height) { - // set the display screen size - setScreenSize(width, height, false); - } - - /** - * Create a standard video display buffer with 80 columns and 24 lines. - */ - public VDUBuffer() { - this(80, 24); - } - - /** - * Put a character on the screen with normal font and outline. - * The character previously on that position will be overwritten. - * You need to call redraw() to update the screen. - * @param c x-coordinate (column) - * @param l y-coordinate (line) - * @param ch the character to show on the screen - * @see #insertChar - * @see #deleteChar - * @see #redraw - */ - public void putChar(int c, int l, char ch) { - putChar(c, l, ch, NORMAL); - } - - /** - * Put a character on the screen with specific font and outline. - * The character previously on that position will be overwritten. - * You need to call redraw() to update the screen. - * @param c x-coordinate (column) - * @param l y-coordinate (line) - * @param ch the character to show on the screen - * @param attributes the character attributes - * @see #BOLD - * @see #UNDERLINE - * @see #INVERT - * @see #INVISIBLE - * @see #NORMAL - * @see #LOW - * @see #insertChar - * @see #deleteChar - * @see #redraw - */ - - public void putChar(int c, int l, char ch, int attributes) { - charArray[screenBase + l][c] = ch; - charAttributes[screenBase + l][c] = attributes; - if (l < height) - update[l + 1] = true; - } - - /** - * Get the character at the specified position. - * @param c x-coordinate (column) - * @param l y-coordinate (line) - * @see #putChar - */ - public char getChar(int c, int l) { - return charArray[screenBase + l][c]; - } - - /** - * Get the attributes for the specified position. - * @param c x-coordinate (column) - * @param l y-coordinate (line) - * @see #putChar - */ - public int getAttributes(int c, int l) { - return charAttributes[screenBase + l][c]; - } - - /** - * Insert a character at a specific position on the screen. - * All character right to from this position will be moved one to the right. - * You need to call redraw() to update the screen. - * @param c x-coordinate (column) - * @param l y-coordinate (line) - * @param ch the character to insert - * @param attributes the character attributes - * @see #BOLD - * @see #UNDERLINE - * @see #INVERT - * @see #INVISIBLE - * @see #NORMAL - * @see #LOW - * @see #putChar - * @see #deleteChar - * @see #redraw - */ - public void insertChar(int c, int l, char ch, int attributes) { - System.arraycopy(charArray[screenBase + l], c, - charArray[screenBase + l], c + 1, width - c - 1); - System.arraycopy(charAttributes[screenBase + l], c, - charAttributes[screenBase + l], c + 1, width - c - 1); - putChar(c, l, ch, attributes); - } - - /** - * Delete a character at a given position on the screen. - * All characters right to the position will be moved one to the left. - * You need to call redraw() to update the screen. - * @param c x-coordinate (column) - * @param l y-coordinate (line) - * @see #putChar - * @see #insertChar - * @see #redraw - */ - public void deleteChar(int c, int l) { - if (c < width - 1) { - System.arraycopy(charArray[screenBase + l], c + 1, - charArray[screenBase + l], c, width - c - 1); - System.arraycopy(charAttributes[screenBase + l], c + 1, - charAttributes[screenBase + l], c, width - c - 1); - } - putChar(width - 1, l, (char) 0); - } - - /** - * Put a String at a specific position. Any characters previously on that - * position will be overwritten. You need to call redraw() for screen update. - * @param c x-coordinate (column) - * @param l y-coordinate (line) - * @param s the string to be shown on the screen - * @see #BOLD - * @see #UNDERLINE - * @see #INVERT - * @see #INVISIBLE - * @see #NORMAL - * @see #LOW - * @see #putChar - * @see #insertLine - * @see #deleteLine - * @see #redraw - */ - public void putString(int c, int l, String s) { - putString(c, l, s, NORMAL); - } - - /** - * Put a String at a specific position giving all characters the same - * attributes. Any characters previously on that position will be - * overwritten. You need to call redraw() to update the screen. - * @param c x-coordinate (column) - * @param l y-coordinate (line) - * @param s the string to be shown on the screen - * @param attributes character attributes - * @see #BOLD - * @see #UNDERLINE - * @see #INVERT - * @see #INVISIBLE - * @see #NORMAL - * @see #LOW - * @see #putChar - * @see #insertLine - * @see #deleteLine - * @see #redraw - */ - public void putString(int c, int l, String s, int attributes) { - for (int i = 0; i < s.length() && c + i < width; i++) - putChar(c + i, l, s.charAt(i), attributes); - } - - /** - * Insert a blank line at a specific position. - * The current line and all previous lines are scrolled one line up. The - * top line is lost. You need to call redraw() to update the screen. - * @param l the y-coordinate to insert the line - * @see #deleteLine - * @see #redraw - */ - public void insertLine(int l) { - insertLine(l, 1, SCROLL_UP); - } - - /** - * Insert blank lines at a specific position. - * You need to call redraw() to update the screen - * @param l the y-coordinate to insert the line - * @param n amount of lines to be inserted - * @see #deleteLine - * @see #redraw - */ - public void insertLine(int l, int n) { - insertLine(l, n, SCROLL_UP); - } - - /** - * Insert a blank line at a specific position. Scroll text according to - * the argument. - * You need to call redraw() to update the screen - * @param l the y-coordinate to insert the line - * @param scrollDown scroll down - * @see #deleteLine - * @see #SCROLL_UP - * @see #SCROLL_DOWN - * @see #redraw - */ - public void insertLine(int l, boolean scrollDown) { - insertLine(l, 1, scrollDown); - } - - /** - * Insert blank lines at a specific position. - * The current line and all previous lines are scrolled one line up. The - * top line is lost. You need to call redraw() to update the screen. - * @param l the y-coordinate to insert the line - * @param n number of lines to be inserted - * @param scrollDown scroll down - * @see #deleteLine - * @see #SCROLL_UP - * @see #SCROLL_DOWN - * @see #redraw - */ - public synchronized void insertLine(int l, int n, boolean scrollDown) { - char cbuf[][] = null; - int abuf[][] = null; - int offset = 0; - int oldBase = screenBase; - - int newScreenBase = screenBase; - int newWindowBase = windowBase; - int newBufSize = bufSize; - - if (l > bottomMargin) /* We do not scroll below bottom margin (below the scrolling region). */ - return; - int top = (l < topMargin ? - 0 : (l > bottomMargin ? - (bottomMargin + 1 < height ? - bottomMargin + 1 : height - 1) : topMargin)); - int bottom = (l > bottomMargin ? - height - 1 : (l < topMargin ? - (topMargin > 0 ? - topMargin - 1 : 0) : bottomMargin)); - - // System.out.println("l is "+l+", top is "+top+", bottom is "+bottom+", bottomargin is "+bottomMargin+", topMargin is "+topMargin); - - if (scrollDown) { - if (n > (bottom - top)) n = (bottom - top); - int size = bottom - l - (n - 1); - if(size < 0) size = 0; - cbuf = new char[size][]; - abuf = new int[size][]; - - System.arraycopy(charArray, oldBase + l, cbuf, 0, bottom - l - (n - 1)); - System.arraycopy(charAttributes, oldBase + l, - abuf, 0, bottom - l - (n - 1)); - System.arraycopy(cbuf, 0, charArray, oldBase + l + n, - bottom - l - (n - 1)); - System.arraycopy(abuf, 0, charAttributes, oldBase + l + n, - bottom - l - (n - 1)); - cbuf = charArray; - abuf = charAttributes; - } else { - try { - if (n > (bottom - top) + 1) n = (bottom - top) + 1; - if (bufSize < maxBufSize) { - if (bufSize + n > maxBufSize) { - offset = n - (maxBufSize - bufSize); - scrollMarker += offset; - newBufSize = maxBufSize; - newScreenBase = maxBufSize - height - 1; - newWindowBase = screenBase; - } else { - scrollMarker += n; - newScreenBase += n; - newWindowBase += n; - newBufSize += n; - } - - cbuf = new char[newBufSize][]; - abuf = new int[newBufSize][]; - } else { - offset = n; - cbuf = charArray; - abuf = charAttributes; - } - // copy anything from the top of the buffer (+offset) to the new top - // up to the screenBase. - if (oldBase > 0) { - System.arraycopy(charArray, offset, - cbuf, 0, - oldBase - offset); - System.arraycopy(charAttributes, offset, - abuf, 0, - oldBase - offset); - } - // copy anything from the top of the screen (screenBase) up to the - // topMargin to the new screen - if (top > 0) { - System.arraycopy(charArray, oldBase, - cbuf, newScreenBase, - top); - System.arraycopy(charAttributes, oldBase, - abuf, newScreenBase, - top); - } - // copy anything from the topMargin up to the amount of lines inserted - // to the gap left over between scrollback buffer and screenBase - if (oldBase >= 0) { - System.arraycopy(charArray, oldBase + top, - cbuf, oldBase - offset, - n); - System.arraycopy(charAttributes, oldBase + top, - abuf, oldBase - offset, - n); - } - // copy anything from topMargin + n up to the line linserted to the - // topMargin - System.arraycopy(charArray, oldBase + top + n, - cbuf, newScreenBase + top, - l - top - (n - 1)); - System.arraycopy(charAttributes, oldBase + top + n, - abuf, newScreenBase + top, - l - top - (n - 1)); - // - // copy the all lines next to the inserted to the new buffer - if (l < height - 1) { - System.arraycopy(charArray, oldBase + l + 1, - cbuf, newScreenBase + l + 1, - (height - 1) - l); - System.arraycopy(charAttributes, oldBase + l + 1, - abuf, newScreenBase + l + 1, - (height - 1) - l); - } - } catch (ArrayIndexOutOfBoundsException e) { - // this should not happen anymore, but I will leave the code - // here in case something happens anyway. That code above is - // so complex I always have a hard time understanding what - // I did, even though there are comments - System.err.println("*** Error while scrolling up:"); - System.err.println("--- BEGIN STACK TRACE ---"); - e.printStackTrace(); - System.err.println("--- END STACK TRACE ---"); - System.err.println("bufSize=" + bufSize + ", maxBufSize=" + maxBufSize); - System.err.println("top=" + top + ", bottom=" + bottom); - System.err.println("n=" + n + ", l=" + l); - System.err.println("screenBase=" + screenBase + ", windowBase=" + windowBase); - System.err.println("newScreenBase=" + newScreenBase + ", newWindowBase=" + newWindowBase); - System.err.println("oldBase=" + oldBase); - System.err.println("size.width=" + width + ", size.height=" + height); - System.err.println("abuf.length=" + abuf.length + ", cbuf.length=" + cbuf.length); - System.err.println("*** done dumping debug information"); - } - } - - // this is a little helper to mark the scrolling - scrollMarker -= n; - - - for (int i = 0; i < n; i++) { - cbuf[(newScreenBase + l) + (scrollDown ? i : -i)] = new char[width]; - Arrays.fill(cbuf[(newScreenBase + l) + (scrollDown ? i : -i)], ' '); - abuf[(newScreenBase + l) + (scrollDown ? i : -i)] = new int[width]; - } - - charArray = cbuf; - charAttributes = abuf; - screenBase = newScreenBase; - windowBase = newWindowBase; - bufSize = newBufSize; - - if (scrollDown) - markLine(l, bottom - l + 1); - else - markLine(top, l - top + 1); - - display.updateScrollBar(); - } - - /** - * Delete a line at a specific position. Subsequent lines will be scrolled - * up to fill the space and a blank line is inserted at the end of the - * screen. - * @param l the y-coordinate to insert the line - * @see #deleteLine - */ - public void deleteLine(int l) { - int bottom = (l > bottomMargin ? height - 1: - (l < topMargin?topMargin:bottomMargin + 1)); - int numRows = bottom - l - 1; - - char[] discardedChars = charArray[screenBase + l]; - int[] discardedAttributes = charAttributes[screenBase + l]; - - if (numRows > 0) { - System.arraycopy(charArray, screenBase + l + 1, - charArray, screenBase + l, numRows); - System.arraycopy(charAttributes, screenBase + l + 1, - charAttributes, screenBase + l, numRows); - } - - int newBottomRow = screenBase + bottom - 1; - charArray[newBottomRow] = discardedChars; - charAttributes[newBottomRow] = discardedAttributes; - Arrays.fill(charArray[newBottomRow], ' '); - Arrays.fill(charAttributes[newBottomRow], 0); - - markLine(l, bottom - l); - } - - /** - * Delete a rectangular portion of the screen. - * You need to call redraw() to update the screen. - * @param c x-coordinate (column) - * @param l y-coordinate (row) - * @param w with of the area in characters - * @param h height of the area in characters - * @param curAttr attribute to fill - * @see #deleteChar - * @see #deleteLine - * @see #redraw - */ - public void deleteArea(int c, int l, int w, int h, int curAttr) { - int endColumn = c + w; - int targetRow = screenBase + l; - for (int i = 0; i < h && l + i < height; i++) { - Arrays.fill(charAttributes[targetRow], c, endColumn, curAttr); - Arrays.fill(charArray[targetRow], c, endColumn, ' '); - targetRow++; - } - markLine(l, h); - } - - /** - * Delete a rectangular portion of the screen. - * You need to call redraw() to update the screen. - * @param c x-coordinate (column) - * @param l y-coordinate (row) - * @param w with of the area in characters - * @param h height of the area in characters - * @see #deleteChar - * @see #deleteLine - * @see #redraw - */ - public void deleteArea(int c, int l, int w, int h) { - deleteArea(c, l, w, h, 0); - } - - /** - * Sets whether the cursor is visible or not. - * @param doshow - */ - public void showCursor(boolean doshow) { - showcursor = doshow; - } - - /** - * Check whether the cursor is currently visible. - * @return visibility - */ - public boolean isCursorVisible() { - return showcursor; - } - - /** - * Puts the cursor at the specified position. - * @param c column - * @param l line - */ - public void setCursorPosition(int c, int l) { - cursorX = c; - cursorY = l; - } - - /** - * Get the current column of the cursor position. - */ - public int getCursorColumn() { - return cursorX; - } - - /** - * Get the current line of the cursor position. - */ - public int getCursorRow() { - return cursorY; - } - - /** - * Set the current window base. This allows to view the scrollback buffer. - * @param line the line where the screen window starts - * @see #setBufferSize - * @see #getBufferSize - */ - public void setWindowBase(int line) { - if (line > screenBase) - line = screenBase; - else if (line < 0) line = 0; - windowBase = line; - update[0] = true; - redraw(); - } - - /** - * Get the current window base. - * @see #setWindowBase - */ - public int getWindowBase() { - return windowBase; - } - - /** - * Set the scroll margins simultaneously. If they're out of bounds, trim them. - * @param l1 line that is the top - * @param l2 line that is the bottom - */ - public void setMargins(int l1, int l2) { - if (l1 > l2) - return; - - if (l1 < 0) - l1 = 0; - if (l2 >= height) - l2 = height - 1; - - topMargin = l1; - bottomMargin = l2; - } - - /** - * Set the top scroll margin for the screen. If the current bottom margin - * is smaller it will become the top margin and the line will become the - * bottom margin. - * @param l line that is the margin - */ - public void setTopMargin(int l) { - if (l > bottomMargin) { - topMargin = bottomMargin; - bottomMargin = l; - } else - topMargin = l; - if (topMargin < 0) topMargin = 0; - if (bottomMargin >= height) bottomMargin = height - 1; - } - - /** - * Get the top scroll margin. - */ - public int getTopMargin() { - return topMargin; - } - - /** - * Set the bottom scroll margin for the screen. If the current top margin - * is bigger it will become the bottom margin and the line will become the - * top margin. - * @param l line that is the margin - */ - public void setBottomMargin(int l) { - if (l < topMargin) { - bottomMargin = topMargin; - topMargin = l; - } else - bottomMargin = l; - if (topMargin < 0) topMargin = 0; - if (bottomMargin >= height) bottomMargin = height - 1; - } - - /** - * Get the bottom scroll margin. - */ - public int getBottomMargin() { - return bottomMargin; - } - - /** - * Set scrollback buffer size. - * @param amount new size of the buffer - */ - public void setBufferSize(int amount) { - if (amount < height) amount = height; - if (amount < maxBufSize) { - char cbuf[][] = new char[amount][width]; - int abuf[][] = new int[amount][width]; - int copyStart = bufSize - amount < 0 ? 0 : bufSize - amount; - int copyCount = bufSize - amount < 0 ? bufSize : amount; - if (charArray != null) - System.arraycopy(charArray, copyStart, cbuf, 0, copyCount); - if (charAttributes != null) - System.arraycopy(charAttributes, copyStart, abuf, 0, copyCount); - charArray = cbuf; - charAttributes = abuf; - bufSize = copyCount; - screenBase = bufSize - height; - windowBase = screenBase; - } - maxBufSize = amount; - - update[0] = true; - redraw(); - } - - /** - * Retrieve current scrollback buffer size. - * @see #setBufferSize - */ - public int getBufferSize() { - return bufSize; - } - - /** - * Retrieve maximum buffer Size. - * @see #getBufferSize - */ - public int getMaxBufferSize() { - return maxBufSize; - } - - /** - * Change the size of the screen. This will include adjustment of the - * scrollback buffer. - * @param w of the screen - * @param h of the screen - */ - public void setScreenSize(int w, int h, boolean broadcast) { - char cbuf[][]; - int abuf[][]; - int maxSize = bufSize; - - if (w < 1 || h < 1) return; - - if (debug > 0) - System.err.println("VDU: screen size [" + w + "," + h + "]"); - - if (h > maxBufSize) - maxBufSize = h; - - if (h > bufSize) { - bufSize = h; - screenBase = 0; - windowBase = 0; - } - - if (windowBase + h >= bufSize) - windowBase = bufSize - h; - - if (screenBase + h >= bufSize) - screenBase = bufSize - h; - - - cbuf = new char[bufSize][w]; - abuf = new int[bufSize][w]; - - - for (int i = 0; i < bufSize; i++) { - Arrays.fill(cbuf[i], ' '); - } - - if (bufSize < maxSize) - maxSize = bufSize; - - int rowLength; - if (charArray != null && charAttributes != null) { - for (int i = 0; i < maxSize && charArray[i] != null; i++) { - rowLength = charArray[i].length; - System.arraycopy(charArray[i], 0, cbuf[i], 0, - w < rowLength ? w : rowLength); - System.arraycopy(charAttributes[i], 0, abuf[i], 0, - w < rowLength ? w : rowLength); - } - } - - int C = getCursorColumn(); - if (C < 0) - C = 0; - else if (C >= width) - C = width - 1; - - int R = getCursorRow(); - if (R < 0) - R = 0; - else if (R >= height) - R = height - 1; - - setCursorPosition(C, R); - - charArray = cbuf; - charAttributes = abuf; - width = w; - height = h; - topMargin = 0; - bottomMargin = h - 1; - update = new boolean[h + 1]; - update[0] = true; - /* FIXME: ??? - if(resizeStrategy == RESIZE_FONT) - setBounds(getBounds()); - */ - } - - /** - * Get amount of rows on the screen. - */ - public int getRows() { - return height; - } - - /** - * Get amount of columns on the screen. - */ - public int getColumns() { - return width; - } - - /** - * Mark lines to be updated with redraw(). - * @param l starting line - * @param n amount of lines to be updated - * @see #redraw - */ - public void markLine(int l, int n) { - for (int i = 0; (i < n) && (l + i < height); i++) - update[l + i + 1] = true; - } - -// private static int checkBounds(int value, int lower, int upper) { -// if (value < lower) -// return lower; -// else if (value > upper) -// return upper; -// else -// return value; -// } - - /** a generic display that should redraw on demand */ - protected VDUDisplay display; - - public void setDisplay(VDUDisplay display) { - this.display = display; - } - - /** - * Trigger a redraw on the display. - */ - protected void redraw() { - if (display != null) - display.redraw(); - } -} diff --git a/src/de/mud/terminal/VDUDisplay.java b/src/de/mud/terminal/VDUDisplay.java deleted file mode 100644 index bb4a7b8..0000000 --- a/src/de/mud/terminal/VDUDisplay.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform". - * - * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved. - * - * Please visit http://javatelnet.org/ for updates and contact. - * - * --LICENSE NOTICE-- - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * --LICENSE NOTICE-- - * - */ - -package de.mud.terminal; - -/** - * Generic display - */ -public interface VDUDisplay { - public void redraw(); - public void updateScrollBar(); - - public void setVDUBuffer(VDUBuffer buffer); - public VDUBuffer getVDUBuffer(); - - public void setColor(int index, int red, int green, int blue); - public void resetColors(); -} diff --git a/src/de/mud/terminal/VDUInput.java b/src/de/mud/terminal/VDUInput.java deleted file mode 100644 index 43c88de..0000000 --- a/src/de/mud/terminal/VDUInput.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform". - * - * (c) Matthias L. Jugel, Marcus Meißner 1996-2005. All Rights Reserved. - * - * Please visit http://javatelnet.org/ for updates and contact. - * - * --LICENSE NOTICE-- - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * --LICENSE NOTICE-- - * - */ -package de.mud.terminal; - -import java.util.Properties; - -/** - * An interface for a terminal that accepts input from keyboard and mouse. - * - * @author Matthias L. Jugel, Marcus Meißner - * @version $Id: VDUInput.java 499 2005-09-29 08:24:54Z leo $ - */ -public interface VDUInput { - - public final static int KEY_CONTROL = 0x01; - public final static int KEY_SHIFT = 0x02; - public final static int KEY_ALT = 0x04; - public final static int KEY_ACTION = 0x08; - - - - /** - * Direct access to writing data ... - * @param b - */ - void write(byte b[]); - - /** - * Terminal is mouse-aware and requires (x,y) coordinates of - * on the terminal (character coordinates) and the button clicked. - * @param x - * @param y - * @param modifiers - */ - void mousePressed(int x, int y, int modifiers); - - /** - * Terminal is mouse-aware and requires the coordinates and button - * of the release. - * @param x - * @param y - * @param modifiers - */ - void mouseReleased(int x, int y, int modifiers); - - /** - * Override the standard key codes used by the terminal emulation. - * @param codes a properties object containing key code definitions - */ - void setKeyCodes(Properties codes); - - /** - * main keytyping event handler... - * @param keyCode the key code - * @param keyChar the character represented by the key - * @param modifiers shift/alt/control modifiers - */ - void keyPressed(int keyCode, char keyChar, int modifiers); - - /** - * Handle key Typed events for the terminal, this will get - * all normal key types, but no shift/alt/control/numlock. - * @param keyCode the key code - * @param keyChar the character represented by the key - * @param modifiers shift/alt/control modifiers - */ - void keyTyped(int keyCode, char keyChar, int modifiers); -} diff --git a/src/de/mud/terminal/vt320.java b/src/de/mud/terminal/vt320.java deleted file mode 100644 index 73369af..0000000 --- a/src/de/mud/terminal/vt320.java +++ /dev/null @@ -1,3032 +0,0 @@ -/* - * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform". - * - * (c) Matthias L. Jugel, Marcus Meiner 1996-2005. All Rights Reserved. - * - * Please visit http://javatelnet.org/ for updates and contact. - * - * --LICENSE NOTICE-- - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * --LICENSE NOTICE-- - * - */ - -package de.mud.terminal; - -import android.text.AndroidCharacter; - -import java.util.Properties; - -/** - * Implementation of a VT terminal emulation plus ANSI compatible. - * <P> - * <B>Maintainer:</B> Marcus Meißner - * - * @version $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $ - * @author Matthias L. Jugel, Marcus Meißner - */ -public abstract class vt320 extends VDUBuffer implements VDUInput { - - /** The current version id tag.<P> - * $Id: vt320.java 507 2005-10-25 10:14:52Z marcus $ - * - */ - public final static String ID = "$Id: vt320.java 507 2005-10-25 10:14:52Z marcus $"; - - /** the debug level */ - private final static int debug = 0; - private StringBuilder debugStr; - public abstract void debug(String notice); - - /** - * Write an answer back to the remote host. This is needed to be able to - * send terminal answers requests like status and type information. - * @param b the array of bytes to be sent - */ - public abstract void write(byte[] b); - - /** - * Write an answer back to the remote host. This is needed to be able to - * send terminal answers requests like status and type information. - * @param b the array of bytes to be sent - */ - public abstract void write(int b); - - /** - * Play the beep sound ... - */ - public void beep() { /* do nothing by default */ - } - - /** - * Convenience function for putString(char[], int, int) - */ - public void putString(String s) { - int len = s.length(); - char[] tmp = new char[len]; - s.getChars(0, len, tmp, 0); - putString(tmp, null, 0, len); - } - - /** - * Put string at current cursor position. Moves cursor - * according to the String. Does NOT wrap. - * @param s character array - * @param start place to start in array - * @param len number of characters to process - */ - public void putString(char[] s, byte[] fullwidths, int start, int len) { - if (len > 0) { - //markLine(R, 1); - int lastChar = -1; - char c; - boolean isWide = false; - - for (int i = 0; i < len; i++) { - c = s[start + i]; - // Shortcut for my favorite ASCII - if (c <= 0x7F) { - if (lastChar != -1) - putChar((char) lastChar, isWide, false); - lastChar = c; - isWide = false; - } else if (!Character.isLowSurrogate(c) && !Character.isHighSurrogate(c)) { - if (Character.getType(c) == Character.NON_SPACING_MARK) { - if (lastChar != -1) { - char nc = Precomposer.precompose((char) lastChar, c); - putChar(nc, isWide, false); - lastChar = -1; - } - } else { - if (lastChar != -1) - putChar((char) lastChar, isWide, false); - lastChar = c; - if (fullwidths != null) { - final byte width = fullwidths[i]; - isWide = (width == AndroidCharacter.EAST_ASIAN_WIDTH_WIDE) - || (width == AndroidCharacter.EAST_ASIAN_WIDTH_FULL_WIDTH); - } - } - } - } - - if (lastChar != -1) - putChar((char) lastChar, isWide, false); - - setCursorPosition(C, R); - redraw(); - } - } - - protected void sendTelnetCommand(byte cmd) { - - } - - /** - * Sent the changed window size from the terminal to all listeners. - */ - protected void setWindowSize(int c, int r) { - /* To be overridden by Terminal.java */ - } - - @Override -public void setScreenSize(int c, int r, boolean broadcast) { - int oldrows = height; - - if (debug>2) { - if (debugStr == null) - debugStr = new StringBuilder(); - - debugStr.append("setscreensize (") - .append(c) - .append(',') - .append(r) - .append(',') - .append(broadcast) - .append(')'); - debug(debugStr.toString()); - debugStr.setLength(0); - } - - super.setScreenSize(c,r,false); - - boolean cursorChanged = false; - - // Don't let the cursor go off the screen. - if (C >= c) { - C = c - 1; - cursorChanged = true; - } - - if (R >= r) { - R = r - 1; - cursorChanged = true; - } - - if (cursorChanged) { - setCursorPosition(C, R); - redraw(); - } - - if (broadcast) { - setWindowSize(c, r); /* broadcast up */ - } - } - - - /** - * Create a new vt320 terminal and intialize it with useful settings. - */ - public vt320(int width, int height) { - super(width, height); - - debugStr = new StringBuilder(); - - setVMS(false); - setIBMCharset(false); - setTerminalID("vt320"); - setBufferSize(100); - //setBorder(2, false); - - gx = new char[4]; - reset(); - - /* top row of numpad */ - PF1 = "\u001bOP"; - PF2 = "\u001bOQ"; - PF3 = "\u001bOR"; - PF4 = "\u001bOS"; - - /* the 3x2 keyblock on PC keyboards */ - Insert = new String[4]; - Remove = new String[4]; - KeyHome = new String[4]; - KeyEnd = new String[4]; - NextScn = new String[4]; - PrevScn = new String[4]; - Escape = new String[4]; - BackSpace = new String[4]; - TabKey = new String[4]; - Insert[0] = Insert[1] = Insert[2] = Insert[3] = "\u001b[2~"; - Remove[0] = Remove[1] = Remove[2] = Remove[3] = "\u001b[3~"; - PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[5~"; - NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[6~"; - KeyHome[0] = KeyHome[1] = KeyHome[2] = KeyHome[3] = "\u001b[H"; - KeyEnd[0] = KeyEnd[1] = KeyEnd[2] = KeyEnd[3] = "\u001b[F"; - Escape[0] = Escape[1] = Escape[2] = Escape[3] = "\u001b"; - if (vms) { - BackSpace[1] = "" + (char) 10; // VMS shift deletes word back - BackSpace[2] = "\u0018"; // VMS control deletes line back - BackSpace[0] = BackSpace[3] = "\u007f"; // VMS other is delete - } else { - //BackSpace[0] = BackSpace[1] = BackSpace[2] = BackSpace[3] = "\b"; - // ConnectBot modifications. - BackSpace[0] = "\b"; - BackSpace[1] = "\u007f"; - BackSpace[2] = "\u001b[3~"; - BackSpace[3] = "\u001b[2~"; - } - - /* some more VT100 keys */ - Find = "\u001b[1~"; - Select = "\u001b[4~"; - Help = "\u001b[28~"; - Do = "\u001b[29~"; - - FunctionKey = new String[21]; - FunctionKey[0] = ""; - FunctionKey[1] = PF1; - FunctionKey[2] = PF2; - FunctionKey[3] = PF3; - FunctionKey[4] = PF4; - /* following are defined differently for vt220 / vt132 ... */ - FunctionKey[5] = "\u001b[15~"; - FunctionKey[6] = "\u001b[17~"; - FunctionKey[7] = "\u001b[18~"; - FunctionKey[8] = "\u001b[19~"; - FunctionKey[9] = "\u001b[20~"; - FunctionKey[10] = "\u001b[21~"; - FunctionKey[11] = "\u001b[23~"; - FunctionKey[12] = "\u001b[24~"; - FunctionKey[13] = "\u001b[25~"; - FunctionKey[14] = "\u001b[26~"; - FunctionKey[15] = Help; - FunctionKey[16] = Do; - FunctionKey[17] = "\u001b[31~"; - FunctionKey[18] = "\u001b[32~"; - FunctionKey[19] = "\u001b[33~"; - FunctionKey[20] = "\u001b[34~"; - - FunctionKeyShift = new String[21]; - FunctionKeyAlt = new String[21]; - FunctionKeyCtrl = new String[21]; - - for (int i = 0; i < 20; i++) { - FunctionKeyShift[i] = ""; - FunctionKeyAlt[i] = ""; - FunctionKeyCtrl[i] = ""; - } - FunctionKeyShift[15] = Find; - FunctionKeyShift[16] = Select; - - - TabKey[0] = "\u0009"; - TabKey[1] = "\u001bOP\u0009"; - TabKey[2] = TabKey[3] = ""; - - KeyUp = new String[4]; - KeyUp[0] = "\u001b[A"; - KeyDown = new String[4]; - KeyDown[0] = "\u001b[B"; - KeyRight = new String[4]; - KeyRight[0] = "\u001b[C"; - KeyLeft = new String[4]; - KeyLeft[0] = "\u001b[D"; - Numpad = new String[10]; - Numpad[0] = "\u001bOp"; - Numpad[1] = "\u001bOq"; - Numpad[2] = "\u001bOr"; - Numpad[3] = "\u001bOs"; - Numpad[4] = "\u001bOt"; - Numpad[5] = "\u001bOu"; - Numpad[6] = "\u001bOv"; - Numpad[7] = "\u001bOw"; - Numpad[8] = "\u001bOx"; - Numpad[9] = "\u001bOy"; - KPMinus = PF4; - KPComma = "\u001bOl"; - KPPeriod = "\u001bOn"; - KPEnter = "\u001bOM"; - - NUMPlus = new String[4]; - NUMPlus[0] = "+"; - NUMDot = new String[4]; - NUMDot[0] = "."; - } - - public void setBackspace(int type) { - switch (type) { - case DELETE_IS_DEL: - BackSpace[0] = "\u007f"; - BackSpace[1] = "\b"; - break; - case DELETE_IS_BACKSPACE: - BackSpace[0] = "\b"; - BackSpace[1] = "\u007f"; - break; - } - } - - /** - * Create a default vt320 terminal with 80 columns and 24 lines. - */ - public vt320() { - this(80, 24); - } - - /** - * Terminal is mouse-aware and requires (x,y) coordinates of - * on the terminal (character coordinates) and the button clicked. - * @param x - * @param y - * @param modifiers - */ - public void mousePressed(int x, int y, int modifiers) { - if (mouserpt == 0) - return; - - int mods = modifiers; - mousebut = 3; - if ((mods & 16) == 16) mousebut = 0; - if ((mods & 8) == 8) mousebut = 1; - if ((mods & 4) == 4) mousebut = 2; - - int mousecode; - if (mouserpt == 9) /* X10 Mouse */ - mousecode = 0x20 | mousebut; - else /* normal xterm mouse reporting */ - mousecode = mousebut | 0x20 | ((mods & 7) << 2); - - byte b[] = new byte[6]; - - b[0] = 27; - b[1] = (byte) '['; - b[2] = (byte) 'M'; - b[3] = (byte) mousecode; - b[4] = (byte) (0x20 + x + 1); - b[5] = (byte) (0x20 + y + 1); - - write(b); // FIXME: writeSpecial here - } - - /** - * Terminal is mouse-aware and requires the coordinates and button - * of the release. - * @param x - * @param y - * @param modifiers - */ - public void mouseReleased(int x, int y, int modifiers) { - if (mouserpt == 0) - return; - - /* problem is tht modifiers still have the released button set in them. - int mods = modifiers; - mousebut = 3; - if ((mods & 16)==16) mousebut=0; - if ((mods & 8)==8 ) mousebut=1; - if ((mods & 4)==4 ) mousebut=2; - */ - - int mousecode; - if (mouserpt == 9) - mousecode = 0x20 + mousebut; /* same as press? appears so. */ - else - mousecode = '#'; - - byte b[] = new byte[6]; - b[0] = 27; - b[1] = (byte) '['; - b[2] = (byte) 'M'; - b[3] = (byte) mousecode; - b[4] = (byte) (0x20 + x + 1); - b[5] = (byte) (0x20 + y + 1); - write(b); // FIXME: writeSpecial here - mousebut = 0; - } - - - /** we should do localecho (passed from other modules). false is default */ - private boolean localecho = false; - - /** - * Enable or disable the local echo property of the terminal. - * @param echo true if the terminal should echo locally - */ - public void setLocalEcho(boolean echo) { - localecho = echo; - } - - /** - * Enable the VMS mode of the terminal to handle some things differently - * for VMS hosts. - * @param vms true for vms mode, false for normal mode - */ - public void setVMS(boolean vms) { - this.vms = vms; - } - - /** - * Enable the usage of the IBM character set used by some BBS's. Special - * graphical character are available in this mode. - * @param ibm true to use the ibm character set - */ - public void setIBMCharset(boolean ibm) { - useibmcharset = ibm; - } - - /** - * Override the standard key codes used by the terminal emulation. - * @param codes a properties object containing key code definitions - */ - public void setKeyCodes(Properties codes) { - String res, prefixes[] = {"", "S", "C", "A"}; - int i; - - for (i = 0; i < 10; i++) { - res = codes.getProperty("NUMPAD" + i); - if (res != null) Numpad[i] = unEscape(res); - } - for (i = 1; i < 20; i++) { - res = codes.getProperty("F" + i); - if (res != null) FunctionKey[i] = unEscape(res); - res = codes.getProperty("SF" + i); - if (res != null) FunctionKeyShift[i] = unEscape(res); - res = codes.getProperty("CF" + i); - if (res != null) FunctionKeyCtrl[i] = unEscape(res); - res = codes.getProperty("AF" + i); - if (res != null) FunctionKeyAlt[i] = unEscape(res); - } - for (i = 0; i < 4; i++) { - res = codes.getProperty(prefixes[i] + "PGUP"); - if (res != null) PrevScn[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "PGDOWN"); - if (res != null) NextScn[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "END"); - if (res != null) KeyEnd[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "HOME"); - if (res != null) KeyHome[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "INSERT"); - if (res != null) Insert[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "REMOVE"); - if (res != null) Remove[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "UP"); - if (res != null) KeyUp[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "DOWN"); - if (res != null) KeyDown[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "LEFT"); - if (res != null) KeyLeft[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "RIGHT"); - if (res != null) KeyRight[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "ESCAPE"); - if (res != null) Escape[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "BACKSPACE"); - if (res != null) BackSpace[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "TAB"); - if (res != null) TabKey[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "NUMPLUS"); - if (res != null) NUMPlus[i] = unEscape(res); - res = codes.getProperty(prefixes[i] + "NUMDECIMAL"); - if (res != null) NUMDot[i] = unEscape(res); - } - } - - /** - * Set the terminal id used to identify this terminal. - * @param terminalID the id string - */ - public void setTerminalID(String terminalID) { - this.terminalID = terminalID; - - if (terminalID.equals("scoansi")) { - FunctionKey[1] = "\u001b[M"; FunctionKey[2] = "\u001b[N"; - FunctionKey[3] = "\u001b[O"; FunctionKey[4] = "\u001b[P"; - FunctionKey[5] = "\u001b[Q"; FunctionKey[6] = "\u001b[R"; - FunctionKey[7] = "\u001b[S"; FunctionKey[8] = "\u001b[T"; - FunctionKey[9] = "\u001b[U"; FunctionKey[10] = "\u001b[V"; - FunctionKey[11] = "\u001b[W"; FunctionKey[12] = "\u001b[X"; - FunctionKey[13] = "\u001b[Y"; FunctionKey[14] = "?"; - FunctionKey[15] = "\u001b[a"; FunctionKey[16] = "\u001b[b"; - FunctionKey[17] = "\u001b[c"; FunctionKey[18] = "\u001b[d"; - FunctionKey[19] = "\u001b[e"; FunctionKey[20] = "\u001b[f"; - PrevScn[0] = PrevScn[1] = PrevScn[2] = PrevScn[3] = "\u001b[I"; - NextScn[0] = NextScn[1] = NextScn[2] = NextScn[3] = "\u001b[G"; - // more theoretically. - } - } - - public void setAnswerBack(String ab) { - this.answerBack = unEscape(ab); - } - - /** - * Get the terminal id used to identify this terminal. - */ - public String getTerminalID() { - return terminalID; - } - - /** - * A small conveniance method thar converts the string to a byte array - * for sending. - * @param s the string to be sent - */ - private boolean write(String s, boolean doecho) { - if (debug > 2) { - debugStr.append("write(|") - .append(s) - .append("|,") - .append(doecho); - debug(debugStr.toString()); - debugStr.setLength(0); - } - if (s == null) // aka the empty string. - return true; - /* NOTE: getBytes() honours some locale, it *CONVERTS* the string. - * However, we output only 7bit stuff towards the target, and *some* - * 8 bit control codes. We must not mess up the latter, so we do hand - * by hand copy. - */ - - byte arr[] = new byte[s.length()]; - for (int i = 0; i < s.length(); i++) { - arr[i] = (byte) s.charAt(i); - } - write(arr); - - if (doecho) - putString(s); - return true; - } - - private boolean write(int s, boolean doecho) { - if (debug > 2) { - debugStr.append("write(|") - .append(s) - .append("|,") - .append(doecho); - debug(debugStr.toString()); - debugStr.setLength(0); - } - - write(s); - - // TODO check if character is wide - if (doecho) - putChar((char)s, false, false); - return true; - } - - private boolean write(String s) { - return write(s, localecho); - } - - // =================================================================== - // the actual terminal emulation code comes here: - // =================================================================== - - private String terminalID = "vt320"; - private String answerBack = "Use Terminal.answerback to set ...\n"; - - // X - COLUMNS, Y - ROWS - int R,C; - int attributes = 0; - - int Sc,Sr,Sa,Stm,Sbm; - char Sgr,Sgl; - char Sgx[]; - - int insertmode = 0; - int statusmode = 0; - boolean vt52mode = false; - boolean keypadmode = false; /* false - numeric, true - application */ - boolean output8bit = false; - int normalcursor = 0; - boolean moveoutsidemargins = true; - boolean wraparound = true; - boolean sendcrlf = true; - boolean capslock = false; - boolean numlock = false; - int mouserpt = 0; - byte mousebut = 0; - - boolean useibmcharset = false; - - int lastwaslf = 0; - boolean usedcharsets = false; - - private final static char ESC = 27; - private final static char IND = 132; - private final static char NEL = 133; - private final static char RI = 141; - private final static char SS2 = 142; - private final static char SS3 = 143; - private final static char DCS = 144; - private final static char HTS = 136; - private final static char CSI = 155; - private final static char OSC = 157; - private final static int TSTATE_DATA = 0; - private final static int TSTATE_ESC = 1; /* ESC */ - private final static int TSTATE_CSI = 2; /* ESC [ */ - private final static int TSTATE_DCS = 3; /* ESC P */ - private final static int TSTATE_DCEQ = 4; /* ESC [? */ - private final static int TSTATE_ESCSQUARE = 5; /* ESC # */ - private final static int TSTATE_OSC = 6; /* ESC ] */ - private final static int TSTATE_SETG0 = 7; /* ESC (? */ - private final static int TSTATE_SETG1 = 8; /* ESC )? */ - private final static int TSTATE_SETG2 = 9; /* ESC *? */ - private final static int TSTATE_SETG3 = 10; /* ESC +? */ - private final static int TSTATE_CSI_DOLLAR = 11; /* ESC [ Pn $ */ - private final static int TSTATE_CSI_EX = 12; /* ESC [ ! */ - private final static int TSTATE_ESCSPACE = 13; /* ESC <space> */ - private final static int TSTATE_VT52X = 14; - private final static int TSTATE_VT52Y = 15; - private final static int TSTATE_CSI_TICKS = 16; - private final static int TSTATE_CSI_EQUAL = 17; /* ESC [ = */ - private final static int TSTATE_TITLE = 18; /* xterm title */ - - /* Keys we support */ - public final static int KEY_PAUSE = 1; - public final static int KEY_F1 = 2; - public final static int KEY_F2 = 3; - public final static int KEY_F3 = 4; - public final static int KEY_F4 = 5; - public final static int KEY_F5 = 6; - public final static int KEY_F6 = 7; - public final static int KEY_F7 = 8; - public final static int KEY_F8 = 9; - public final static int KEY_F9 = 10; - public final static int KEY_F10 = 11; - public final static int KEY_F11 = 12; - public final static int KEY_F12 = 13; - public final static int KEY_UP = 14; - public final static int KEY_DOWN =15 ; - public final static int KEY_LEFT = 16; - public final static int KEY_RIGHT = 17; - public final static int KEY_PAGE_DOWN = 18; - public final static int KEY_PAGE_UP = 19; - public final static int KEY_INSERT = 20; - public final static int KEY_DELETE = 21; - public final static int KEY_BACK_SPACE = 22; - public final static int KEY_HOME = 23; - public final static int KEY_END = 24; - public final static int KEY_NUM_LOCK = 25; - public final static int KEY_CAPS_LOCK = 26; - public final static int KEY_SHIFT = 27; - public final static int KEY_CONTROL = 28; - public final static int KEY_ALT = 29; - public final static int KEY_ENTER = 30; - public final static int KEY_NUMPAD0 = 31; - public final static int KEY_NUMPAD1 = 32; - public final static int KEY_NUMPAD2 = 33; - public final static int KEY_NUMPAD3 = 34; - public final static int KEY_NUMPAD4 = 35; - public final static int KEY_NUMPAD5 = 36; - public final static int KEY_NUMPAD6 = 37; - public final static int KEY_NUMPAD7 = 38; - public final static int KEY_NUMPAD8 = 39; - public final static int KEY_NUMPAD9 = 40; - public final static int KEY_DECIMAL = 41; - public final static int KEY_ADD = 42; - public final static int KEY_ESCAPE = 43; - - public final static int DELETE_IS_DEL = 0; - public final static int DELETE_IS_BACKSPACE = 1; - - /* The graphics charsets - * B - default ASCII - * A - ISO Latin 1 - * 0 - DEC SPECIAL - * < - User defined - * .... - */ - char gx[]; - char gl; // GL (left charset) - char gr; // GR (right charset) - int onegl; // single shift override for GL. - - // Map from scoansi linedrawing to DEC _and_ unicode (for the stuff which - // is not in linedrawing). Got from experimenting with scoadmin. - private final static String scoansi_acs = "Tm7k3x4u?kZl@mYjEnB\u2566DqCtAvM\u2550:\u2551N\u2557I\u2554;\u2557H\u255a0a<\u255d"; - // array to store DEC Special -> Unicode mapping - // Unicode DEC Unicode name (DEC name) - private static char DECSPECIAL[] = { - '\u0040', //5f blank - '\u2666', //60 black diamond - '\u2592', //61 grey square - '\u2409', //62 Horizontal tab (ht) pict. for control - '\u240c', //63 Form Feed (ff) pict. for control - '\u240d', //64 Carriage Return (cr) pict. for control - '\u240a', //65 Line Feed (lf) pict. for control - '\u00ba', //66 Masculine ordinal indicator - '\u00b1', //67 Plus or minus sign - '\u2424', //68 New Line (nl) pict. for control - '\u240b', //69 Vertical Tab (vt) pict. for control - '\u2518', //6a Forms light up and left - '\u2510', //6b Forms light down and left - '\u250c', //6c Forms light down and right - '\u2514', //6d Forms light up and right - '\u253c', //6e Forms light vertical and horizontal - '\u2594', //6f Upper 1/8 block (Scan 1) - '\u2580', //70 Upper 1/2 block (Scan 3) - '\u2500', //71 Forms light horizontal or ?em dash? (Scan 5) - '\u25ac', //72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7) - '\u005f', //73 \u005f underscore or \u2581 lower 1/8 (Scan 9) - '\u251c', //74 Forms light vertical and right - '\u2524', //75 Forms light vertical and left - '\u2534', //76 Forms light up and horizontal - '\u252c', //77 Forms light down and horizontal - '\u2502', //78 vertical bar - '\u2264', //79 less than or equal - '\u2265', //7a greater than or equal - '\u00b6', //7b paragraph - '\u2260', //7c not equal - '\u00a3', //7d Pound Sign (british) - '\u00b7' //7e Middle Dot - }; - - /** Strings to send on function key pressing */ - private String Numpad[]; - private String FunctionKey[]; - private String FunctionKeyShift[]; - private String FunctionKeyCtrl[]; - private String FunctionKeyAlt[]; - private String TabKey[]; - private String KeyUp[],KeyDown[],KeyLeft[],KeyRight[]; - private String KPMinus, KPComma, KPPeriod, KPEnter; - private String PF1, PF2, PF3, PF4; - private String Help, Do, Find, Select; - - private String KeyHome[], KeyEnd[], Insert[], Remove[], PrevScn[], NextScn[]; - private String Escape[], BackSpace[], NUMDot[], NUMPlus[]; - - private String osc,dcs; /* to memorize OSC & DCS control sequence */ - - /** vt320 state variable (internal) */ - private int term_state = TSTATE_DATA; - /** in vms mode, set by Terminal.VMS property */ - private boolean vms = false; - /** Tabulators */ - private byte[] Tabs; - /** The list of integers as used by CSI */ - private int[] DCEvars = new int[30]; - private int DCEvar; - - /** - * Replace escape code characters (backslash + identifier) with their - * respective codes. - * @param tmp the string to be parsed - * @return a unescaped string - */ - static String unEscape(String tmp) { - int idx = 0, oldidx = 0; - String cmd; - // f.println("unescape("+tmp+")"); - cmd = ""; - while ((idx = tmp.indexOf('\\', oldidx)) >= 0 && - ++idx <= tmp.length()) { - cmd += tmp.substring(oldidx, idx - 1); - if (idx == tmp.length()) return cmd; - switch (tmp.charAt(idx)) { - case 'b': - cmd += "\b"; - break; - case 'e': - cmd += "\u001b"; - break; - case 'n': - cmd += "\n"; - break; - case 'r': - cmd += "\r"; - break; - case 't': - cmd += "\t"; - break; - case 'v': - cmd += "\u000b"; - break; - case 'a': - cmd += "\u0012"; - break; - default : - if ((tmp.charAt(idx) >= '0') && (tmp.charAt(idx) <= '9')) { - int i; - for (i = idx; i < tmp.length(); i++) - if ((tmp.charAt(i) < '0') || (tmp.charAt(i) > '9')) - break; - cmd += (char) Integer.parseInt(tmp.substring(idx, i)); - idx = i - 1; - } else - cmd += tmp.substring(idx, ++idx); - break; - } - oldidx = ++idx; - } - if (oldidx <= tmp.length()) cmd += tmp.substring(oldidx); - return cmd; - } - - /** - * A small conveniance method thar converts a 7bit string to the 8bit - * version depending on VT52/Output8Bit mode. - * - * @param s the string to be sent - */ - private boolean writeSpecial(String s) { - if (s == null) - return true; - if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == 'O'))) { - if (vt52mode) { - if ((s.charAt(2) >= 'P') && (s.charAt(2) <= 'S')) { - s = "\u001b" + s.substring(2); /* ESC x */ - } else { - s = "\u001b?" + s.substring(2); /* ESC ? x */ - } - } else { - if (output8bit) { - s = "\u008f" + s.substring(2); /* SS3 x */ - } /* else keep string as it is */ - } - } - if (((s.length() >= 3) && (s.charAt(0) == 27) && (s.charAt(1) == '['))) { - if (output8bit) { - s = "\u009b" + s.substring(2); /* CSI ... */ - } /* else keep */ - } - return write(s, false); - } - - /** - * main keytyping event handler... - */ - public void keyPressed(int keyCode, char keyChar, int modifiers) { - boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0; - boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0; - boolean alt = (modifiers & VDUInput.KEY_ALT) != 0; - - if (debug > 1) { - debugStr.append("keyPressed(") - .append(keyCode) - .append(", ") - .append((int)keyChar) - .append(", ") - .append(modifiers) - .append(')'); - debug(debugStr.toString()); - debugStr.setLength(0); - } - - int xind; - String fmap[]; - xind = 0; - fmap = FunctionKey; - if (shift) { - fmap = FunctionKeyShift; - xind = 1; - } - if (control) { - fmap = FunctionKeyCtrl; - xind = 2; - } - if (alt) { - fmap = FunctionKeyAlt; - xind = 3; - } - - switch (keyCode) { - case KEY_PAUSE: - if (shift || control) - sendTelnetCommand((byte) 243); // BREAK - break; - case KEY_F1: - writeSpecial(fmap[1]); - break; - case KEY_F2: - writeSpecial(fmap[2]); - break; - case KEY_F3: - writeSpecial(fmap[3]); - break; - case KEY_F4: - writeSpecial(fmap[4]); - break; - case KEY_F5: - writeSpecial(fmap[5]); - break; - case KEY_F6: - writeSpecial(fmap[6]); - break; - case KEY_F7: - writeSpecial(fmap[7]); - break; - case KEY_F8: - writeSpecial(fmap[8]); - break; - case KEY_F9: - writeSpecial(fmap[9]); - break; - case KEY_F10: - writeSpecial(fmap[10]); - break; - case KEY_F11: - writeSpecial(fmap[11]); - break; - case KEY_F12: - writeSpecial(fmap[12]); - break; - case KEY_UP: - writeSpecial(KeyUp[xind]); - break; - case KEY_DOWN: - writeSpecial(KeyDown[xind]); - break; - case KEY_LEFT: - writeSpecial(KeyLeft[xind]); - break; - case KEY_RIGHT: - writeSpecial(KeyRight[xind]); - break; - case KEY_PAGE_DOWN: - writeSpecial(NextScn[xind]); - break; - case KEY_PAGE_UP: - writeSpecial(PrevScn[xind]); - break; - case KEY_INSERT: - writeSpecial(Insert[xind]); - break; - case KEY_DELETE: - writeSpecial(Remove[xind]); - break; - case KEY_BACK_SPACE: - writeSpecial(BackSpace[xind]); - if (localecho) { - if (BackSpace[xind] == "\b") { - putString("\b \b"); // make the last char 'deleted' - } else { - putString(BackSpace[xind]); // echo it - } - } - break; - case KEY_HOME: - writeSpecial(KeyHome[xind]); - break; - case KEY_END: - writeSpecial(KeyEnd[xind]); - break; - case KEY_NUM_LOCK: - if (vms && control) { - writeSpecial(PF1); - } - if (!control) - numlock = !numlock; - break; - case KEY_CAPS_LOCK: - capslock = !capslock; - return; - case KEY_SHIFT: - case KEY_CONTROL: - case KEY_ALT: - return; - default: - break; - } - } -/* - public void keyReleased(KeyEvent evt) { - if (debug > 1) debug("keyReleased("+evt+")"); - // ignore - } -*/ - /** - * Handle key Typed events for the terminal, this will get - * all normal key types, but no shift/alt/control/numlock. - */ - public void keyTyped(int keyCode, char keyChar, int modifiers) { - boolean control = (modifiers & VDUInput.KEY_CONTROL) != 0; - boolean shift = (modifiers & VDUInput.KEY_SHIFT) != 0; - boolean alt = (modifiers & VDUInput.KEY_ALT) != 0; - - if (debug > 1) debug("keyTyped("+keyCode+", "+(int)keyChar+", "+modifiers+")"); - - if (keyChar == '\t') { - if (shift) { - write(TabKey[1], false); - } else { - if (control) { - write(TabKey[2], false); - } else { - if (alt) { - write(TabKey[3], false); - } else { - write(TabKey[0], false); - } - } - } - return; - } - if (alt) { - write(((char) (keyChar | 0x80))); - return; - } - - if (((keyCode == KEY_ENTER) || (keyChar == 10)) - && !control) { - write('\r'); - if (localecho) putString("\r\n"); // bad hack - return; - } - - if ((keyCode == 10) && !control) { - debug("Sending \\r"); - write('\r'); - return; - } - - // FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @, - // so we can't just use it here... will probably break some other VMS - // codes. -Marcus - // if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ') - // && control) - if (((!vms && keyChar == '2') || keyChar == ' ') && control) - write(0); - - if (vms) { - if (keyChar == 127 && !control) { - if (shift) - writeSpecial(Insert[0]); // VMS shift delete = insert - else - writeSpecial(Remove[0]); // VMS delete = remove - return; - } else if (control) - switch (keyChar) { - case '0': - writeSpecial(Numpad[0]); - return; - case '1': - writeSpecial(Numpad[1]); - return; - case '2': - writeSpecial(Numpad[2]); - return; - case '3': - writeSpecial(Numpad[3]); - return; - case '4': - writeSpecial(Numpad[4]); - return; - case '5': - writeSpecial(Numpad[5]); - return; - case '6': - writeSpecial(Numpad[6]); - return; - case '7': - writeSpecial(Numpad[7]); - return; - case '8': - writeSpecial(Numpad[8]); - return; - case '9': - writeSpecial(Numpad[9]); - return; - case '.': - writeSpecial(KPPeriod); - return; - case '-': - case 31: - writeSpecial(KPMinus); - return; - case '+': - writeSpecial(KPComma); - return; - case 10: - writeSpecial(KPEnter); - return; - case '/': - writeSpecial(PF2); - return; - case '*': - writeSpecial(PF3); - return; - /* NUMLOCK handled in keyPressed */ - default: - break; - } - /* Now what does this do and how did it get here. -Marcus - if (shift && keyChar < 32) { - write(PF1+(char)(keyChar + 64)); - return; - } - */ - } - - // FIXME: not used? - //String fmap[]; - int xind; - xind = 0; - //fmap = FunctionKey; - if (shift) { - //fmap = FunctionKeyShift; - xind = 1; - } - if (control) { - //fmap = FunctionKeyCtrl; - xind = 2; - } - if (alt) { - //fmap = FunctionKeyAlt; - xind = 3; - } - - if (keyCode == KEY_ESCAPE) { - writeSpecial(Escape[xind]); - return; - } - - if ((modifiers & VDUInput.KEY_ACTION) != 0) - switch (keyCode) { - case KEY_NUMPAD0: - writeSpecial(Numpad[0]); - return; - case KEY_NUMPAD1: - writeSpecial(Numpad[1]); - return; - case KEY_NUMPAD2: - writeSpecial(Numpad[2]); - return; - case KEY_NUMPAD3: - writeSpecial(Numpad[3]); - return; - case KEY_NUMPAD4: - writeSpecial(Numpad[4]); - return; - case KEY_NUMPAD5: - writeSpecial(Numpad[5]); - return; - case KEY_NUMPAD6: - writeSpecial(Numpad[6]); - return; - case KEY_NUMPAD7: - writeSpecial(Numpad[7]); - return; - case KEY_NUMPAD8: - writeSpecial(Numpad[8]); - return; - case KEY_NUMPAD9: - writeSpecial(Numpad[9]); - return; - case KEY_DECIMAL: - writeSpecial(NUMDot[xind]); - return; - case KEY_ADD: - writeSpecial(NUMPlus[xind]); - return; - } - - if (!((keyChar == 8) || (keyChar == 127) || (keyChar == '\r') || (keyChar == '\n'))) { - write(keyChar); - return; - } - } - - private void handle_dcs(String dcs) { - debugStr.append("DCS: ") - .append(dcs); - debug(debugStr.toString()); - debugStr.setLength(0); - } - - private void handle_osc(String osc) { - if (osc.length() > 2 && osc.substring(0, 2).equals("4;")) { - // Define color palette - String[] colorData = osc.split(";"); - - try { - int colorIndex = Integer.parseInt(colorData[1]); - - if ("rgb:".equals(colorData[2].substring(0, 4))) { - String[] rgb = colorData[2].substring(4).split("/"); - - int red = Integer.parseInt(rgb[0].substring(0, 2), 16) & 0xFF; - int green = Integer.parseInt(rgb[1].substring(0, 2), 16) & 0xFF; - int blue = Integer.parseInt(rgb[2].substring(0, 2), 16) & 0xFF; - display.setColor(colorIndex, red, green, blue); - } - } catch (Exception e) { - debugStr.append("OSC: invalid color sequence encountered: ") - .append(osc); - debug(debugStr.toString()); - debugStr.setLength(0); - } - } else - debug("OSC: " + osc); - } - - private final static char unimap[] = { - //# - //# Name: cp437_DOSLatinUS to Unicode table - //# Unicode version: 1.1 - //# Table version: 1.1 - //# Table format: Format A - //# Date: 03/31/95 - //# Authors: Michel Suignard <michelsu@microsoft.com> - //# Lori Hoerth <lorih@microsoft.com> - //# General notes: none - //# - //# Format: Three tab-separated columns - //# Column #1 is the cp1255_WinHebrew code (in hex) - //# Column #2 is the Unicode (in hex as 0xXXXX) - //# Column #3 is the Unicode name (follows a comment sign, '#') - //# - //# The entries are in cp437_DOSLatinUS order - //# - - 0x0000, // #NULL - 0x0001, // #START OF HEADING - 0x0002, // #START OF TEXT - 0x0003, // #END OF TEXT - 0x0004, // #END OF TRANSMISSION - 0x0005, // #ENQUIRY - 0x0006, // #ACKNOWLEDGE - 0x0007, // #BELL - 0x0008, // #BACKSPACE - 0x0009, // #HORIZONTAL TABULATION - 0x000a, // #LINE FEED - 0x000b, // #VERTICAL TABULATION - 0x000c, // #FORM FEED - 0x000d, // #CARRIAGE RETURN - 0x000e, // #SHIFT OUT - 0x000f, // #SHIFT IN - 0x0010, // #DATA LINK ESCAPE - 0x0011, // #DEVICE CONTROL ONE - 0x0012, // #DEVICE CONTROL TWO - 0x0013, // #DEVICE CONTROL THREE - 0x0014, // #DEVICE CONTROL FOUR - 0x0015, // #NEGATIVE ACKNOWLEDGE - 0x0016, // #SYNCHRONOUS IDLE - 0x0017, // #END OF TRANSMISSION BLOCK - 0x0018, // #CANCEL - 0x0019, // #END OF MEDIUM - 0x001a, // #SUBSTITUTE - 0x001b, // #ESCAPE - 0x001c, // #FILE SEPARATOR - 0x001d, // #GROUP SEPARATOR - 0x001e, // #RECORD SEPARATOR - 0x001f, // #UNIT SEPARATOR - 0x0020, // #SPACE - 0x0021, // #EXCLAMATION MARK - 0x0022, // #QUOTATION MARK - 0x0023, // #NUMBER SIGN - 0x0024, // #DOLLAR SIGN - 0x0025, // #PERCENT SIGN - 0x0026, // #AMPERSAND - 0x0027, // #APOSTROPHE - 0x0028, // #LEFT PARENTHESIS - 0x0029, // #RIGHT PARENTHESIS - 0x002a, // #ASTERISK - 0x002b, // #PLUS SIGN - 0x002c, // #COMMA - 0x002d, // #HYPHEN-MINUS - 0x002e, // #FULL STOP - 0x002f, // #SOLIDUS - 0x0030, // #DIGIT ZERO - 0x0031, // #DIGIT ONE - 0x0032, // #DIGIT TWO - 0x0033, // #DIGIT THREE - 0x0034, // #DIGIT FOUR - 0x0035, // #DIGIT FIVE - 0x0036, // #DIGIT SIX - 0x0037, // #DIGIT SEVEN - 0x0038, // #DIGIT EIGHT - 0x0039, // #DIGIT NINE - 0x003a, // #COLON - 0x003b, // #SEMICOLON - 0x003c, // #LESS-THAN SIGN - 0x003d, // #EQUALS SIGN - 0x003e, // #GREATER-THAN SIGN - 0x003f, // #QUESTION MARK - 0x0040, // #COMMERCIAL AT - 0x0041, // #LATIN CAPITAL LETTER A - 0x0042, // #LATIN CAPITAL LETTER B - 0x0043, // #LATIN CAPITAL LETTER C - 0x0044, // #LATIN CAPITAL LETTER D - 0x0045, // #LATIN CAPITAL LETTER E - 0x0046, // #LATIN CAPITAL LETTER F - 0x0047, // #LATIN CAPITAL LETTER G - 0x0048, // #LATIN CAPITAL LETTER H - 0x0049, // #LATIN CAPITAL LETTER I - 0x004a, // #LATIN CAPITAL LETTER J - 0x004b, // #LATIN CAPITAL LETTER K - 0x004c, // #LATIN CAPITAL LETTER L - 0x004d, // #LATIN CAPITAL LETTER M - 0x004e, // #LATIN CAPITAL LETTER N - 0x004f, // #LATIN CAPITAL LETTER O - 0x0050, // #LATIN CAPITAL LETTER P - 0x0051, // #LATIN CAPITAL LETTER Q - 0x0052, // #LATIN CAPITAL LETTER R - 0x0053, // #LATIN CAPITAL LETTER S - 0x0054, // #LATIN CAPITAL LETTER T - 0x0055, // #LATIN CAPITAL LETTER U - 0x0056, // #LATIN CAPITAL LETTER V - 0x0057, // #LATIN CAPITAL LETTER W - 0x0058, // #LATIN CAPITAL LETTER X - 0x0059, // #LATIN CAPITAL LETTER Y - 0x005a, // #LATIN CAPITAL LETTER Z - 0x005b, // #LEFT SQUARE BRACKET - 0x005c, // #REVERSE SOLIDUS - 0x005d, // #RIGHT SQUARE BRACKET - 0x005e, // #CIRCUMFLEX ACCENT - 0x005f, // #LOW LINE - 0x0060, // #GRAVE ACCENT - 0x0061, // #LATIN SMALL LETTER A - 0x0062, // #LATIN SMALL LETTER B - 0x0063, // #LATIN SMALL LETTER C - 0x0064, // #LATIN SMALL LETTER D - 0x0065, // #LATIN SMALL LETTER E - 0x0066, // #LATIN SMALL LETTER F - 0x0067, // #LATIN SMALL LETTER G - 0x0068, // #LATIN SMALL LETTER H - 0x0069, // #LATIN SMALL LETTER I - 0x006a, // #LATIN SMALL LETTER J - 0x006b, // #LATIN SMALL LETTER K - 0x006c, // #LATIN SMALL LETTER L - 0x006d, // #LATIN SMALL LETTER M - 0x006e, // #LATIN SMALL LETTER N - 0x006f, // #LATIN SMALL LETTER O - 0x0070, // #LATIN SMALL LETTER P - 0x0071, // #LATIN SMALL LETTER Q - 0x0072, // #LATIN SMALL LETTER R - 0x0073, // #LATIN SMALL LETTER S - 0x0074, // #LATIN SMALL LETTER T - 0x0075, // #LATIN SMALL LETTER U - 0x0076, // #LATIN SMALL LETTER V - 0x0077, // #LATIN SMALL LETTER W - 0x0078, // #LATIN SMALL LETTER X - 0x0079, // #LATIN SMALL LETTER Y - 0x007a, // #LATIN SMALL LETTER Z - 0x007b, // #LEFT CURLY BRACKET - 0x007c, // #VERTICAL LINE - 0x007d, // #RIGHT CURLY BRACKET - 0x007e, // #TILDE - 0x007f, // #DELETE - 0x00c7, // #LATIN CAPITAL LETTER C WITH CEDILLA - 0x00fc, // #LATIN SMALL LETTER U WITH DIAERESIS - 0x00e9, // #LATIN SMALL LETTER E WITH ACUTE - 0x00e2, // #LATIN SMALL LETTER A WITH CIRCUMFLEX - 0x00e4, // #LATIN SMALL LETTER A WITH DIAERESIS - 0x00e0, // #LATIN SMALL LETTER A WITH GRAVE - 0x00e5, // #LATIN SMALL LETTER A WITH RING ABOVE - 0x00e7, // #LATIN SMALL LETTER C WITH CEDILLA - 0x00ea, // #LATIN SMALL LETTER E WITH CIRCUMFLEX - 0x00eb, // #LATIN SMALL LETTER E WITH DIAERESIS - 0x00e8, // #LATIN SMALL LETTER E WITH GRAVE - 0x00ef, // #LATIN SMALL LETTER I WITH DIAERESIS - 0x00ee, // #LATIN SMALL LETTER I WITH CIRCUMFLEX - 0x00ec, // #LATIN SMALL LETTER I WITH GRAVE - 0x00c4, // #LATIN CAPITAL LETTER A WITH DIAERESIS - 0x00c5, // #LATIN CAPITAL LETTER A WITH RING ABOVE - 0x00c9, // #LATIN CAPITAL LETTER E WITH ACUTE - 0x00e6, // #LATIN SMALL LIGATURE AE - 0x00c6, // #LATIN CAPITAL LIGATURE AE - 0x00f4, // #LATIN SMALL LETTER O WITH CIRCUMFLEX - 0x00f6, // #LATIN SMALL LETTER O WITH DIAERESIS - 0x00f2, // #LATIN SMALL LETTER O WITH GRAVE - 0x00fb, // #LATIN SMALL LETTER U WITH CIRCUMFLEX - 0x00f9, // #LATIN SMALL LETTER U WITH GRAVE - 0x00ff, // #LATIN SMALL LETTER Y WITH DIAERESIS - 0x00d6, // #LATIN CAPITAL LETTER O WITH DIAERESIS - 0x00dc, // #LATIN CAPITAL LETTER U WITH DIAERESIS - 0x00a2, // #CENT SIGN - 0x00a3, // #POUND SIGN - 0x00a5, // #YEN SIGN - 0x20a7, // #PESETA SIGN - 0x0192, // #LATIN SMALL LETTER F WITH HOOK - 0x00e1, // #LATIN SMALL LETTER A WITH ACUTE - 0x00ed, // #LATIN SMALL LETTER I WITH ACUTE - 0x00f3, // #LATIN SMALL LETTER O WITH ACUTE - 0x00fa, // #LATIN SMALL LETTER U WITH ACUTE - 0x00f1, // #LATIN SMALL LETTER N WITH TILDE - 0x00d1, // #LATIN CAPITAL LETTER N WITH TILDE - 0x00aa, // #FEMININE ORDINAL INDICATOR - 0x00ba, // #MASCULINE ORDINAL INDICATOR - 0x00bf, // #INVERTED QUESTION MARK - 0x2310, // #REVERSED NOT SIGN - 0x00ac, // #NOT SIGN - 0x00bd, // #VULGAR FRACTION ONE HALF - 0x00bc, // #VULGAR FRACTION ONE QUARTER - 0x00a1, // #INVERTED EXCLAMATION MARK - 0x00ab, // #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - 0x00bb, // #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - 0x2591, // #LIGHT SHADE - 0x2592, // #MEDIUM SHADE - 0x2593, // #DARK SHADE - 0x2502, // #BOX DRAWINGS LIGHT VERTICAL - 0x2524, // #BOX DRAWINGS LIGHT VERTICAL AND LEFT - 0x2561, // #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE - 0x2562, // #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE - 0x2556, // #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE - 0x2555, // #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE - 0x2563, // #BOX DRAWINGS DOUBLE VERTICAL AND LEFT - 0x2551, // #BOX DRAWINGS DOUBLE VERTICAL - 0x2557, // #BOX DRAWINGS DOUBLE DOWN AND LEFT - 0x255d, // #BOX DRAWINGS DOUBLE UP AND LEFT - 0x255c, // #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE - 0x255b, // #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE - 0x2510, // #BOX DRAWINGS LIGHT DOWN AND LEFT - 0x2514, // #BOX DRAWINGS LIGHT UP AND RIGHT - 0x2534, // #BOX DRAWINGS LIGHT UP AND HORIZONTAL - 0x252c, // #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - 0x251c, // #BOX DRAWINGS LIGHT VERTICAL AND RIGHT - 0x2500, // #BOX DRAWINGS LIGHT HORIZONTAL - 0x253c, // #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - 0x255e, // #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE - 0x255f, // #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE - 0x255a, // #BOX DRAWINGS DOUBLE UP AND RIGHT - 0x2554, // #BOX DRAWINGS DOUBLE DOWN AND RIGHT - 0x2569, // #BOX DRAWINGS DOUBLE UP AND HORIZONTAL - 0x2566, // #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL - 0x2560, // #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT - 0x2550, // #BOX DRAWINGS DOUBLE HORIZONTAL - 0x256c, // #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL - 0x2567, // #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE - 0x2568, // #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE - 0x2564, // #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE - 0x2565, // #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE - 0x2559, // #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE - 0x2558, // #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE - 0x2552, // #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE - 0x2553, // #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE - 0x256b, // #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE - 0x256a, // #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE - 0x2518, // #BOX DRAWINGS LIGHT UP AND LEFT - 0x250c, // #BOX DRAWINGS LIGHT DOWN AND RIGHT - 0x2588, // #FULL BLOCK - 0x2584, // #LOWER HALF BLOCK - 0x258c, // #LEFT HALF BLOCK - 0x2590, // #RIGHT HALF BLOCK - 0x2580, // #UPPER HALF BLOCK - 0x03b1, // #GREEK SMALL LETTER ALPHA - 0x00df, // #LATIN SMALL LETTER SHARP S - 0x0393, // #GREEK CAPITAL LETTER GAMMA - 0x03c0, // #GREEK SMALL LETTER PI - 0x03a3, // #GREEK CAPITAL LETTER SIGMA - 0x03c3, // #GREEK SMALL LETTER SIGMA - 0x00b5, // #MICRO SIGN - 0x03c4, // #GREEK SMALL LETTER TAU - 0x03a6, // #GREEK CAPITAL LETTER PHI - 0x0398, // #GREEK CAPITAL LETTER THETA - 0x03a9, // #GREEK CAPITAL LETTER OMEGA - 0x03b4, // #GREEK SMALL LETTER DELTA - 0x221e, // #INFINITY - 0x03c6, // #GREEK SMALL LETTER PHI - 0x03b5, // #GREEK SMALL LETTER EPSILON - 0x2229, // #INTERSECTION - 0x2261, // #IDENTICAL TO - 0x00b1, // #PLUS-MINUS SIGN - 0x2265, // #GREATER-THAN OR EQUAL TO - 0x2264, // #LESS-THAN OR EQUAL TO - 0x2320, // #TOP HALF INTEGRAL - 0x2321, // #BOTTOM HALF INTEGRAL - 0x00f7, // #DIVISION SIGN - 0x2248, // #ALMOST EQUAL TO - 0x00b0, // #DEGREE SIGN - 0x2219, // #BULLET OPERATOR - 0x00b7, // #MIDDLE DOT - 0x221a, // #SQUARE ROOT - 0x207f, // #SUPERSCRIPT LATIN SMALL LETTER N - 0x00b2, // #SUPERSCRIPT TWO - 0x25a0, // #BLACK SQUARE - 0x00a0, // #NO-BREAK SPACE - }; - - public char map_cp850_unicode(char x) { - if (x >= 0x100) - return x; - return unimap[x]; - } - - private void _SetCursor(int row, int col) { - int maxr = height - 1; - int tm = getTopMargin(); - - R = (row < 0)?0: row; - C = (col < 0)?0: (col >= width) ? width - 1 : col; - - if (!moveoutsidemargins) { - R += tm; - maxr = getBottomMargin(); - } - if (R > maxr) R = maxr; - } - - private void putChar(char c, boolean isWide, boolean doshowcursor) { - int rows = this.height; //statusline - int columns = this.width; - // byte msg[]; - -// if (debug > 4) { -// debugStr.append("putChar(") -// .append(c) -// .append(" [") -// .append((int) c) -// .append("]) at R=") -// .append(R) -// .append(" , C=") -// .append(C) -// .append(", columns=") -// .append(columns) -// .append(", rows=") -// .append(rows); -// debug(debugStr.toString()); -// debugStr.setLength(0); -// } -// markLine(R, 1); -// if (c > 255) { -// if (debug > 0) -// debug("char > 255:" + (int) c); -// //return; -// } - - switch (term_state) { - case TSTATE_DATA: - /* FIXME: we shouldn't use chars with bit 8 set if ibmcharset. - * probably... but some BBS do anyway... - */ - if (!useibmcharset) { - boolean doneflag = true; - switch (c) { - case OSC: - osc = ""; - term_state = TSTATE_OSC; - break; - case RI: - if (R > getTopMargin()) - R--; - else - insertLine(R, 1, SCROLL_DOWN); - if (debug > 1) - debug("RI"); - break; - case IND: - if (debug > 2) { - debugStr.append("IND at ") - .append(R) - .append(", tm is ") - .append(getTopMargin()) - .append(", bm is ") - .append(getBottomMargin()); - debug(debugStr.toString()); - debugStr.setLength(0); - } - if (R == getBottomMargin() || R == rows - 1) - insertLine(R, 1, SCROLL_UP); - else - R++; - if (debug > 1) - debug("IND (at " + R + " )"); - break; - case NEL: - if (R == getBottomMargin() || R == rows - 1) - insertLine(R, 1, SCROLL_UP); - else - R++; - C = 0; - if (debug > 1) - debug("NEL (at " + R + " )"); - break; - case HTS: - Tabs[C] = 1; - if (debug > 1) - debug("HTS"); - break; - case DCS: - dcs = ""; - term_state = TSTATE_DCS; - break; - default: - doneflag = false; - break; - } - if (doneflag) break; - } - switch (c) { - case SS3: - onegl = 3; - break; - case SS2: - onegl = 2; - break; - case CSI: // should be in the 8bit section, but some BBS use this - DCEvar = 0; - DCEvars[0] = 0; - DCEvars[1] = 0; - DCEvars[2] = 0; - DCEvars[3] = 0; - term_state = TSTATE_CSI; - break; - case ESC: - term_state = TSTATE_ESC; - lastwaslf = 0; - break; - case 5: /* ENQ */ - write(answerBack, false); - break; - case 12: - /* FormFeed, Home for the BBS world */ - deleteArea(0, 0, columns, rows, attributes); - C = R = 0; - break; - case '\b': /* 8 */ - C--; - if (C < 0) - C = 0; - lastwaslf = 0; - break; - case '\t': - do { - // Don't overwrite or insert! TABS are not destructive, but movement! - C++; - } while (C < columns && (Tabs[C] == 0)); - lastwaslf = 0; - break; - case '\r': // 13 CR - C = 0; - break; - case '\n': // 10 LF - if (debug > 3) - debug("R= " + R + ", bm " + getBottomMargin() + ", tm=" + getTopMargin() + ", rows=" + rows); - if (!vms) { - if (lastwaslf != 0 && lastwaslf != c) // Ray: I do not understand this logic. - break; - lastwaslf = c; - /*C = 0;*/ - } - if (R == getBottomMargin() || R >= rows - 1) - insertLine(R, 1, SCROLL_UP); - else - R++; - break; - case 7: - beep(); - break; - case '\016': /* SMACS , as */ - /* ^N, Shift out - Put G1 into GL */ - gl = 1; - usedcharsets = true; - break; - case '\017': /* RMACS , ae */ - /* ^O, Shift in - Put G0 into GL */ - gl = 0; - usedcharsets = true; - break; - default: - { - int thisgl = gl; - - if (onegl >= 0) { - thisgl = onegl; - onegl = -1; - } - lastwaslf = 0; - if (c < 32) { - if (c != 0) - if (debug > 0) - debug("TSTATE_DATA char: " + ((int) c)); - /*break; some BBS really want those characters, like hearst etc. */ - if (c == 0) /* print 0 ... you bet */ - break; - } - if (C >= columns) { - if (wraparound) { - int bot = rows; - - // If we're in the scroll region, check against the bottom margin - if (R <= getBottomMargin() && R >= getTopMargin()) - bot = getBottomMargin() + 1; - - if (R < bot - 1) - R++; - else { - if (debug > 3) debug("scrolling due to wrap at " + R); - insertLine(R, 1, SCROLL_UP); - } - C = 0; - } else { - // cursor stays on last character. - C = columns - 1; - } - } - - boolean mapped = false; - - // Mapping if DEC Special is chosen charset - if (usedcharsets) { - if (c >= '\u0020' && c <= '\u007f') { - switch (gx[thisgl]) { - case '0': - // Remap SCOANSI line drawing to VT100 line drawing chars - // for our SCO using customers. - if (terminalID.equals("scoansi") || terminalID.equals("ansi")) { - for (int i = 0; i < scoansi_acs.length(); i += 2) { - if (c == scoansi_acs.charAt(i)) { - c = scoansi_acs.charAt(i + 1); - break; - } - } - } - if (c >= '\u005f' && c <= '\u007e') { - c = DECSPECIAL[(short) c - 0x5f]; - mapped = true; - } - break; - case '<': // 'user preferred' is currently 'ISO Latin-1 suppl - c = (char) ((c & 0x7f) | 0x80); - mapped = true; - break; - case 'A': - case 'B': // Latin-1 , ASCII -> fall through - mapped = true; - break; - default: - debug("Unsupported GL mapping: " + gx[thisgl]); - break; - } - } - if (!mapped && (c >= '\u0080' && c <= '\u00ff')) { - switch (gx[gr]) { - case '0': - if (c >= '\u00df' && c <= '\u00fe') { - c = DECSPECIAL[c - '\u00df']; - mapped = true; - } - break; - case '<': - case 'A': - case 'B': - mapped = true; - break; - default: - debug("Unsupported GR mapping: " + gx[gr]); - break; - } - } - } - if (!mapped && useibmcharset) - c = map_cp850_unicode(c); - - /*if(true || (statusmode == 0)) { */ - if (isWide) { - if (C >= columns - 1) { - if (wraparound) { - int bot = rows; - - // If we're in the scroll region, check against the bottom margin - if (R <= getBottomMargin() && R >= getTopMargin()) - bot = getBottomMargin() + 1; - - if (R < bot - 1) - R++; - else { - if (debug > 3) debug("scrolling due to wrap at " + R); - insertLine(R, 1, SCROLL_UP); - } - C = 0; - } else { - // cursor stays on last wide character. - C = columns - 2; - } - } - } - - if (insertmode == 1) { - if (isWide) { - insertChar(C++, R, c, attributes | FULLWIDTH); - insertChar(C, R, ' ', attributes | FULLWIDTH); - } else - insertChar(C, R, c, attributes); - } else { - if (isWide) { - putChar(C++, R, c, attributes | FULLWIDTH); - putChar(C, R, ' ', attributes | FULLWIDTH); - } else - putChar(C, R, c, attributes); - } - - /* - } else { - if (insertmode==1) { - insertChar(C, rows, c, attributes); - } else { - putChar(C, rows, c, attributes); - } - } - */ - C++; - break; - } - } /* switch(c) */ - break; - case TSTATE_OSC: - if ((c < 0x20) && (c != ESC)) {// NP - No printing character - handle_osc(osc); - term_state = TSTATE_DATA; - break; - } - //but check for vt102 ESC \ - if (c == '\\' && osc.charAt(osc.length() - 1) == ESC) { - handle_osc(osc); - term_state = TSTATE_DATA; - break; - } - osc = osc + c; - break; - case TSTATE_ESCSPACE: - term_state = TSTATE_DATA; - switch (c) { - case 'F': /* S7C1T, Disable output of 8-bit controls, use 7-bit */ - output8bit = false; - break; - case 'G': /* S8C1T, Enable output of 8-bit control codes*/ - output8bit = true; - break; - default: - debug("ESC <space> " + c + " unhandled."); - } - break; - case TSTATE_ESC: - term_state = TSTATE_DATA; - switch (c) { - case ' ': - term_state = TSTATE_ESCSPACE; - break; - case '#': - term_state = TSTATE_ESCSQUARE; - break; - case 'c': - /* Hard terminal reset */ - reset(); - break; - case '[': - DCEvar = 0; - DCEvars[0] = 0; - DCEvars[1] = 0; - DCEvars[2] = 0; - DCEvars[3] = 0; - term_state = TSTATE_CSI; - break; - case ']': - osc = ""; - term_state = TSTATE_OSC; - break; - case 'P': - dcs = ""; - term_state = TSTATE_DCS; - break; - case 'A': /* CUU */ - R--; - if (R < 0) R = 0; - break; - case 'B': /* CUD */ - R++; - if (R >= rows) R = rows - 1; - break; - case 'C': - C++; - if (C >= columns) C = columns - 1; - break; - case 'I': // RI - insertLine(R, 1, SCROLL_DOWN); - break; - case 'E': /* NEL */ - if (R == getBottomMargin() || R == rows - 1) - insertLine(R, 1, SCROLL_UP); - else - R++; - C = 0; - if (debug > 1) - debug("ESC E (at " + R + ")"); - break; - case 'D': /* IND */ - if (R == getBottomMargin() || R == rows - 1) - insertLine(R, 1, SCROLL_UP); - else - R++; - if (debug > 1) - debug("ESC D (at " + R + " )"); - break; - case 'J': /* erase to end of screen */ - if (R < rows - 1) - deleteArea(0, R + 1, columns, rows - R - 1, attributes); - if (C < columns - 1) - deleteArea(C, R, columns - C, 1, attributes); - break; - case 'K': - if (C < columns - 1) - deleteArea(C, R, columns - C, 1, attributes); - break; - case 'M': // RI - debug("ESC M : R is "+R+", tm is "+getTopMargin()+", bm is "+getBottomMargin()); - if (R > getTopMargin()) { // just go up 1 line. - R--; - } else { // scroll down - insertLine(R, 1, SCROLL_DOWN); - } - /* else do nothing ; */ - if (debug > 2) - debug("ESC M "); - break; - case 'H': - if (debug > 1) - debug("ESC H at " + C); - /* right border probably ...*/ - if (C >= columns) - C = columns - 1; - Tabs[C] = 1; - break; - case 'N': // SS2 - onegl = 2; - break; - case 'O': // SS3 - onegl = 3; - break; - case '=': - /*application keypad*/ - if (debug > 0) - debug("ESC ="); - keypadmode = true; - break; - case '<': /* vt52 mode off */ - vt52mode = false; - break; - case '>': /*normal keypad*/ - if (debug > 0) - debug("ESC >"); - keypadmode = false; - break; - case '7': /* DECSC: save cursor, attributes */ - Sc = C; - Sr = R; - Sgl = gl; - Sgr = gr; - Sa = attributes; - Sgx = new char[4]; - for (int i = 0; i < 4; i++) Sgx[i] = gx[i]; - if (debug > 1) - debug("ESC 7"); - break; - case '8': /* DECRC: restore cursor, attributes */ - C = Sc; - R = Sr; - gl = Sgl; - gr = Sgr; - if (Sgx != null) - for (int i = 0; i < 4; i++) gx[i] = Sgx[i]; - attributes = Sa; - if (debug > 1) - debug("ESC 8"); - break; - case '(': /* Designate G0 Character set (ISO 2022) */ - term_state = TSTATE_SETG0; - usedcharsets = true; - break; - case ')': /* Designate G1 character set (ISO 2022) */ - term_state = TSTATE_SETG1; - usedcharsets = true; - break; - case '*': /* Designate G2 Character set (ISO 2022) */ - term_state = TSTATE_SETG2; - usedcharsets = true; - break; - case '+': /* Designate G3 Character set (ISO 2022) */ - term_state = TSTATE_SETG3; - usedcharsets = true; - break; - case '~': /* Locking Shift 1, right */ - gr = 1; - usedcharsets = true; - break; - case 'n': /* Locking Shift 2 */ - gl = 2; - usedcharsets = true; - break; - case '}': /* Locking Shift 2, right */ - gr = 2; - usedcharsets = true; - break; - case 'o': /* Locking Shift 3 */ - gl = 3; - usedcharsets = true; - break; - case '|': /* Locking Shift 3, right */ - gr = 3; - usedcharsets = true; - break; - case 'Y': /* vt52 cursor address mode , next chars are x,y */ - term_state = TSTATE_VT52Y; - break; - case '_': - term_state = TSTATE_TITLE; - break; - case '\\': - // TODO save title - term_state = TSTATE_DATA; - break; - default: - debug("ESC unknown letter: " + c + " (" + ((int) c) + ")"); - break; - } - break; - case TSTATE_VT52X: - C = c - 37; - if (C < 0) - C = 0; - else if (C >= width) - C = width - 1; - term_state = TSTATE_VT52Y; - break; - case TSTATE_VT52Y: - R = c - 37; - if (R < 0) - R = 0; - else if (R >= height) - R = height - 1; - term_state = TSTATE_DATA; - break; - case TSTATE_SETG0: - if (c != '0' && c != 'A' && c != 'B' && c != '<') - debug("ESC ( " + c + ": G0 char set? (" + ((int) c) + ")"); - else { - if (debug > 2) debug("ESC ( : G0 char set (" + c + " " + ((int) c) + ")"); - gx[0] = c; - } - term_state = TSTATE_DATA; - break; - case TSTATE_SETG1: - if (c != '0' && c != 'A' && c != 'B' && c != '<') { - debug("ESC ) " + c + " (" + ((int) c) + ") :G1 char set?"); - } else { - if (debug > 2) debug("ESC ) :G1 char set (" + c + " " + ((int) c) + ")"); - gx[1] = c; - } - term_state = TSTATE_DATA; - break; - case TSTATE_SETG2: - if (c != '0' && c != 'A' && c != 'B' && c != '<') - debug("ESC*:G2 char set? (" + ((int) c) + ")"); - else { - if (debug > 2) debug("ESC*:G2 char set (" + c + " " + ((int) c) + ")"); - gx[2] = c; - } - term_state = TSTATE_DATA; - break; - case TSTATE_SETG3: - if (c != '0' && c != 'A' && c != 'B' && c != '<') - debug("ESC+:G3 char set? (" + ((int) c) + ")"); - else { - if (debug > 2) debug("ESC+:G3 char set (" + c + " " + ((int) c) + ")"); - gx[3] = c; - } - term_state = TSTATE_DATA; - break; - case TSTATE_ESCSQUARE: - switch (c) { - case '8': - for (int i = 0; i < columns; i++) - for (int j = 0; j < rows; j++) - putChar(i, j, 'E', 0); - break; - default: - debug("ESC # " + c + " not supported."); - break; - } - term_state = TSTATE_DATA; - break; - case TSTATE_DCS: - if (c == '\\' && dcs.charAt(dcs.length() - 1) == ESC) { - handle_dcs(dcs); - term_state = TSTATE_DATA; - break; - } - dcs = dcs + c; - break; - - case TSTATE_DCEQ: - term_state = TSTATE_DATA; - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48; - term_state = TSTATE_DCEQ; - break; - case ';': - DCEvar++; - DCEvars[DCEvar] = 0; - term_state = TSTATE_DCEQ; - break; - case 's': // XTERM_SAVE missing! - if (true || debug > 1) - debug("ESC [ ? " + DCEvars[0] + " s unimplemented!"); - break; - case 'r': // XTERM_RESTORE - if (true || debug > 1) - debug("ESC [ ? " + DCEvars[0] + " r"); - /* DEC Mode reset */ - for (int i = 0; i <= DCEvar; i++) { - switch (DCEvars[i]) { - case 3: /* 80 columns*/ - setScreenSize(80, height, true); - break; - case 4: /* scrolling mode, smooth */ - break; - case 5: /* light background */ - break; - case 6: /* DECOM (Origin Mode) move inside margins. */ - moveoutsidemargins = true; - break; - case 7: /* DECAWM: Autowrap Mode */ - wraparound = false; - break; - case 12:/* local echo off */ - break; - case 9: /* X10 mouse */ - case 1000: /* xterm style mouse report on */ - case 1001: - case 1002: - case 1003: - mouserpt = DCEvars[i]; - break; - default: - debug("ESC [ ? " + DCEvars[0] + " r, unimplemented!"); - } - } - break; - case 'h': // DECSET - if (debug > 0) - debug("ESC [ ? " + DCEvars[0] + " h"); - /* DEC Mode set */ - for (int i = 0; i <= DCEvar; i++) { - switch (DCEvars[i]) { - case 1: /* Application cursor keys */ - KeyUp[0] = "\u001bOA"; - KeyDown[0] = "\u001bOB"; - KeyRight[0] = "\u001bOC"; - KeyLeft[0] = "\u001bOD"; - break; - case 2: /* DECANM */ - vt52mode = false; - break; - case 3: /* 132 columns*/ - setScreenSize(132, height, true); - break; - case 6: /* DECOM: move inside margins. */ - moveoutsidemargins = false; - break; - case 7: /* DECAWM: Autowrap Mode */ - wraparound = true; - break; - case 25: /* turn cursor on */ - showCursor(true); - break; - case 9: /* X10 mouse */ - case 1000: /* xterm style mouse report on */ - case 1001: - case 1002: - case 1003: - mouserpt = DCEvars[i]; - break; - - /* unimplemented stuff, fall through */ - /* 4 - scrolling mode, smooth */ - /* 5 - light background */ - /* 12 - local echo off */ - /* 18 - DECPFF - Printer Form Feed Mode -> On */ - /* 19 - DECPEX - Printer Extent Mode -> Screen */ - default: - debug("ESC [ ? " + DCEvars[0] + " h, unsupported."); - break; - } - } - break; - case 'i': // DEC Printer Control, autoprint, echo screenchars to printer - // This is different to CSI i! - // Also: "Autoprint prints a final display line only when the - // cursor is moved off the line by an autowrap or LF, FF, or - // VT (otherwise do not print the line)." - switch (DCEvars[0]) { - case 1: - if (debug > 1) - debug("CSI ? 1 i : Print line containing cursor"); - break; - case 4: - if (debug > 1) - debug("CSI ? 4 i : Start passthrough printing"); - break; - case 5: - if (debug > 1) - debug("CSI ? 4 i : Stop passthrough printing"); - break; - } - break; - case 'l': //DECRST - /* DEC Mode reset */ - if (debug > 0) - debug("ESC [ ? " + DCEvars[0] + " l"); - for (int i = 0; i <= DCEvar; i++) { - switch (DCEvars[i]) { - case 1: /* Application cursor keys */ - KeyUp[0] = "\u001b[A"; - KeyDown[0] = "\u001b[B"; - KeyRight[0] = "\u001b[C"; - KeyLeft[0] = "\u001b[D"; - break; - case 2: /* DECANM */ - vt52mode = true; - break; - case 3: /* 80 columns*/ - setScreenSize(80, height, true); - break; - case 6: /* DECOM: move outside margins. */ - moveoutsidemargins = true; - break; - case 7: /* DECAWM: Autowrap Mode OFF */ - wraparound = false; - break; - case 25: /* turn cursor off */ - showCursor(false); - break; - /* Unimplemented stuff: */ - /* 4 - scrolling mode, jump */ - /* 5 - dark background */ - /* 7 - DECAWM - no wrap around mode */ - /* 12 - local echo on */ - /* 18 - DECPFF - Printer Form Feed Mode -> Off*/ - /* 19 - DECPEX - Printer Extent Mode -> Scrolling Region */ - case 9: /* X10 mouse */ - case 1000: /* xterm style mouse report OFF */ - case 1001: - case 1002: - case 1003: - mouserpt = 0; - break; - default: - debug("ESC [ ? " + DCEvars[0] + " l, unsupported."); - break; - } - } - break; - case 'n': - if (debug > 0) - debug("ESC [ ? " + DCEvars[0] + " n"); - switch (DCEvars[0]) { - case 15: - /* printer? no printer. */ - write((ESC) + "[?13n", false); - debug("ESC[5n"); - break; - default: - debug("ESC [ ? " + DCEvars[0] + " n, unsupported."); - break; - } - break; - default: - debug("ESC [ ? " + DCEvars[0] + " " + c + ", unsupported."); - break; - } - break; - case TSTATE_CSI_EX: - term_state = TSTATE_DATA; - switch (c) { - case ESC: - term_state = TSTATE_ESC; - break; - default: - debug("Unknown character ESC[! character is " + (int) c); - break; - } - break; - case TSTATE_CSI_TICKS: - term_state = TSTATE_DATA; - switch (c) { - case 'p': - debug("Conformance level: " + DCEvars[0] + " (unsupported)," + DCEvars[1]); - if (DCEvars[0] == 61) { - output8bit = false; - break; - } - if (DCEvars[1] == 1) { - output8bit = false; - } else { - output8bit = true; /* 0 or 2 */ - } - break; - default: - debug("Unknown ESC [... \"" + c); - break; - } - break; - case TSTATE_CSI_EQUAL: - term_state = TSTATE_DATA; - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48; - term_state = TSTATE_CSI_EQUAL; - break; - case ';': - DCEvar++; - DCEvars[DCEvar] = 0; - term_state = TSTATE_CSI_EQUAL; - break; - - case 'F': /* SCO ANSI foreground */ - { - int newcolor; - - debug("ESC [ = "+DCEvars[0]+" F"); - - attributes &= ~COLOR_FG; - newcolor = ((DCEvars[0] & 1) << 2) | - (DCEvars[0] & 2) | - ((DCEvars[0] & 4) >> 2) ; - attributes |= (newcolor+1) << COLOR_FG_SHIFT; - - break; - } - case 'G': /* SCO ANSI background */ - { - int newcolor; - - debug("ESC [ = "+DCEvars[0]+" G"); - - attributes &= ~COLOR_BG; - newcolor = ((DCEvars[0] & 1) << 2) | - (DCEvars[0] & 2) | - ((DCEvars[0] & 4) >> 2) ; - attributes |= (newcolor+1) << COLOR_BG_SHIFT; - break; - } - - default: - debugStr.append("Unknown ESC [ = "); - for (int i=0;i<=DCEvar;i++) { - debugStr.append(DCEvars[i]) - .append(','); - } - debugStr.append(c); - debug(debugStr.toString()); - debugStr.setLength(0); - break; - } - break; - case TSTATE_CSI_DOLLAR: - term_state = TSTATE_DATA; - switch (c) { - case '}': - debug("Active Status Display now " + DCEvars[0]); - statusmode = DCEvars[0]; - break; - /* bad documentation? - case '-': - debug("Set Status Display now "+DCEvars[0]); - break; - */ - case '~': - debug("Status Line mode now " + DCEvars[0]); - break; - default: - debug("UNKNOWN Status Display code " + c + ", with Pn=" + DCEvars[0]); - break; - } - break; - case TSTATE_CSI: - term_state = TSTATE_DATA; - switch (c) { - case '"': - term_state = TSTATE_CSI_TICKS; - break; - case '$': - term_state = TSTATE_CSI_DOLLAR; - break; - case '=': - term_state = TSTATE_CSI_EQUAL; - break; - case '!': - term_state = TSTATE_CSI_EX; - break; - case '?': - DCEvar = 0; - DCEvars[0] = 0; - term_state = TSTATE_DCEQ; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - DCEvars[DCEvar] = DCEvars[DCEvar] * 10 + (c) - 48; - term_state = TSTATE_CSI; - break; - case ';': - DCEvar++; - DCEvars[DCEvar] = 0; - term_state = TSTATE_CSI; - break; - case 'c':/* send primary device attributes */ - /* send (ESC[?61c) */ - - String subcode = ""; - if (terminalID.equals("vt320")) subcode = "63;"; - if (terminalID.equals("vt220")) subcode = "62;"; - if (terminalID.equals("vt100")) subcode = "61;"; - write((ESC) + "[?" + subcode + "1;2c", false); - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " c"); - break; - case 'q': - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " q"); - break; - case 'g': - /* used for tabsets */ - switch (DCEvars[0]) { - case 3:/* clear them */ - Tabs = new byte[width]; - break; - case 0: - Tabs[C] = 0; - break; - } - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " g"); - break; - case 'h': - switch (DCEvars[0]) { - case 4: - insertmode = 1; - break; - case 20: - debug("Setting CRLF to TRUE"); - sendcrlf = true; - break; - default: - debug("unsupported: ESC [ " + DCEvars[0] + " h"); - break; - } - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " h"); - break; - case 'i': // Printer Controller mode. - // "Transparent printing sends all output, except the CSI 4 i - // termination string, to the printer and not the screen, - // uses an 8-bit channel if no parity so NUL and DEL will be - // seen by the printer and by the termination recognizer code, - // and all translation and character set selections are - // bypassed." - switch (DCEvars[0]) { - case 0: - if (debug > 1) - debug("CSI 0 i: Print Screen, not implemented."); - break; - case 4: - if (debug > 1) - debug("CSI 4 i: Enable Transparent Printing, not implemented."); - break; - case 5: - if (debug > 1) - debug("CSI 4/5 i: Disable Transparent Printing, not implemented."); - break; - default: - debug("ESC [ " + DCEvars[0] + " i, unimplemented!"); - } - break; - case 'l': - switch (DCEvars[0]) { - case 4: - insertmode = 0; - break; - case 20: - debug("Setting CRLF to FALSE"); - sendcrlf = false; - break; - default: - debug("ESC [ " + DCEvars[0] + " l, unimplemented!"); - break; - } - break; - case 'A': // CUU - { - int limit; - /* FIXME: xterm only cares about 0 and topmargin */ - if (R >= getTopMargin()) { - limit = getTopMargin(); - } else - limit = 0; - if (DCEvars[0] == 0) - R--; - else - R -= DCEvars[0]; - if (R < limit) - R = limit; - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " A"); - break; - } - case 'B': // CUD - /* cursor down n (1) times */ - { - int limit; - if (R <= getBottomMargin()) { - limit = getBottomMargin(); - } else - limit = rows - 1; - if (DCEvars[0] == 0) - R++; - else - R += DCEvars[0]; - if (R > limit) - R = limit; - else { - if (debug > 2) debug("Not limited."); - } - if (debug > 2) debug("to: " + R); - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " B (at C=" + C + ")"); - break; - } - case 'C': - if (DCEvars[0] == 0) - DCEvars[0] = 1; - while (DCEvars[0]-- > 0) { - C++; - } - if (C >= columns) - C = columns - 1; - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " C"); - break; - case 'd': // CVA - R = DCEvars[0] - 1; - if (R < 0) - R = 0; - else if (R >= height) - R = height - 1; - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " d"); - break; - case 'D': - if (DCEvars[0] == 0) - DCEvars[0] = 1; - while (DCEvars[0]-- > 0) { - C--; - } - if (C < 0) C = 0; - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " D"); - break; - case 'r': // DECSTBM - if (DCEvar > 0) // Ray: Any argument is optional - { - R = DCEvars[1] - 1; - if (R < 0) - R = rows - 1; - else if (R >= rows) { - R = rows - 1; - } - } else - R = rows - 1; - int bot = R; - if (R >= DCEvars[0]) { - R = DCEvars[0] - 1; - if (R < 0) - R = 0; - } - setMargins(R, bot); - _SetCursor(0, 0); - if (debug > 1) - debug("ESC [" + DCEvars[0] + " ; " + DCEvars[1] + " r"); - break; - case 'G': /* CUP / cursor absolute column */ - C = DCEvars[0]; - if (C < 0) - C = 0; - else if (C >= width) - C = width - 1; - if (debug > 1) debug("ESC [ " + DCEvars[0] + " G"); - break; - case 'H': /* CUP / cursor position */ - /* gets 2 arguments */ - _SetCursor(DCEvars[0] - 1, DCEvars[1] - 1); - if (debug > 2) { - debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " H, moveoutsidemargins " + moveoutsidemargins); - debug(" -> R now " + R + ", C now " + C); - } - break; - case 'f': /* move cursor 2 */ - /* gets 2 arguments */ - R = DCEvars[0] - 1; - C = DCEvars[1] - 1; - if (C < 0) - C = 0; - else if (C >= width) - C = width - 1; - if (R < 0) - R = 0; - else if (R >= height) - R = height - 1; - if (debug > 2) - debug("ESC [ " + DCEvars[0] + ";" + DCEvars[1] + " f"); - break; - case 'S': /* ind aka 'scroll forward' */ - if (DCEvars[0] == 0) - insertLine(getBottomMargin(), SCROLL_UP); - else - insertLine(getBottomMargin(), DCEvars[0], SCROLL_UP); - break; - case 'L': - /* insert n lines */ - if (DCEvars[0] == 0) - insertLine(R, SCROLL_DOWN); - else - insertLine(R, DCEvars[0], SCROLL_DOWN); - if (debug > 1) - debug("ESC [ " + DCEvars[0] + "" + (c) + " (at R " + R + ")"); - break; - case 'T': /* 'ri' aka scroll backward */ - if (DCEvars[0] == 0) - insertLine(getTopMargin(), SCROLL_DOWN); - else - insertLine(getTopMargin(), DCEvars[0], SCROLL_DOWN); - break; - case 'M': - if (debug > 1) - debug("ESC [ " + DCEvars[0] + "" + (c) + " at R=" + R); - if (DCEvars[0] == 0) - deleteLine(R); - else - for (int i = 0; i < DCEvars[0]; i++) - deleteLine(R); - break; - case 'K': - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " K"); - /* clear in line */ - switch (DCEvars[0]) { - case 6: /* 97801 uses ESC[6K for delete to end of line */ - case 0:/*clear to right*/ - if (C < columns - 1) - deleteArea(C, R, columns - C, 1, attributes); - break; - case 1:/*clear to the left, including this */ - if (C > 0) - deleteArea(0, R, C + 1, 1, attributes); - break; - case 2:/*clear whole line */ - deleteArea(0, R, columns, 1, attributes); - break; - } - break; - case 'J': - /* clear below current line */ - switch (DCEvars[0]) { - case 0: - if (R < rows - 1) - deleteArea(0, R + 1, columns, rows - R - 1, attributes); - if (C < columns - 1) - deleteArea(C, R, columns - C, 1, attributes); - break; - case 1: - if (R > 0) - deleteArea(0, 0, columns, R, attributes); - if (C > 0) - deleteArea(0, R, C + 1, 1, attributes);// include up to and including current - break; - case 2: - deleteArea(0, 0, columns, rows, attributes); - break; - } - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " J"); - break; - case '@': - if (DCEvars[0] == 0) DCEvars[0] = 1; - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " @"); - for (int i = 0; i < DCEvars[0]; i++) - insertChar(C, R, ' ', attributes); - break; - case 'X': - { - int toerase = DCEvars[0]; - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " X, C=" + C + ",R=" + R); - if (toerase == 0) - toerase = 1; - if (toerase + C > columns) - toerase = columns - C; - deleteArea(C, R, toerase, 1, attributes); - // does not change cursor position - break; - } - case 'P': - if (debug > 1) - debug("ESC [ " + DCEvars[0] + " P, C=" + C + ",R=" + R); - if (DCEvars[0] == 0) DCEvars[0] = 1; - for (int i = 0; i < DCEvars[0]; i++) - deleteChar(C, R); - break; - case 'n': - switch (DCEvars[0]) { - case 5: /* malfunction? No malfunction. */ - writeSpecial((ESC) + "[0n"); - if (debug > 1) - debug("ESC[5n"); - break; - case 6: - // DO NOT offset R and C by 1! (checked against /usr/X11R6/bin/resize - // FIXME check again. - // FIXME: but vttest thinks different??? - writeSpecial((ESC) + "[" + R + ";" + C + "R"); - if (debug > 1) - debug("ESC[6n"); - break; - default: - if (debug > 0) - debug("ESC [ " + DCEvars[0] + " n??"); - break; - } - break; - case 's': /* DECSC - save cursor */ - Sc = C; - Sr = R; - Sa = attributes; - if (debug > 3) - debug("ESC[s"); - break; - case 'u': /* DECRC - restore cursor */ - C = Sc; - R = Sr; - attributes = Sa; - if (debug > 3) - debug("ESC[u"); - break; - case 'm': /* attributes as color, bold , blink,*/ - if (debug > 3) - debug("ESC [ "); - if (DCEvar == 0 && DCEvars[0] == 0) - attributes = 0; - for (int i = 0; i <= DCEvar; i++) { - switch (DCEvars[i]) { - case 0: - if (DCEvar > 0) { - if (terminalID.equals("scoansi")) { - attributes &= COLOR; /* Keeps color. Strange but true. */ - } else { - attributes = 0; - } - } - break; - case 1: - attributes |= BOLD; - attributes &= ~LOW; - break; - case 2: - /* SCO color hack mode */ - if (terminalID.equals("scoansi") && ((DCEvar - i) >= 2)) { - int ncolor; - attributes &= ~(COLOR | BOLD); - - ncolor = DCEvars[i + 1]; - if ((ncolor & 8) == 8) - attributes |= BOLD; - ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2); - attributes |= ((ncolor) + 1) << COLOR_FG_SHIFT; - ncolor = DCEvars[i + 2]; - ncolor = ((ncolor & 1) << 2) | (ncolor & 2) | ((ncolor & 4) >> 2); - attributes |= ((ncolor) + 1) << COLOR_BG_SHIFT; - i += 2; - } else { - attributes |= LOW; - } - break; - case 3: /* italics */ - attributes |= INVERT; - break; - case 4: - attributes |= UNDERLINE; - break; - case 7: - attributes |= INVERT; - break; - case 8: - attributes |= INVISIBLE; - break; - case 5: /* blink on */ - break; - /* 10 - ANSI X3.64-1979, select primary font, don't display control - * chars, don't set bit 8 on output */ - case 10: - gl = 0; - usedcharsets = true; - break; - /* 11 - ANSI X3.64-1979, select second alt. font, display control - * chars, set bit 8 on output */ - case 11: /* SMACS , as */ - case 12: - gl = 1; - usedcharsets = true; - break; - case 21: /* normal intensity */ - attributes &= ~(LOW | BOLD); - break; - case 23: /* italics off */ - attributes &= ~INVERT; - break; - case 25: /* blinking off */ - break; - case 27: - attributes &= ~INVERT; - break; - case 28: - attributes &= ~INVISIBLE; - break; - case 24: - attributes &= ~UNDERLINE; - break; - case 22: - attributes &= ~BOLD; - break; - case 30: - case 31: - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - attributes &= ~COLOR_FG; - attributes |= ((DCEvars[i] - 30) + 1)<< COLOR_FG_SHIFT; - break; - case 38: - if (DCEvars[i+1] == 5) { - attributes &= ~COLOR_FG; - attributes |= ((DCEvars[i + 2]) + 1) << COLOR_FG_SHIFT; - i += 2; - } - break; - case 39: - attributes &= ~COLOR_FG; - break; - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - attributes &= ~COLOR_BG; - attributes |= ((DCEvars[i] - 40) + 1) << COLOR_BG_SHIFT; - break; - case 48: - if (DCEvars[i+1] == 5) { - attributes &= ~COLOR_BG; - attributes |= (DCEvars[i + 2] + 1) << COLOR_BG_SHIFT; - i += 2; - } - break; - case 49: - attributes &= ~COLOR_BG; - break; - case 90: - case 91: - case 92: - case 93: - case 94: - case 95: - case 96: - case 97: - attributes &= ~COLOR_FG; - attributes |= ((DCEvars[i] - 82) + 1) << COLOR_FG_SHIFT; - break; - case 100: - case 101: - case 102: - case 103: - case 104: - case 105: - case 106: - case 107: - attributes &= ~COLOR_BG; - attributes |= ((DCEvars[i] - 92) + 1) << COLOR_BG_SHIFT; - break; - - default: - debugStr.append("ESC [ ") - .append(DCEvars[i]) - .append(" m unknown..."); - debug(debugStr.toString()); - debugStr.setLength(0); - break; - } - if (debug > 3) { - debugStr.append(DCEvars[i]) - .append(';'); - debug(debugStr.toString()); - debugStr.setLength(0); - } - } - if (debug > 3) { - debugStr.append(" (attributes = ") - .append(attributes) - .append(")m"); - debug(debugStr.toString()); - debugStr.setLength(0); - } - break; - default: - debugStr.append("ESC [ unknown letter: ") - .append(c) - .append(" (") - .append((int)c) - .append(')'); - debug(debugStr.toString()); - debugStr.setLength(0); - break; - } - break; - case TSTATE_TITLE: - switch (c) { - case ESC: - term_state = TSTATE_ESC; - break; - default: - // TODO save title - break; - } - break; - default: - term_state = TSTATE_DATA; - break; - } - - setCursorPosition(C, R); - } - - /* hard reset the terminal */ - public void reset() { - gx[0] = 'B'; - gx[1] = 'B'; - gx[2] = 'B'; - gx[3] = 'B'; - - gl = 0; // default GL to G0 - gr = 2; // default GR to G2 - - onegl = -1; // Single shift override - - /* reset tabs */ - int nw = width; - if (nw < 132) nw = 132; - Tabs = new byte[nw]; - for (int i = 0; i < nw; i += 8) { - Tabs[i] = 1; - } - - deleteArea(0, 0, width, height, attributes); - setMargins(0, height); - C = R = 0; - _SetCursor(0, 0); - - if (display != null) - display.resetColors(); - - showCursor(true); - /*FIXME:*/ - term_state = TSTATE_DATA; - } -} diff --git a/src/net/sourceforge/jsocks/Authentication.java b/src/net/sourceforge/jsocks/Authentication.java deleted file mode 100644 index 18cc48b..0000000 --- a/src/net/sourceforge/jsocks/Authentication.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.sourceforge.jsocks; - -/** - The Authentication interface provides for performing method specific - authentication for SOCKS5 connections. -*/ -public interface Authentication{ - /** - This method is called when SOCKS5 server have selected a particular - authentication method, for whch an implementaion have been registered. - - <p> - This method should return an array {inputstream,outputstream - [,UDPEncapsulation]}. The reason for that is that SOCKS5 protocol - allows to have method specific encapsulation of data on the socket for - purposes of integrity or security. And this encapsulation should be - performed by those streams returned from the method. It is also possible - to encapsulate datagrams. If authentication method supports such - encapsulation an instance of the UDPEncapsulation interface should be - returned as third element of the array, otherwise either null should be - returned as third element, or array should contain only 2 elements. - - @param methodId Authentication method selected by the server. - @param proxySocket Socket used to conect to the proxy. - @return Two or three element array containing - Input/Output streams which should be used on this connection. - Third argument is optional and should contain an instance - of UDPEncapsulation. It should be provided if the authentication - method used requires any encapsulation to be done on the - datagrams. - */ - Object[] doSocksAuthentication(int methodId,java.net.Socket proxySocket) - throws java.io.IOException; -} diff --git a/src/net/sourceforge/jsocks/AuthenticationNone.java b/src/net/sourceforge/jsocks/AuthenticationNone.java deleted file mode 100644 index f28193a..0000000 --- a/src/net/sourceforge/jsocks/AuthenticationNone.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.sourceforge.jsocks; - -/** - SOCKS5 none authentication. Dummy class does almost nothing. -*/ -public class AuthenticationNone implements Authentication{ - - public Object[] doSocksAuthentication(int methodId, - java.net.Socket proxySocket) - throws java.io.IOException{ - - if(methodId!=0) return null; - - return new Object[] { proxySocket.getInputStream(), - proxySocket.getOutputStream()}; - } -} diff --git a/src/net/sourceforge/jsocks/Proxy.java b/src/net/sourceforge/jsocks/Proxy.java deleted file mode 100644 index 381c0a0..0000000 --- a/src/net/sourceforge/jsocks/Proxy.java +++ /dev/null @@ -1,404 +0,0 @@ -package net.sourceforge.jsocks; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; - -/** - Abstract class Proxy, base for classes Socks4Proxy and Socks5Proxy. - Defines methods for specifying default proxy, to be - used by all classes of this package. -*/ - -public abstract class Proxy{ - -//Data members - //protected InetRange directHosts = new InetRange(); - - protected InetAddress proxyIP = null; - protected String proxyHost = null; - protected int proxyPort; - protected Socket proxySocket = null; - - protected InputStream in; - protected OutputStream out; - - protected int version; - - protected Proxy chainProxy = null; - - -//Protected static/class variables - protected static Proxy defaultProxy = null; - -//Constructors -//==================== - Proxy(String proxyHost, int proxyPort) throws UnknownHostException { - this.proxyHost = proxyHost; - this.proxyIP = InetAddress.getByName(proxyHost); - this.proxyPort = proxyPort; - } - - Proxy(Proxy chainProxy,InetAddress proxyIP,int proxyPort){ - this.chainProxy = chainProxy; - this.proxyIP = proxyIP; - this.proxyPort = proxyPort; - } - - Proxy(InetAddress proxyIP,int proxyPort){ - this.proxyIP = proxyIP; - this.proxyPort = proxyPort; - } - - Proxy(Proxy p){ - this.proxyIP = p.proxyIP; - this.proxyPort = p.proxyPort; - this.version = p.version; - } - -//Public instance methods -//======================== - - /** - Get the port on which proxy server is running. - * @return Proxy port. - */ - public int getPort(){ - return proxyPort; - } - /** - Get the ip address of the proxy server host. - * @return Proxy InetAddress. - */ - public InetAddress getInetAddress(){ - return proxyIP; - } - - /** - Get string representation of this proxy. - * @returns string in the form:proxyHost:proxyPort \t Version versionNumber - */ - public String toString(){ - return (""+proxyIP.getHostName()+":"+proxyPort+"\tVersion "+version); - } - - -//Public Static(Class) Methods -//============================== - - /** - * Sets SOCKS4 proxy as default. - @param hostName Host name on which SOCKS4 server is running. - @param port Port on which SOCKS4 server is running. - @param user Username to use for communications with proxy. - */ - public static void setDefaultProxy(String hostName,int port,String user) - throws UnknownHostException{ - defaultProxy = new Socks4Proxy(hostName,port,user); - } - - /** - * Sets SOCKS4 proxy as default. - @param ipAddress Host address on which SOCKS4 server is running. - @param port Port on which SOCKS4 server is running. - @param user Username to use for communications with proxy. - */ - public static void setDefaultProxy(InetAddress ipAddress,int port, - String user){ - defaultProxy = new Socks4Proxy(ipAddress,port,user); - } - /** - * Sets SOCKS5 proxy as default. - * Default proxy only supports no-authentication. - @param hostName Host name on which SOCKS5 server is running. - @param port Port on which SOCKS5 server is running. - */ - public static void setDefaultProxy(String hostName,int port) - throws UnknownHostException{ - defaultProxy = new Socks5Proxy(hostName,port); - } - /** - * Sets SOCKS5 proxy as default. - * Default proxy only supports no-authentication. - @param ipAddress Host address on which SOCKS5 server is running. - @param port Port on which SOCKS5 server is running. - */ - public static void setDefaultProxy(InetAddress ipAddress,int port){ - defaultProxy = new Socks5Proxy(ipAddress,port); - } - /** - * Sets default proxy. - @param p Proxy to use as default proxy. - */ - public static void setDefaultProxy(Proxy p){ - defaultProxy = p; - } - - /** - Get current default proxy. - * @return Current default proxy, or null if none is set. - */ - public static Proxy getDefaultProxy(){ - return defaultProxy; - } - - /** - Parses strings in the form: host[:port:user:password], and creates - proxy from information obtained from parsing. - <p> - Defaults: port = 1080.<br> - If user specified but not password, creates Socks4Proxy, if user - not specified creates Socks5Proxy, if both user and password are - speciefied creates Socks5Proxy with user/password authentication. - @param proxy_entry String in the form host[:port:user:password] - @return Proxy created from the string, null if entry was somehow - invalid(host unknown for example, or empty string) - */ - public static Proxy parseProxy(String proxy_entry){ - - String proxy_host; - int proxy_port = 1080; - String proxy_user = null; - String proxy_password = null; - Proxy proxy; - - java.util.StringTokenizer st = new java.util.StringTokenizer( - proxy_entry,":"); - if(st.countTokens() < 1) return null; - - proxy_host = st.nextToken(); - if(st.hasMoreTokens()) - try{ - proxy_port = Integer.parseInt(st.nextToken().trim()); - }catch(NumberFormatException nfe){} - - if(st.hasMoreTokens()) - proxy_user = st.nextToken(); - - if(st.hasMoreTokens()) - proxy_password = st.nextToken(); - - try{ - if(proxy_user == null) - proxy = new Socks5Proxy(proxy_host,proxy_port); - else if(proxy_password == null) - proxy = new Socks4Proxy(proxy_host,proxy_port,proxy_user); - else{ - proxy = new Socks5Proxy(proxy_host,proxy_port); - /* - UserPasswordAuthentication upa = new UserPasswordAuthentication( - proxy_user, proxy_password); - - ((Socks5Proxy)proxy).setAuthenticationMethod(upa.METHOD_ID,upa); - */ - } - }catch(UnknownHostException uhe){ - return null; - } - - return proxy; - } - - -//Protected Methods -//================= - - protected void startSession()throws SocksException{ - try{ - proxySocket = new Socket(proxyIP,proxyPort); - in = proxySocket.getInputStream(); - out = proxySocket.getOutputStream(); - }catch(SocksException se){ - throw se; - }catch(IOException io_ex){ - throw new SocksException(SOCKS_PROXY_IO_ERROR,""+io_ex); - } - } - - protected abstract Proxy copy(); - protected abstract ProxyMessage formMessage(int cmd,InetAddress ip,int port); - protected abstract ProxyMessage formMessage(int cmd,String host,int port) - throws UnknownHostException; - protected abstract ProxyMessage formMessage(InputStream in) - throws SocksException, - IOException; - - - protected ProxyMessage connect(InetAddress ip,int port) - throws SocksException{ - try{ - startSession(); - ProxyMessage request = formMessage(SOCKS_CMD_CONNECT, - ip,port); - return exchange(request); - }catch(SocksException se){ - endSession(); - throw se; - } - } - protected ProxyMessage connect(String host,int port) - throws UnknownHostException,SocksException{ - try{ - startSession(); - ProxyMessage request = formMessage(SOCKS_CMD_CONNECT, - host,port); - return exchange(request); - }catch(SocksException se){ - endSession(); - throw se; - } - } - - protected ProxyMessage bind(InetAddress ip,int port) - throws SocksException{ - try{ - startSession(); - ProxyMessage request = formMessage(SOCKS_CMD_BIND, - ip,port); - return exchange(request); - }catch(SocksException se){ - endSession(); - throw se; - } - } - protected ProxyMessage bind(String host,int port) - throws UnknownHostException,SocksException{ - try{ - startSession(); - ProxyMessage request = formMessage(SOCKS_CMD_BIND, - host,port); - return exchange(request); - }catch(SocksException se){ - endSession(); - throw se; - } - } - - protected ProxyMessage accept() - throws IOException,SocksException{ - ProxyMessage msg; - try{ - msg = formMessage(in); - }catch(InterruptedIOException iioe){ - throw iioe; - }catch(IOException io_ex){ - endSession(); - throw new SocksException(SOCKS_PROXY_IO_ERROR,"While Trying accept:" - +io_ex); - } - return msg; - } - - protected ProxyMessage udpAssociate(InetAddress ip,int port) - throws SocksException{ - try{ - startSession(); - ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE, - ip,port); - if(request != null) - return exchange(request); - }catch(SocksException se){ - endSession(); - throw se; - } - //Only get here if request was null - endSession(); - throw new SocksException(SOCKS_METHOD_NOTSUPPORTED, - "This version of proxy does not support UDP associate, use version 5"); - } - protected ProxyMessage udpAssociate(String host,int port) - throws UnknownHostException,SocksException{ - try{ - startSession(); - ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE, - host,port); - if(request != null) return exchange(request); - }catch(SocksException se){ - endSession(); - throw se; - } - //Only get here if request was null - endSession(); - throw new SocksException(SOCKS_METHOD_NOTSUPPORTED, - "This version of proxy does not support UDP associate, use version 5"); - } - - - protected void endSession(){ - try{ - if(proxySocket!=null) proxySocket.close(); - proxySocket = null; - }catch(IOException io_ex){ - } - } - - /** - *Sends the request to SOCKS server - */ - protected void sendMsg(ProxyMessage msg)throws SocksException, - IOException{ - msg.write(out); - } - - /** - * Reads the reply from the SOCKS server - */ - protected ProxyMessage readMsg()throws SocksException, - IOException{ - return formMessage(in); - } - /** - *Sends the request reads reply and returns it - *throws exception if something wrong with IO - *or the reply code is not zero - */ - protected ProxyMessage exchange(ProxyMessage request) - throws SocksException{ - ProxyMessage reply; - try{ - request.write(out); - reply = formMessage(in); - }catch(SocksException s_ex){ - throw s_ex; - }catch(IOException ioe){ - throw(new SocksException(SOCKS_PROXY_IO_ERROR,""+ioe)); - } - return reply; - } - - -//Private methods -//=============== - - -//Constants - - public static final int SOCKS_SUCCESS =0; - public static final int SOCKS_FAILURE =1; - public static final int SOCKS_BADCONNECT =2; - public static final int SOCKS_BADNETWORK =3; - public static final int SOCKS_HOST_UNREACHABLE =4; - public static final int SOCKS_CONNECTION_REFUSED =5; - public static final int SOCKS_TTL_EXPIRE =6; - public static final int SOCKS_CMD_NOT_SUPPORTED =7; - public static final int SOCKS_ADDR_NOT_SUPPORTED =8; - - public static final int SOCKS_NO_PROXY =1<<16; - public static final int SOCKS_PROXY_NO_CONNECT =2<<16; - public static final int SOCKS_PROXY_IO_ERROR =3<<16; - public static final int SOCKS_AUTH_NOT_SUPPORTED =4<<16; - public static final int SOCKS_AUTH_FAILURE =5<<16; - public static final int SOCKS_JUST_ERROR =6<<16; - - public static final int SOCKS_DIRECT_FAILED =7<<16; - public static final int SOCKS_METHOD_NOTSUPPORTED =8<<16; - - - public static final int SOCKS_CMD_CONNECT =0x1; - static final int SOCKS_CMD_BIND =0x2; - static final int SOCKS_CMD_UDP_ASSOCIATE =0x3; - -} diff --git a/src/net/sourceforge/jsocks/ProxyMessage.java b/src/net/sourceforge/jsocks/ProxyMessage.java deleted file mode 100644 index 442c380..0000000 --- a/src/net/sourceforge/jsocks/ProxyMessage.java +++ /dev/null @@ -1,109 +0,0 @@ -package net.sourceforge.jsocks; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - Abstract class which describes SOCKS4/5 response/request. -*/ -public abstract class ProxyMessage{ - /** Host as an IP address */ - public InetAddress ip=null; - /** SOCKS version, or version of the response for SOCKS4*/ - public int version; - /** Port field of the request/response*/ - public int port; - /** Request/response code as an int*/ - public int command; - /** Host as string.*/ - public String host=null; - /** User field for SOCKS4 request messages*/ - public String user=null; - - ProxyMessage(int command,InetAddress ip,int port){ - this.command = command; - this.ip = ip; - this.port = port; - } - - ProxyMessage(){ - } - - - /** - Initialises Message from the stream. Reads server response from - given stream. - @param in Input stream to read response from. - @throws SocksException If server response code is not SOCKS_SUCCESS(0), or - if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public abstract void read(InputStream in) - throws SocksException, - IOException; - - - /** - Initialises Message from the stream. Reads server response or client - request from given stream. - - @param in Input stream to read response from. - @param clinetMode If true read server response, else read client request. - @throws SocksException If server response code is not SOCKS_SUCCESS(0) and - reading in client mode, or if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public abstract void read(InputStream in,boolean client_mode) - throws SocksException, - IOException; - - - /** - Writes the message to the stream. - @param out Output stream to which message should be written. - */ - public abstract void write(OutputStream out)throws SocksException, - IOException; - - /** - Get the Address field of this message as InetAddress object. - @return Host address or null, if one can't be determined. - */ - public InetAddress getInetAddress() throws UnknownHostException{ - return ip; - } - - - /** - Get string representaion of this message. - @return string representation of this message. - */ - public String toString(){ - return - "Proxy Message:\n"+ - "Version:"+ version+"\n"+ - "Command:"+ command+"\n"+ - "IP: "+ ip+"\n"+ - "Port: "+ port+"\n"+ - "User: "+ user+"\n" ; - } - -//Package methods -////////////////// - - static final String bytes2IPV4(byte[] addr,int offset){ - String hostName = ""+(addr[offset] & 0xFF); - for(int i = offset+1;i<offset+4;++i) - hostName+="."+(addr[i] & 0xFF); - return hostName; - } - - static final String bytes2IPV6(byte[] addr,int offset){ - //Have no idea how they look like! - return null; - } - -} diff --git a/src/net/sourceforge/jsocks/ProxyServer.java b/src/net/sourceforge/jsocks/ProxyServer.java deleted file mode 100644 index 225149d..0000000 --- a/src/net/sourceforge/jsocks/ProxyServer.java +++ /dev/null @@ -1,591 +0,0 @@ -package net.sourceforge.jsocks; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.PushbackInputStream; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.NoRouteToHostException; -import java.net.ServerSocket; -import java.net.Socket; - -import net.sourceforge.jsocks.server.ServerAuthenticator; - -/** - SOCKS4 and SOCKS5 proxy, handles both protocols simultaniously. - Implements all SOCKS commands, including UDP relaying. - <p> - In order to use it you will need to implement ServerAuthenticator - interface. There is an implementation of this interface which does - no authentication ServerAuthenticatorNone, but it is very dangerous - to use, as it will give access to your local network to anybody - in the world. One should never use this authentication scheme unless - one have pretty good reason to do so. - There is a couple of other authentication schemes in socks.server package. - @see socks.server.ServerAuthenticator -*/ -public class ProxyServer implements Runnable{ - - ServerAuthenticator auth; - ProxyMessage msg = null; - - Socket sock=null,remote_sock=null; - ServerSocket ss=null; - UDPRelayServer relayServer = null; - InputStream in,remote_in; - OutputStream out,remote_out; - - int mode; - static final int START_MODE = 0; - static final int ACCEPT_MODE = 1; - static final int PIPE_MODE = 2; - static final int ABORT_MODE = 3; - - static final int BUF_SIZE = 8192; - - Thread pipe_thread1,pipe_thread2; - long lastReadTime; - - protected static int iddleTimeout = 180000; //3 minutes - static int acceptTimeout = 180000; //3 minutes - - static PrintStream log = null; - static Proxy proxy; - - -//Public Constructors -///////////////////// - - - /** - Creates a proxy server with given Authentication scheme. - @param auth Authentication scheme to be used. - */ - public ProxyServer(ServerAuthenticator auth){ - this.auth = auth; - } - -//Other constructors -//////////////////// - - protected ProxyServer(ServerAuthenticator auth,Socket s){ - this.auth = auth; - this.sock = s; - mode = START_MODE; - } - -//Public methods -///////////////// - - /** - Set the logging stream. Specifying null disables logging. - */ - public static void setLog(OutputStream out){ - if(out == null){ - log = null; - }else{ - log = new PrintStream(out,true); - } - - UDPRelayServer.log = log; - } - - /** - Set proxy. - <p> - Allows Proxy chaining so that one Proxy server is connected to another - and so on. If proxy supports SOCKSv4, then only some SOCKSv5 requests - can be handled, UDP would not work, however CONNECT and BIND will be - translated. - - @param p Proxy which should be used to handle user requests. - */ - public static void setProxy(Proxy p){ - proxy =p; - UDPRelayServer.proxy = proxy; - } - - /** - Get proxy. - @return Proxy wich is used to handle user requests. - */ - public static Proxy getProxy(){ - return proxy; - } - - /** - Sets the timeout for connections, how long shoud server wait - for data to arrive before dropping the connection.<br> - Zero timeout implies infinity.<br> - Default timeout is 3 minutes. - */ - public static void setIddleTimeout(int timeout){ - iddleTimeout = timeout; - } - /** - Sets the timeout for BIND command, how long the server should - wait for the incoming connection.<br> - Zero timeout implies infinity.<br> - Default timeout is 3 minutes. - */ - public static void setAcceptTimeout(int timeout){ - acceptTimeout = timeout; - } - - /** - Sets the timeout for UDPRelay server.<br> - Zero timeout implies infinity.<br> - Default timeout is 3 minutes. - */ - public static void setUDPTimeout(int timeout){ - UDPRelayServer.setTimeout(timeout); - } - - /** - Sets the size of the datagrams used in the UDPRelayServer.<br> - Default size is 64K, a bit more than maximum possible size of the - datagram. - */ - public static void setDatagramSize(int size){ - UDPRelayServer.setDatagramSize(size); - } - - - /** - Start the Proxy server at given port.<br> - This methods blocks. - */ - public void start(int port){ - start(port,5,null); - } - - /** - Create a server with the specified port, listen backlog, and local - IP address to bind to. The localIP argument can be used on a multi-homed - host for a ServerSocket that will only accept connect requests to one of - its addresses. If localIP is null, it will default accepting connections - on any/all local addresses. The port must be between 0 and 65535, - inclusive. <br> - This methods blocks. - */ - public void start(int port,int backlog,InetAddress localIP){ - try{ - ss = new ServerSocket(port,backlog,localIP); - log("Starting SOCKS Proxy on:"+ss.getInetAddress().getHostAddress()+":" - +ss.getLocalPort()); - while(true){ - Socket s = ss.accept(); - log("Accepted from:"+s.getInetAddress().getHostName()+":" - +s.getPort()); - ProxyServer ps = new ProxyServer(auth,s); - (new Thread(ps)).start(); - } - }catch(IOException ioe){ - ioe.printStackTrace(); - }finally{ - } - } - - /** - Stop server operation.It would be wise to interrupt thread running the - server afterwards. - */ - public void stop(){ - try{ - if(ss != null) ss.close(); - }catch(IOException ioe){ - } - } - -//Runnable interface -//////////////////// - public void run(){ - switch(mode){ - case START_MODE: - try{ - startSession(); - }catch(IOException ioe){ - handleException(ioe); - //ioe.printStackTrace(); - }finally{ - abort(); - if(auth!=null) auth.endSession(); - log("Main thread(client->remote)stopped."); - } - break; - case ACCEPT_MODE: - try{ - doAccept(); - mode = PIPE_MODE; - pipe_thread1.interrupt(); //Tell other thread that connection have - //been accepted. - pipe(remote_in,out); - }catch(IOException ioe){ - //log("Accept exception:"+ioe); - handleException(ioe); - }finally{ - abort(); - log("Accept thread(remote->client) stopped"); - } - break; - case PIPE_MODE: - try{ - pipe(remote_in,out); - }catch(IOException ioe){ - }finally{ - abort(); - log("Support thread(remote->client) stopped"); - } - break; - case ABORT_MODE: - break; - default: - log("Unexpected MODE "+mode); - } - } - -//Private methods -///////////////// - private void startSession() throws IOException{ - sock.setSoTimeout(iddleTimeout); - - try{ - auth = auth.startSession(sock); - }catch(IOException ioe){ - log("Auth throwed exception:"+ioe); - auth = null; - return; - } - - if(auth == null){ //Authentication failed - log("Authentication failed"); - return; - } - - in = auth.getInputStream(); - out = auth.getOutputStream(); - - msg = readMsg(in); - handleRequest(msg); - } - - protected void handleRequest(ProxyMessage msg) - throws IOException{ - if(!auth.checkRequest(msg)) throw new - SocksException(Proxy.SOCKS_FAILURE); - - if(msg.ip == null){ - if(msg instanceof Socks5Message){ - msg.ip = InetAddress.getByName(msg.host); - }else - throw new SocksException(Proxy.SOCKS_FAILURE); - } - log(msg); - - switch(msg.command){ - case Proxy.SOCKS_CMD_CONNECT: - onConnect(msg); - break; - case Proxy.SOCKS_CMD_BIND: - onBind(msg); - break; - case Proxy.SOCKS_CMD_UDP_ASSOCIATE: - onUDP(msg); - break; - default: - throw new SocksException(Proxy.SOCKS_CMD_NOT_SUPPORTED); - } - } - - private void handleException(IOException ioe){ - //If we couldn't read the request, return; - if(msg == null) return; - //If have been aborted by other thread - if(mode == ABORT_MODE) return; - //If the request was successfully completed, but exception happened later - if(mode == PIPE_MODE) return; - - int error_code = Proxy.SOCKS_FAILURE; - - if(ioe instanceof SocksException) - error_code = ((SocksException)ioe).errCode; - else if(ioe instanceof NoRouteToHostException) - error_code = Proxy.SOCKS_HOST_UNREACHABLE; - else if(ioe instanceof ConnectException) - error_code = Proxy.SOCKS_CONNECTION_REFUSED; - else if(ioe instanceof InterruptedIOException) - error_code = Proxy.SOCKS_TTL_EXPIRE; - - if(error_code > Proxy.SOCKS_ADDR_NOT_SUPPORTED || error_code < 0){ - error_code = Proxy.SOCKS_FAILURE; - } - - sendErrorMessage(error_code); - } - - private void onConnect(ProxyMessage msg) throws IOException{ - Socket s; - ProxyMessage response = null; - - s = new Socket(msg.ip,msg.port); - - log("Connected to "+s.getInetAddress()+":"+s.getPort()); - - if(msg instanceof Socks5Message){ - response = new Socks5Message(Proxy.SOCKS_SUCCESS, - s.getLocalAddress(), - s.getLocalPort()); - }else{ - response = new Socks4Message(Socks4Message.REPLY_OK, - s.getLocalAddress(),s.getLocalPort()); - - } - response.write(out); - startPipe(s); - } - - private void onBind(ProxyMessage msg) throws IOException{ - ProxyMessage response = null; - - if(proxy == null) - ss = new ServerSocket(0); - else - ss = new SocksServerSocket(proxy, msg.ip, msg.port); - - ss.setSoTimeout(acceptTimeout); - - log("Trying accept on "+ss.getInetAddress()+":"+ss.getLocalPort()); - - if(msg.version == 5) - response = new Socks5Message(Proxy.SOCKS_SUCCESS,ss.getInetAddress(), - ss.getLocalPort()); - else - response = new Socks4Message(Socks4Message.REPLY_OK, - ss.getInetAddress(), - ss.getLocalPort()); - response.write(out); - - mode = ACCEPT_MODE; - - pipe_thread1 = Thread.currentThread(); - pipe_thread2 = new Thread(this); - pipe_thread2.start(); - - //Make timeout infinit. - sock.setSoTimeout(0); - int eof=0; - - try{ - while((eof=in.read())>=0){ - if(mode != ACCEPT_MODE){ - if(mode != PIPE_MODE) return;//Accept failed - - remote_out.write(eof); - break; - } - } - }catch(EOFException eofe){ - //System.out.println("EOF exception"); - return;//Connection closed while we were trying to accept. - }catch(InterruptedIOException iioe){ - //Accept thread interrupted us. - //System.out.println("Interrupted"); - if(mode != PIPE_MODE) - return;//If accept thread was not successfull return. - }finally{ - //System.out.println("Finnaly!"); - } - - if(eof < 0)//Connection closed while we were trying to accept; - return; - - //Do not restore timeout, instead timeout is set on the - //remote socket. It does not make any difference. - - pipe(in,remote_out); - } - - private void onUDP(ProxyMessage msg) throws IOException{ - if(msg.ip.getHostAddress().equals("0.0.0.0")) - msg.ip = sock.getInetAddress(); - log("Creating UDP relay server for "+msg.ip+":"+msg.port); - relayServer = new UDPRelayServer(msg.ip,msg.port, - Thread.currentThread(),sock,auth); - - ProxyMessage response; - - response = new Socks5Message(Proxy.SOCKS_SUCCESS, - relayServer.relayIP,relayServer.relayPort); - - response.write(out); - - relayServer.start(); - - //Make timeout infinit. - sock.setSoTimeout(0); - try{ - while(in.read()>=0) /*do nothing*/; - }catch(EOFException eofe){ - } - } - -//Private methods -////////////////// - - private void doAccept() throws IOException{ - Socket s; - long startTime = System.currentTimeMillis(); - - while(true){ - s = ss.accept(); - if(s.getInetAddress().equals(msg.ip)){ - //got the connection from the right host - //Close listenning socket. - ss.close(); - break; - }else if(ss instanceof SocksServerSocket){ - //We can't accept more then one connection - s.close(); - ss.close(); - throw new SocksException(Proxy.SOCKS_FAILURE); - }else{ - if(acceptTimeout!=0){ //If timeout is not infinit - int newTimeout = acceptTimeout-(int)(System.currentTimeMillis()- - startTime); - if(newTimeout <= 0) throw new InterruptedIOException( - "In doAccept()"); - ss.setSoTimeout(newTimeout); - } - s.close(); //Drop all connections from other hosts - } - } - - //Accepted connection - remote_sock = s; - remote_in = s.getInputStream(); - remote_out = s.getOutputStream(); - - //Set timeout - remote_sock.setSoTimeout(iddleTimeout); - - log("Accepted from "+s.getInetAddress()+":"+s.getPort()); - - ProxyMessage response; - - if(msg.version == 5) - response = new Socks5Message(Proxy.SOCKS_SUCCESS, s.getInetAddress(), - s.getPort()); - else - response = new Socks4Message(Socks4Message.REPLY_OK, - s.getInetAddress(), s.getPort()); - response.write(out); - } - - protected ProxyMessage readMsg(InputStream in) throws IOException{ - PushbackInputStream push_in; - if(in instanceof PushbackInputStream) - push_in = (PushbackInputStream) in; - else - push_in = new PushbackInputStream(in); - - int version = push_in.read(); - push_in.unread(version); - - - ProxyMessage msg; - - if(version == 5){ - msg = new Socks5Message(push_in,false); - }else if(version == 4){ - msg = new Socks4Message(push_in,false); - }else{ - throw new SocksException(Proxy.SOCKS_FAILURE); - } - return msg; - } - - private void startPipe(Socket s){ - mode = PIPE_MODE; - remote_sock = s; - try{ - remote_in = s.getInputStream(); - remote_out = s.getOutputStream(); - pipe_thread1 = Thread.currentThread(); - pipe_thread2 = new Thread(this); - pipe_thread2.start(); - pipe(in,remote_out); - }catch(IOException ioe){ - } - } - - private void sendErrorMessage(int error_code){ - ProxyMessage err_msg; - if(msg instanceof Socks4Message) - err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED); - else - err_msg = new Socks5Message(error_code); - try{ - err_msg.write(out); - }catch(IOException ioe){} - } - - private synchronized void abort(){ - if(mode == ABORT_MODE) return; - mode = ABORT_MODE; - try{ - log("Aborting operation"); - if(remote_sock != null) remote_sock.close(); - if(sock != null) sock.close(); - if(relayServer!=null) relayServer.stop(); - if(ss!=null) ss.close(); - if(pipe_thread1 != null) pipe_thread1.interrupt(); - if(pipe_thread2 != null) pipe_thread2.interrupt(); - }catch(IOException ioe){} - } - - static final void log(String s){ - if(log != null){ - log.println(s); - log.flush(); - } - } - - static final void log(ProxyMessage msg){ - log("Request version:"+msg.version+ - "\tCommand: "+command2String(msg.command)); - log("IP:"+msg.ip +"\tPort:"+msg.port+ - (msg.version==4?"\tUser:"+msg.user:"")); - } - - private void pipe(InputStream in,OutputStream out) throws IOException{ - lastReadTime = System.currentTimeMillis(); - byte[] buf = new byte[BUF_SIZE]; - int len = 0; - while(len >= 0){ - try{ - if(len!=0){ - out.write(buf,0,len); - out.flush(); - } - len= in.read(buf); - lastReadTime = System.currentTimeMillis(); - }catch(InterruptedIOException iioe){ - if(iddleTimeout == 0) return;//Other thread interrupted us. - long timeSinceRead = System.currentTimeMillis() - lastReadTime; - if(timeSinceRead >= iddleTimeout - 1000) //-1s for adjustment. - return; - len = 0; - - } - } - } - static final String command_names[] = {"CONNECT","BIND","UDP_ASSOCIATE"}; - - static final String command2String(int cmd){ - if(cmd > 0 && cmd < 4) return command_names[cmd-1]; - else return "Unknown Command "+cmd; - } -} diff --git a/src/net/sourceforge/jsocks/Socks4Message.java b/src/net/sourceforge/jsocks/Socks4Message.java deleted file mode 100644 index 99fb211..0000000 --- a/src/net/sourceforge/jsocks/Socks4Message.java +++ /dev/null @@ -1,171 +0,0 @@ -package net.sourceforge.jsocks; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - SOCKS4 Reply/Request message. -*/ - -public class Socks4Message extends ProxyMessage{ - - private byte[] msgBytes; - private int msgLength; - - /** - * Server failed reply, cmd command for failed request - */ - public Socks4Message(int cmd){ - super(cmd,null,0); - this.user = null; - - msgLength = 2; - msgBytes = new byte[2]; - - msgBytes[0] = (byte) 0; - msgBytes[1] = (byte) command; - } - - /** - * Server successfull reply - */ - public Socks4Message(int cmd,InetAddress ip,int port){ - this(0,cmd,ip,port,null); - } - - /** - * Client request - */ - public Socks4Message(int cmd,InetAddress ip,int port,String user){ - this(SOCKS_VERSION,cmd,ip,port,user); - } - - /** - * Most general constructor - */ - public Socks4Message(int version, int cmd, - InetAddress ip,int port,String user){ - super(cmd,ip,port); - this.user = user; - this.version = version; - - msgLength = user == null?8:9+user.length(); - msgBytes = new byte[msgLength]; - - msgBytes[0] = (byte) version; - msgBytes[1] = (byte) command; - msgBytes[2] = (byte) (port >> 8); - msgBytes[3] = (byte) port; - - byte[] addr; - - if(ip != null) - addr = ip.getAddress(); - else{ - addr = new byte[4]; - addr[0]=addr[1]=addr[2]=addr[3]=0; - } - System.arraycopy(addr,0,msgBytes,4,4); - - if(user != null){ - byte[] buf = user.getBytes(); - System.arraycopy(buf,0,msgBytes,8,buf.length); - msgBytes[msgBytes.length -1 ] = 0; - } - } - - /** - *Initialise from the stream - *If clientMode is true attempts to read a server response - *otherwise reads a client request - *see read for more detail - */ - public Socks4Message(InputStream in, boolean clientMode) throws IOException{ - msgBytes = null; - read(in,clientMode); - } - - @Override -public void read(InputStream in) throws IOException{ - read(in,true); - } - - @Override -public void read(InputStream in, boolean clientMode) throws IOException{ - boolean mode4a = false; - DataInputStream d_in = new DataInputStream(in); - version= d_in.readUnsignedByte(); - command = d_in.readUnsignedByte(); - if(clientMode && command != REPLY_OK){ - String errMsg; - if(command >REPLY_OK && command < REPLY_BAD_IDENTD) - errMsg = replyMessage[command-REPLY_OK]; - else - errMsg = "Unknown Reply Code"; - throw new SocksException(command,errMsg); - } - port = d_in.readUnsignedShort(); - byte[] addr = new byte[4]; - d_in.readFully(addr); - if (addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] != 0) - mode4a = true; - else { - ip=bytes2IP(addr); - host = ip.getHostName(); - } - if(!clientMode){ - StringBuilder sb = new StringBuilder(); - int b; - while ((b = in.read()) != 0) - sb.append((char) b); - user = sb.toString(); - if (mode4a) { - sb.setLength(0); - while ((b = in.read()) != 0) - sb.append((char) b); - host = sb.toString(); - } - } - } - @Override -public void write(OutputStream out) throws IOException{ - if(msgBytes == null){ - Socks4Message msg = new Socks4Message(version,command,ip,port,user); - msgBytes = msg.msgBytes; - msgLength = msg.msgLength; - } - out.write(msgBytes); - } - - //Class methods - static InetAddress bytes2IP(byte[] addr){ - String s = bytes2IPV4(addr,0); - try{ - return InetAddress.getByName(s); - }catch(UnknownHostException uh_ex){ - return null; - } - } - - //Constants - - static final String[] replyMessage ={ - "Request Granted", - "Request Rejected or Failed", - "Failed request, can't connect to Identd", - "Failed request, bad user name"}; - - static final int SOCKS_VERSION = 4; - - public final static int REQUEST_CONNECT = 1; - public final static int REQUEST_BIND = 2; - - public final static int REPLY_OK = 90; - public final static int REPLY_REJECTED = 91; - public final static int REPLY_NO_CONNECT = 92; - public final static int REPLY_BAD_IDENTD = 93; - -} diff --git a/src/net/sourceforge/jsocks/Socks4Proxy.java b/src/net/sourceforge/jsocks/Socks4Proxy.java deleted file mode 100644 index 9a17fc2..0000000 --- a/src/net/sourceforge/jsocks/Socks4Proxy.java +++ /dev/null @@ -1,107 +0,0 @@ -package net.sourceforge.jsocks; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - Proxy which describes SOCKS4 proxy. -*/ - -public class Socks4Proxy extends Proxy implements Cloneable{ - -//Data members - String user; - -//Public Constructors -//==================== - - /** - Creates the SOCKS4 proxy - @param p Proxy to use to connect to this proxy, allows proxy chaining. - @param proxyHost Address of the proxy server. - @param proxyPort Port of the proxy server - @param user User name to use for identification purposes. - @throws UnknownHostException If proxyHost can't be resolved. - */ - public Socks4Proxy(String proxyHost,int proxyPort,String user) - throws UnknownHostException{ - super(proxyHost,proxyPort); - this.user = new String(user); - version = 4; - } - - /** - Creates the SOCKS4 proxy - @param p Proxy to use to connect to this proxy, allows proxy chaining. - @param proxyIP Address of the proxy server. - @param proxyPort Port of the proxy server - @param user User name to use for identification purposes. - */ - public Socks4Proxy(Proxy p,InetAddress proxyIP,int proxyPort,String user){ - super(p,proxyIP,proxyPort); - this.user = new String(user); - version = 4; - } - - /** - Creates the SOCKS4 proxy - @param proxyIP Address of the proxy server. - @param proxyPort Port of the proxy server - @param user User name to use for identification purposes. - */ - public Socks4Proxy(InetAddress proxyIP,int proxyPort,String user){ - this(null,proxyIP,proxyPort,user); - } - -//Public instance methods -//======================== - - /** - * Creates a clone of this proxy. Changes made to the clone should not - * affect this object. - */ - public Object clone(){ - Socks4Proxy newProxy = new Socks4Proxy(proxyIP,proxyPort,user); - newProxy.chainProxy = chainProxy; - return newProxy; - } - - -//Public Static(Class) Methods -//============================== - - -//Protected Methods -//================= - - protected Proxy copy(){ - Socks4Proxy copy = new Socks4Proxy(proxyIP,proxyPort,user); - copy.chainProxy = chainProxy; - return copy; - } - - protected ProxyMessage formMessage(int cmd,InetAddress ip,int port){ - switch(cmd){ - case SOCKS_CMD_CONNECT: - cmd = Socks4Message.REQUEST_CONNECT; - break; - case SOCKS_CMD_BIND: - cmd = Socks4Message.REQUEST_BIND; - break; - default: - return null; - } - return new Socks4Message(cmd,ip,port,user); - } - protected ProxyMessage formMessage(int cmd,String host,int port) - throws UnknownHostException{ - return formMessage(cmd,InetAddress.getByName(host),port); - } - protected ProxyMessage formMessage(InputStream in) - throws SocksException, - IOException{ - return new Socks4Message(in,true); - } - -} diff --git a/src/net/sourceforge/jsocks/Socks5DatagramSocket.java b/src/net/sourceforge/jsocks/Socks5DatagramSocket.java deleted file mode 100644 index b847400..0000000 --- a/src/net/sourceforge/jsocks/Socks5DatagramSocket.java +++ /dev/null @@ -1,460 +0,0 @@ -package net.sourceforge.jsocks; -import java.net.*; -import java.io.*; - -/** - Datagram socket to interract through the firewall.<BR> - Can be used same way as the normal DatagramSocket. One should - be carefull though with the datagram sizes used, as additional data - is present in both incomming and outgoing datagrams. - <p> - SOCKS5 protocol allows to send host address as either: - <ul> - <li> IPV4, normal 4 byte address. (10 bytes header size) - <li> IPV6, version 6 ip address (not supported by Java as for now). - 22 bytes header size. - <li> Host name,(7+length of the host name bytes header size). - </ul> - As with other Socks equivalents, direct addresses are handled - transparently, that is data will be send directly when required - by the proxy settings. - <p> - <b>NOTE:</b><br> - Unlike other SOCKS Sockets, it <b>does not</b> support proxy chaining, - and will throw an exception if proxy has a chain proxy attached. The - reason for that is not my laziness, but rather the restrictions of - the SOCKSv5 protocol. Basicaly SOCKSv5 proxy server, needs to know from - which host:port datagrams will be send for association, and returns address - to which datagrams should be send by the client, but it does not - inform client from which host:port it is going to send datagrams, in fact - there is even no guarantee they will be send at all and from the same address - each time. - - */ -public class Socks5DatagramSocket extends DatagramSocket{ - - InetAddress relayIP; - int relayPort; - Socks5Proxy proxy; - private boolean server_mode = false; - UDPEncapsulation encapsulation; - - - /** - Construct Datagram socket for communication over SOCKS5 proxy - server. This constructor uses default proxy, the one set with - Proxy.setDefaultProxy() method. If default proxy is not set or - it is set to version4 proxy, which does not support datagram - forwarding, throws SocksException. - - */ - public Socks5DatagramSocket() throws SocksException, - IOException{ - this(Proxy.defaultProxy,0,null); - } - /** - Construct Datagram socket for communication over SOCKS5 proxy - server. And binds it to the specified local port. - This constructor uses default proxy, the one set with - Proxy.setDefaultProxy() method. If default proxy is not set or - it is set to version4 proxy, which does not support datagram - forwarding, throws SocksException. - */ - public Socks5DatagramSocket(int port) throws SocksException, - IOException{ - this(Proxy.defaultProxy,port,null); - } - /** - Construct Datagram socket for communication over SOCKS5 proxy - server. And binds it to the specified local port and address. - This constructor uses default proxy, the one set with - Proxy.setDefaultProxy() method. If default proxy is not set or - it is set to version4 proxy, which does not support datagram - forwarding, throws SocksException. - */ - public Socks5DatagramSocket(int port,InetAddress ip) throws SocksException, - IOException{ - this(Proxy.defaultProxy,port,ip); - } - - /** - Constructs datagram socket for communication over specified proxy. - And binds it to the given local address and port. Address of null - and port of 0, signify any availabale port/address. - Might throw SocksException, if: - <ol> - <li> Given version of proxy does not support UDP_ASSOCIATE. - <li> Proxy can't be reached. - <li> Authorization fails. - <li> Proxy does not want to perform udp forwarding, for any reason. - </ol> - Might throw IOException if binding dtagram socket to given address/port - fails. - See java.net.DatagramSocket for more details. - */ - public Socks5DatagramSocket(Proxy p,int port,InetAddress ip) - throws SocksException, - IOException{ - super(port,ip); - if(p == null) throw new SocksException(Proxy.SOCKS_NO_PROXY); - if(!(p instanceof Socks5Proxy)) - throw new SocksException(-1,"Datagram Socket needs Proxy version 5"); - - if(p.chainProxy != null) - throw new SocksException(Proxy.SOCKS_JUST_ERROR, - "Datagram Sockets do not support proxy chaining."); - - proxy =(Socks5Proxy) p.copy(); - - ProxyMessage msg = proxy.udpAssociate(super.getLocalAddress(), - super.getLocalPort()); - relayIP = msg.ip; - if(relayIP.getHostAddress().equals("0.0.0.0")) relayIP = proxy.proxyIP; - relayPort = msg.port; - - encapsulation = proxy.udp_encapsulation; - - //debug("Datagram Socket:"+getLocalAddress()+":"+getLocalPort()+"\n"); - //debug("Socks5Datagram: "+relayIP+":"+relayPort+"\n"); - } - - /** - Used by UDPRelayServer. - */ - Socks5DatagramSocket(boolean server_mode,UDPEncapsulation encapsulation, - InetAddress relayIP,int relayPort) - throws IOException{ - super(); - this.server_mode = server_mode; - this.relayIP = relayIP; - this.relayPort = relayPort; - this.encapsulation = encapsulation; - this.proxy = null; - } - - /** - Sends the Datagram either through the proxy or directly depending - on current proxy settings and destination address. <BR> - - <B> NOTE: </B> DatagramPacket size should be at least 10 bytes less - than the systems limit. - - <P> - See documentation on java.net.DatagramSocket - for full details on how to use this method. - @param dp Datagram to send. - @throws IOException If error happens with I/O. - */ - public void send(DatagramPacket dp) throws IOException{ - //If the host should be accessed directly, send it as is. - if(!server_mode){ - super.send(dp); - //debug("Sending directly:"); - return; - } - - byte[] head = formHeader(dp.getAddress(),dp.getPort()); - byte[] buf = new byte[head.length + dp.getLength()]; - byte[] data = dp.getData(); - //Merge head and data - System.arraycopy(head,0,buf,0,head.length); - //System.arraycopy(data,dp.getOffset(),buf,head.length,dp.getLength()); - System.arraycopy(data,0,buf,head.length,dp.getLength()); - - if(encapsulation != null) - buf = encapsulation.udpEncapsulate(buf,true); - - super.send(new DatagramPacket(buf,buf.length,relayIP,relayPort)); - } - /** - This method allows to send datagram packets with address type DOMAINNAME. - SOCKS5 allows to specify host as names rather than ip addresses.Using - this method one can send udp datagrams through the proxy, without having - to know the ip address of the destination host. - <p> - If proxy specified for that socket has an option resolveAddrLocally set - to true host will be resolved, and the datagram will be send with address - type IPV4, if resolve fails, UnknownHostException is thrown. - @param dp Datagram to send, it should contain valid port and data - @param host Host name to which datagram should be send. - @throws IOException If error happens with I/O, or the host can't be - resolved when proxy settings say that hosts should be resolved locally. - @see Socks5Proxy#resolveAddrLocally(boolean) - */ - public void send(DatagramPacket dp, String host) throws IOException { - dp.setAddress(InetAddress.getByName(host)); - super.send(dp); - } - - /** - * Receives udp packet. If packet have arrived from the proxy relay server, - * it is processed and address and port of the packet are set to the - * address and port of sending host.<BR> - * If the packet arrived from anywhere else it is not changed.<br> - * <B> NOTE: </B> DatagramPacket size should be at least 10 bytes bigger - * than the largest packet you expect (this is for IPV4 addresses). - * For hostnames and IPV6 it is even more. - @param dp Datagram in which all relevent information will be copied. - */ - public void receive(DatagramPacket dp) throws IOException{ - super.receive(dp); - - if(server_mode){ - //Drop all datagrams not from relayIP/relayPort - int init_length = dp.getLength(); - int initTimeout = getSoTimeout(); - long startTime = System.currentTimeMillis(); - - while(!relayIP.equals(dp.getAddress()) || - relayPort != dp.getPort()){ - - //Restore datagram size - dp.setLength(init_length); - - //If there is a non-infinit timeout on this socket - //Make sure that it happens no matter how often unexpected - //packets arrive. - if(initTimeout != 0){ - int newTimeout = initTimeout - (int)(System.currentTimeMillis() - - startTime); - if(newTimeout <= 0) throw new InterruptedIOException( - "In Socks5DatagramSocket->receive()"); - setSoTimeout(newTimeout); - } - - super.receive(dp); - } - - //Restore timeout settings - if(initTimeout != 0) setSoTimeout(initTimeout); - - }else if(!relayIP.equals(dp.getAddress()) || - relayPort != dp.getPort()) - return; // Recieved direct packet - //If the datagram is not from the relay server, return it it as is. - - byte[] data; - data = dp.getData(); - - if(encapsulation != null) - data = encapsulation.udpEncapsulate(data,false); - - int offset = 0; //Java 1.1 - //int offset = dp.getOffset(); //Java 1.2 - - ByteArrayInputStream bIn = new ByteArrayInputStream(data,offset, - dp.getLength()); - - - ProxyMessage msg = new Socks5Message(bIn); - dp.setPort(msg.port); - dp.setAddress(msg.getInetAddress()); - - //what wasn't read by the Message is the data - int data_length = bIn.available(); - //Shift data to the left - System.arraycopy(data,offset+dp.getLength()-data_length, - data,offset,data_length); - - - dp.setLength(data_length); - } - - /** - * Returns port assigned by the proxy, to which datagrams are relayed. - * It is not the same port to which other party should send datagrams. - @return Port assigned by socks server to which datagrams are send - for association. - */ - public int getLocalPort(){ - if(server_mode) return super.getLocalPort(); - return relayPort; - } - /** - * Address assigned by the proxy, to which datagrams are send for relay. - * It is not necesseraly the same address, to which other party should send - * datagrams. - @return Address to which datagrams are send for association. - */ - public InetAddress getLocalAddress(){ - if(server_mode) return super.getLocalAddress(); - return relayIP; - } - - /** - * Closes datagram socket, and proxy connection. - */ - public void close(){ - if(!server_mode) proxy.endSession(); - super.close(); - } - - /** - This method checks wether proxy still runs udp forwarding service - for this socket. - <p> - This methods checks wether the primary connection to proxy server - is active. If it is, chances are that proxy continues to forward - datagrams being send from this socket. If it was closed, most likely - datagrams are no longer being forwarded by the server. - <p> - Proxy might decide to stop forwarding datagrams, in which case it - should close primary connection. This method allows to check, wether - this have been done. - <p> - You can specify timeout for which we should be checking EOF condition - on the primary connection. Timeout is in milliseconds. Specifying 0 as - timeout implies infinity, in which case method will block, until - connection to proxy is closed or an error happens, and then return false. - <p> - One possible scenario is to call isProxyactive(0) in separate thread, - and once it returned notify other threads about this event. - - @param timeout For how long this method should block, before returning. - @return true if connection to proxy is active, false if eof or error - condition have been encountered on the connection. - */ - public boolean isProxyAlive(int timeout){ - if(server_mode) return false; - if(proxy != null){ - try{ - proxy.proxySocket.setSoTimeout(timeout); - - int eof = proxy.in.read(); - if(eof < 0) return false; // EOF encountered. - else return true; // This really should not happen - - }catch(InterruptedIOException iioe){ - return true; // read timed out. - }catch(IOException ioe){ - return false; - } - } - return false; - } - -//PRIVATE METHODS -////////////////// - - - private byte[] formHeader(InetAddress ip, int port){ - Socks5Message request = new Socks5Message(0,ip,port); - request.data[0] = 0; - return request.data; - } - - -/*====================================================================== - -//Mainly Test functions -////////////////////// - - private String bytes2String(byte[] b){ - String s=""; - char[] hex_digit = { '0','1','2','3','4','5','6','7','8','9', - 'A','B','C','D','E','F'}; - for(int i=0;i<b.length;++i){ - int i1 = (b[i] & 0xF0) >> 4; - int i2 = b[i] & 0xF; - s+=hex_digit[i1]; - s+=hex_digit[i2]; - s+=" "; - } - return s; - } - private static final void debug(String s){ - if(DEBUG) - System.out.print(s); - } - - private static final boolean DEBUG = true; - - - public static void usage(){ - System.err.print( - "Usage: java Socks.SocksDatagramSocket host port [socksHost socksPort]\n"); - } - - static final int defaultProxyPort = 1080; //Default Port - static final String defaultProxyHost = "www-proxy"; //Default proxy - - public static void main(String args[]){ - int port; - String host; - int proxyPort; - String proxyHost; - InetAddress ip; - - if(args.length > 1 && args.length < 5){ - try{ - - host = args[0]; - port = Integer.parseInt(args[1]); - - proxyPort =(args.length > 3)? Integer.parseInt(args[3]) - : defaultProxyPort; - - host = args[0]; - ip = InetAddress.getByName(host); - - proxyHost =(args.length > 2)? args[2] - : defaultProxyHost; - - Proxy.setDefaultProxy(proxyHost,proxyPort); - Proxy p = Proxy.getDefaultProxy(); - p.addDirect("lux"); - - - DatagramSocket ds = new Socks5DatagramSocket(); - - - BufferedReader in = new BufferedReader( - new InputStreamReader(System.in)); - String s; - - System.out.print("Enter line:"); - s = in.readLine(); - - while(s != null){ - byte[] data = (s+"\r\n").getBytes(); - DatagramPacket dp = new DatagramPacket(data,0,data.length, - ip,port); - System.out.println("Sending to: "+ip+":"+port); - ds.send(dp); - dp = new DatagramPacket(new byte[1024],1024); - - System.out.println("Trying to recieve on port:"+ - ds.getLocalPort()); - ds.receive(dp); - System.out.print("Recieved:\n"+ - "From:"+dp.getAddress()+":"+dp.getPort()+ - "\n\n"+ - new String(dp.getData(),dp.getOffset(),dp.getLength())+"\n" - ); - System.out.print("Enter line:"); - s = in.readLine(); - - } - ds.close(); - System.exit(1); - - }catch(SocksException s_ex){ - System.err.println("SocksException:"+s_ex); - s_ex.printStackTrace(); - System.exit(1); - }catch(IOException io_ex){ - io_ex.printStackTrace(); - System.exit(1); - }catch(NumberFormatException num_ex){ - usage(); - num_ex.printStackTrace(); - System.exit(1); - } - - }else{ - usage(); - } - } -*/ - -} diff --git a/src/net/sourceforge/jsocks/Socks5Message.java b/src/net/sourceforge/jsocks/Socks5Message.java deleted file mode 100644 index ea2a321..0000000 --- a/src/net/sourceforge/jsocks/Socks5Message.java +++ /dev/null @@ -1,292 +0,0 @@ -package net.sourceforge.jsocks; - -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - SOCKS5 request/response message. -*/ - -public class Socks5Message extends ProxyMessage{ - /** Address type of given message*/ - public int addrType; - - byte[] data; - - /** - Server error response. - @param cmd Error code. - */ - public Socks5Message(int cmd){ - super(cmd,null,0); - data = new byte[3]; - data[0] = SOCKS_VERSION; //Version. - data[1] = (byte)cmd; //Reply code for some kind of failure. - data[2] = 0; //Reserved byte. - } - - /** - Construct client request or server response. - @param cmd - Request/Response code. - @param ip - IP field. - @paarm port - port field. - */ - public Socks5Message(int cmd,InetAddress ip,int port){ - super(cmd,ip,port); - this.host = ip==null?"0.0.0.0":ip.getHostName(); - this.version = SOCKS_VERSION; - - byte[] addr; - - if(ip == null){ - addr = new byte[4]; - addr[0]=addr[1]=addr[2]=addr[3]=0; - }else - addr = ip.getAddress(); - - addrType = addr.length == 4 ? SOCKS_ATYP_IPV4 - : SOCKS_ATYP_IPV6; - - data = new byte[6+addr.length]; - data[0] = (byte) SOCKS_VERSION; //Version - data[1] = (byte) command; //Command - data[2] = (byte) 0; //Reserved byte - data[3] = (byte) addrType; //Address type - - //Put Address - System.arraycopy(addr,0,data,4,addr.length); - //Put port - data[data.length-2] = (byte)(port>>8); - data[data.length-1] = (byte)(port); - } - - - /** - Construct client request or server response. - @param cmd - Request/Response code. - @param hostName - IP field as hostName, uses ADDR_TYPE of HOSTNAME. - @paarm port - port field. - */ - public Socks5Message(int cmd,String hostName,int port){ - super(cmd,null,port); - this.host = hostName; - this.version = SOCKS_VERSION; - - //System.out.println("Doing ATYP_DOMAINNAME"); - - addrType = SOCKS_ATYP_DOMAINNAME; - byte addr[] = hostName.getBytes(); - - data =new byte[7+addr.length]; - data[0] = (byte) SOCKS_VERSION; //Version - data[1] = (byte) command; //Command - data[2] = (byte) 0; //Reserved byte - data[3] = (byte) SOCKS_ATYP_DOMAINNAME; //Address type - data[4] = (byte) addr.length; //Length of the address - - //Put Address - System.arraycopy(addr,0,data,5,addr.length); - //Put port - data[data.length-2] = (byte)(port >>8); - data[data.length-1] = (byte)(port); - } - - /** - Initialises Message from the stream. Reads server response from - given stream. - @param in Input stream to read response from. - @throws SocksException If server response code is not SOCKS_SUCCESS(0), or - if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public Socks5Message(InputStream in) throws SocksException, - IOException{ - this(in,true); - } - - /** - Initialises Message from the stream. Reads server response or client - request from given stream. - - @param in Input stream to read response from. - @param clinetMode If true read server response, else read client request. - @throws SocksException If server response code is not SOCKS_SUCCESS(0) and - reading in client mode, or if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public Socks5Message(InputStream in,boolean clientMode)throws SocksException, - IOException{ - read(in,clientMode); - } - - - /** - Initialises Message from the stream. Reads server response from - given stream. - @param in Input stream to read response from. - @throws SocksException If server response code is not SOCKS_SUCCESS(0), or - if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public void read(InputStream in) throws SocksException, - IOException{ - read(in,true); - } - - - /** - Initialises Message from the stream. Reads server response or client - request from given stream. - - @param in Input stream to read response from. - @param clinetMode If true read server response, else read client request. - @throws SocksException If server response code is not SOCKS_SUCCESS(0) and - reading in client mode, or if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public void read(InputStream in,boolean clientMode) throws SocksException, - IOException{ - data = null; - ip = null; - - DataInputStream di = new DataInputStream(in); - - version = di.readUnsignedByte(); - command = di.readUnsignedByte(); - if(clientMode && command != 0) - throw new SocksException(command); - - @SuppressWarnings("unused") - int reserved = di.readUnsignedByte(); - addrType = di.readUnsignedByte(); - - byte addr[]; - - switch(addrType){ - case SOCKS_ATYP_IPV4: - addr = new byte[4]; - di.readFully(addr); - host = bytes2IPV4(addr,0); - break; - case SOCKS_ATYP_IPV6: - addr = new byte[SOCKS_IPV6_LENGTH];//I believe it is 16 bytes,huge! - di.readFully(addr); - host = bytes2IPV6(addr,0); - break; - case SOCKS_ATYP_DOMAINNAME: - //System.out.println("Reading ATYP_DOMAINNAME"); - addr = new byte[di.readUnsignedByte()];//Next byte shows the length - di.readFully(addr); - host = new String(addr); - break; - default: - throw(new SocksException(Proxy.SOCKS_JUST_ERROR)); - } - - port = di.readUnsignedShort(); - - if(addrType != SOCKS_ATYP_DOMAINNAME && doResolveIP){ - try{ - ip = InetAddress.getByName(host); - }catch(UnknownHostException uh_ex){ - } - } - } - - /** - Writes the message to the stream. - @param out Output stream to which message should be written. - */ - public void write(OutputStream out)throws SocksException, - IOException{ - if(data == null){ - Socks5Message msg; - - if(addrType == SOCKS_ATYP_DOMAINNAME) - msg = new Socks5Message(command,host,port); - else{ - if(ip == null){ - try{ - ip = InetAddress.getByName(host); - }catch(UnknownHostException uh_ex){ - throw new SocksException(Proxy.SOCKS_JUST_ERROR); - } - } - msg = new Socks5Message(command,ip,port); - } - data = msg.data; - } - out.write(data); - } - - /** - Returns IP field of the message as IP, if the message was created - with ATYP of HOSTNAME, it will attempt to resolve the hostname, - which might fail. - @throws UnknownHostException if host can't be resolved. - */ - public InetAddress getInetAddress() throws UnknownHostException{ - if(ip!=null) return ip; - - return (ip=InetAddress.getByName(host)); - } - - /** - Returns string representation of the message. - */ - public String toString(){ - String s= - "Socks5Message:"+"\n"+ - "VN "+version+"\n"+ - "CMD "+command+"\n"+ - "ATYP "+addrType+"\n"+ - "ADDR "+host+"\n"+ - "PORT "+port+"\n"; - return s; - } - - - /** - *Wether to resolve hostIP returned from SOCKS server - *that is wether to create InetAddress object from the - *hostName string - */ - static public boolean resolveIP(){ return doResolveIP;} - - /** - *Wether to resolve hostIP returned from SOCKS server - *that is wether to create InetAddress object from the - *hostName string - *@param doResolve Wether to resolve hostIP from SOCKS server. - *@return Previous value. - */ - static public boolean resolveIP(boolean doResolve){ - boolean old = doResolveIP; - doResolveIP = doResolve; - return old; - } - - /* - private static final void debug(String s){ - if(DEBUG) - System.out.print(s); - } - private static final boolean DEBUG = false; - */ - - //SOCKS5 constants - public static final int SOCKS_VERSION =5; - - public static final int SOCKS_ATYP_IPV4 =0x1; //Where is 2?? - public static final int SOCKS_ATYP_DOMAINNAME =0x3; //!!!!rfc1928 - public static final int SOCKS_ATYP_IPV6 =0x4; - - public static final int SOCKS_IPV6_LENGTH =16; - - static boolean doResolveIP = true; - -} diff --git a/src/net/sourceforge/jsocks/Socks5Proxy.java b/src/net/sourceforge/jsocks/Socks5Proxy.java deleted file mode 100644 index aa9c643..0000000 --- a/src/net/sourceforge/jsocks/Socks5Proxy.java +++ /dev/null @@ -1,231 +0,0 @@ -package net.sourceforge.jsocks; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.Enumeration; -import java.util.Hashtable; - -/** - SOCKS5 Proxy. -*/ - -public class Socks5Proxy extends Proxy implements Cloneable{ - -//Data members - private Hashtable<Integer, Authentication> authMethods = new Hashtable<Integer, Authentication>(); - private int selectedMethod; - - boolean resolveAddrLocally = true; - UDPEncapsulation udp_encapsulation=null; - - -//Public Constructors -//==================== - - /** - Creates SOCKS5 proxy. - @param proxyHost Host on which a Proxy server runs. - @param proxyPort Port on which a Proxy server listens for connections. - @throws UnknownHostException If proxyHost can't be resolved. - */ - public Socks5Proxy(String proxyHost,int proxyPort) - throws UnknownHostException{ - super(proxyHost,proxyPort); - version = 5; - setAuthenticationMethod(0,new AuthenticationNone()); - } - - - /** - Creates SOCKS5 proxy. - @param proxyIP Host on which a Proxy server runs. - @param proxyPort Port on which a Proxy server listens for connections. - */ - public Socks5Proxy(InetAddress proxyIP,int proxyPort){ - super(proxyIP,proxyPort); - version = 5; - setAuthenticationMethod(0,new AuthenticationNone()); - } - - -//Public instance methods -//======================== - - - /** - * Wether to resolve address locally or to let proxy do so. - <p> - SOCKS5 protocol allows to send host names rather then IPs in the - requests, this option controls wether the hostnames should be send - to the proxy server as names, or should they be resolved locally. - @param doResolve Wether to perform resolution locally. - @return Previous settings. - */ - public boolean resolveAddrLocally(boolean doResolve){ - boolean old = resolveAddrLocally; - resolveAddrLocally = doResolve; - return old; - } - /** - Get current setting on how the addresses should be handled. - @return Current setting for address resolution. - @see Socks5Proxy#resolveAddrLocally(boolean doResolve) - */ - public boolean resolveAddrLocally(){ - return resolveAddrLocally; - } - - /** - Adds another authentication method. - @param methodId Authentication method id, see rfc1928 - @param method Implementation of Authentication - @see Authentication - */ - public boolean setAuthenticationMethod(int methodId, - Authentication method){ - if(methodId<0 || methodId > 255) - return false; - if(method == null){ - //Want to remove a particular method - return (authMethods.remove(new Integer(methodId)) != null); - }else{//Add the method, or rewrite old one - authMethods.put(new Integer(methodId),method); - } - return true; - } - - /** - Get authentication method, which corresponds to given method id - @param methodId Authentication method id. - @return Implementation for given method or null, if one was not set. - */ - public Authentication getAuthenticationMethod(int methodId){ - Object method = authMethods.get(new Integer(methodId)); - if(method == null) return null; - return (Authentication)method; - } - - /** - Creates a clone of this Proxy. - */ - @SuppressWarnings("unchecked") -public Object clone(){ - Socks5Proxy newProxy = new Socks5Proxy(proxyIP,proxyPort); - newProxy.authMethods = (Hashtable<Integer, Authentication>) this.authMethods.clone(); - newProxy.resolveAddrLocally = resolveAddrLocally; - newProxy.chainProxy = chainProxy; - return newProxy; - } - -//Public Static(Class) Methods -//============================== - - -//Protected Methods -//================= - - protected Proxy copy(){ - Socks5Proxy copy = new Socks5Proxy(proxyIP,proxyPort); - copy.authMethods = this.authMethods; //same Hash, no copy - copy.chainProxy = this.chainProxy; - copy.resolveAddrLocally = this.resolveAddrLocally; - return copy; - } - /** - * - * - */ - protected void startSession()throws SocksException{ - super.startSession(); - Authentication auth; - Socket ps = proxySocket; //The name is too long - - try{ - - byte nMethods = (byte) authMethods.size(); //Number of methods - - byte[] buf = new byte[2+nMethods]; //2 is for VER,NMETHODS - buf[0] = (byte) version; - buf[1] = nMethods; //Number of methods - int i=2; - - Enumeration<Integer> ids = authMethods.keys(); - while(ids.hasMoreElements()) - buf[i++] = (byte)((Integer)ids.nextElement()).intValue(); - - out.write(buf); - out.flush(); - - int versionNumber = in.read(); - selectedMethod = in.read(); - - if(versionNumber < 0 || selectedMethod < 0){ - //EOF condition was reached - endSession(); - throw(new SocksException(SOCKS_PROXY_IO_ERROR, - "Connection to proxy lost.")); - } - if(versionNumber < version){ - //What should we do?? - } - if(selectedMethod == 0xFF){ //No method selected - ps.close(); - throw ( new SocksException(SOCKS_AUTH_NOT_SUPPORTED)); - } - - auth = getAuthenticationMethod(selectedMethod); - if(auth == null){ - //This shouldn't happen, unless method was removed by other - //thread, or the server stuffed up - throw(new SocksException(SOCKS_JUST_ERROR, - "Speciefied Authentication not found!")); - } - Object[] in_out = auth.doSocksAuthentication(selectedMethod,ps); - if(in_out == null){ - //Authentication failed by some reason - throw(new SocksException(SOCKS_AUTH_FAILURE)); - } - //Most authentication methods are expected to return - //simply the input/output streams associated with - //the socket. However if the auth. method requires - //some kind of encryption/decryption being done on the - //connection it should provide classes to handle I/O. - - in = (InputStream) in_out[0]; - out = (OutputStream) in_out[1]; - if(in_out.length > 2) - udp_encapsulation = (UDPEncapsulation) in_out[2]; - - }catch(SocksException s_ex){ - throw s_ex; - }catch(UnknownHostException uh_ex){ - throw(new SocksException(SOCKS_PROXY_NO_CONNECT)); - }catch(SocketException so_ex){ - throw(new SocksException(SOCKS_PROXY_NO_CONNECT)); - }catch(IOException io_ex){ - //System.err.println(io_ex); - throw(new SocksException(SOCKS_PROXY_IO_ERROR,""+io_ex)); - } - } - - protected ProxyMessage formMessage(int cmd,InetAddress ip,int port){ - return new Socks5Message(cmd,ip,port); - } - protected ProxyMessage formMessage(int cmd,String host,int port) - throws UnknownHostException{ - if(resolveAddrLocally) - return formMessage(cmd,InetAddress.getByName(host),port); - else - return new Socks5Message(cmd,host,port); - } - protected ProxyMessage formMessage(InputStream in) - throws SocksException, - IOException{ - return new Socks5Message(in); - } - -} diff --git a/src/net/sourceforge/jsocks/SocksException.java b/src/net/sourceforge/jsocks/SocksException.java deleted file mode 100644 index 764587f..0000000 --- a/src/net/sourceforge/jsocks/SocksException.java +++ /dev/null @@ -1,80 +0,0 @@ -package net.sourceforge.jsocks; - -/** - Exception thrown by various socks classes to indicate errors - with protocol or unsuccessful server responses. -*/ -public class SocksException extends java.io.IOException{ - private static final long serialVersionUID = 6141184566248512277L; - - /** - Construct a SocksException with given error code. - <p> - Tries to look up message which corresponds to this error code. - @param errCode Error code for this exception. - */ - public SocksException(int errCode){ - this.errCode = errCode; - if((errCode >> 16) == 0){ - //Server reply error message - errString = errCode <= serverReplyMessage.length ? - serverReplyMessage[errCode] : - UNASSIGNED_ERROR_MESSAGE; - }else{ - //Local error - errCode = (errCode >> 16) -1; - errString = errCode <= localErrorMessage.length ? - localErrorMessage[errCode] : - UNASSIGNED_ERROR_MESSAGE; - } - } - /** - Constructs a SocksException with given error code and message. - @param errCode Error code. - @param errString Error Message. - */ - public SocksException(int errCode,String errString){ - this.errCode = errCode; - this.errString = errString; - } - /** - Get the error code associated with this exception. - @return Error code associated with this exception. - */ - public int getErrorCode(){ - return errCode; - } - /** - Get human readable representation of this exception. - @return String represntation of this exception. - */ - public String toString(){ - return errString; - } - - static final String UNASSIGNED_ERROR_MESSAGE = - "Unknown error message"; - static final String serverReplyMessage[] = { - "Succeeded", - "General SOCKS server failure", - "Connection not allowed by ruleset", - "Network unreachable", - "Host unreachable", - "Connection refused", - "TTL expired", - "Command not supported", - "Address type not supported" }; - - static final String localErrorMessage[] ={ - "SOCKS server not specified", - "Unable to contact SOCKS server", - "IO error", - "None of Authentication methods are supported", - "Authentication failed", - "General SOCKS fault" }; - - String errString; - public int errCode; - -}//End of SocksException class - diff --git a/src/net/sourceforge/jsocks/SocksServerSocket.java b/src/net/sourceforge/jsocks/SocksServerSocket.java deleted file mode 100644 index 179e9c4..0000000 --- a/src/net/sourceforge/jsocks/SocksServerSocket.java +++ /dev/null @@ -1,164 +0,0 @@ -package net.sourceforge.jsocks; - -import java.net.*; -import java.io.*; - -/** - SocksServerSocket allows to accept connections from one particular - host through the SOCKS4 or SOCKS5 proxy. -*/ -public class SocksServerSocket extends ServerSocket{ - //Data members - protected Proxy proxy; - protected String localHost; - protected InetAddress localIP; - protected int localPort; - - boolean doing_direct = false; - InetAddress remoteAddr; - - /** - *Creates ServerSocket capable of accepting one connection - *through the firewall, uses given proxy. - *@param host Host from which the connection should be recieved. - *@param port Port number of the primary connection. - */ - public SocksServerSocket(String host, int port) throws SocksException, - UnknownHostException, IOException { - - super(0); - remoteAddr = InetAddress.getByName(host); - doDirect(); - } - - /** - * Creates ServerSocket capable of accepting one connection - * through the firewall, uses default Proxy. - *@param ip Host from which the connection should be recieved. - *@param port Port number of the primary connection. - */ - public SocksServerSocket(InetAddress ip, int port) throws SocksException, - IOException{ - this(Proxy.defaultProxy,ip,port); - } - - /** - *Creates ServerSocket capable of accepting one connection - *through the firewall, uses given proxy. - *@param ip Host from which the connection should be recieved. - *@param port Port number of the primary connection. - */ - public SocksServerSocket(Proxy p, InetAddress ip, int port) - throws SocksException, IOException { - super(0); - - remoteAddr = ip; - doDirect(); - } - - - /** - * Accepts the incoming connection. - */ - public Socket accept() throws IOException{ - Socket s; - - if(!doing_direct){ - if(proxy == null) return null; - - ProxyMessage msg = proxy.accept(); - s = msg.ip == null? new SocksSocket(msg.host,msg.port,proxy) - : new SocksSocket(msg.ip,msg.port,proxy); - //Set timeout back to 0 - proxy.proxySocket.setSoTimeout(0); - }else{ //Direct Connection - - //Mimic the proxy behaviour, - //only accept connections from the speciefed host. - while(true){ - s = super.accept(); - if(s.getInetAddress().equals(remoteAddr)){ - //got the connection from the right host - //Close listenning socket. - break; - }else - s.close(); //Drop all connections from other hosts - } - - } - proxy = null; - //Return accepted socket - return s; - } - - /** - * Closes the connection to proxy if socket have not been accepted, if - * the direct connection is used, closes direct ServerSocket. If the - * client socket have been allready accepted, does nothing. - */ - public void close() throws IOException{ - super.close(); - if(proxy != null) proxy.endSession(); - proxy = null; - } - - /** - Get the name of the host proxy is using to listen for incoming - connection. - <P> - Usefull when address is returned by proxy as the hostname. - @return the hostname of the address proxy is using to listen - for incoming connection. - */ - public String getHost(){ - return localHost; - } - - /** - * Get address assigned by proxy to listen for incomming - * connections, or the local machine address if doing direct - * connection. - */ - public InetAddress getInetAddress(){ - if(localIP == null){ - try{ - localIP = InetAddress.getByName(localHost); - }catch(UnknownHostException e){ - return null; - } - } - return localIP; - } - - /** - * Get port assigned by proxy to listen for incoming connections, or - the port chosen by local system, if accepting directly. - */ - public int getLocalPort(){ - return localPort; - } - - /** - Set Timeout. - - @param timeout Amount of time in milliseconds, accept should wait for - incoming connection before failing with exception. - Zero timeout implies infinity. - */ - public void setSoTimeout(int timeout) throws SocketException{ - super.setSoTimeout(timeout); - if(!doing_direct) proxy.proxySocket.setSoTimeout(timeout); - } - - -//Private Methods -////////////////// - - private void doDirect(){ - doing_direct = true; - localPort = super.getLocalPort(); - localIP = super.getInetAddress(); - localHost = localIP.getHostName(); - } - -} diff --git a/src/net/sourceforge/jsocks/SocksSocket.java b/src/net/sourceforge/jsocks/SocksSocket.java deleted file mode 100644 index cf9ff65..0000000 --- a/src/net/sourceforge/jsocks/SocksSocket.java +++ /dev/null @@ -1,291 +0,0 @@ -package net.sourceforge.jsocks; - -import java.net.*; -import java.io.*; - -/** - * SocksSocket tryies to look very similar to normal Socket, - * while allowing connections through the SOCKS4 or 5 proxy. - * To use this class you will have to identify proxy you need - * to use, Proxy class allows you to set default proxy, which - * will be used by all Socks aware sockets. You can also create - * either Socks4Proxy or Socks5Proxy, and use them by passing to the - * appropriate constructors. - * <P> - * Using Socks package can be as easy as that: - * - * <pre><tt> - * - * import Socks.*; - * .... - * - * try{ - * //Specify SOCKS5 proxy - * Proxy.setDefaultProxy("socks-proxy",1080); - * - * //OR you still use SOCKS4 - * //Code below uses SOCKS4 proxy - * //Proxy.setDefaultProxy("socks-proxy",1080,userName); - * - * Socket s = SocksSocket("some.host.of.mine",13); - * readTimeFromSock(s); - * }catch(SocksException sock_ex){ - * //Usually it will turn in more or less meaningfull message - * System.err.println("SocksException:"+sock_ex); - * } - * - * </tt></pre> - *<P> - * However if the need exist for more control, like resolving addresses - * remotely, or using some non-trivial authentication schemes, it can be done. - */ - -public class SocksSocket extends Socket{ - //Data members - protected Proxy proxy; - protected String localHost, remoteHost; - protected InetAddress localIP, remoteIP; - protected int localPort,remotePort; - - private Socket directSock = null; - - /** - * Tryies to connect to given host and port - * using default proxy. If no default proxy speciefied - * it throws SocksException with error code SOCKS_NO_PROXY. - @param host Machine to connect to. - @param port Port to which to connect. - * @see SocksSocket#SocksSocket(Proxy,String,int) - * @see Socks5Proxy#resolveAddrLocally - */ - public SocksSocket(String host,int port) - throws SocksException,UnknownHostException{ - this(Proxy.defaultProxy,host,port); - } - /** - * Connects to host port using given proxy server. - @param p Proxy to use. - @param host Machine to connect to. - @param port Port to which to connect. - @throws UnknownHostException - If one of the following happens: - <ol> - - <li> Proxy settings say that address should be resolved locally, but - this fails. - <li> Proxy settings say that the host should be contacted directly but - host name can't be resolved. - </ol> - @throws SocksException - If one of the following happens: - <ul> - <li> Proxy is is null. - <li> Proxy settings say that the host should be contacted directly but - this fails. - <li> Socks Server can't be contacted. - <li> Authentication fails. - <li> Connection is not allowed by the SOCKS proxy. - <li> SOCKS proxy can't establish the connection. - <li> Any IO error occured. - <li> Any protocol error occured. - </ul> - @throws IOexception if anything is wrong with I/O. - @see Socks5Proxy#resolveAddrLocally - */ - public SocksSocket(Proxy p, String host, int port) throws SocksException, - UnknownHostException { - remoteHost = host; - remotePort = port; - remoteIP = InetAddress.getByName(host); - doDirect(); - } - - /** - Connects to given ip and port using given Proxy server. - @param p Proxy to use. - @param ip Machine to connect to. - @param port Port to which to connect. - - */ - public SocksSocket(InetAddress ip, int port) throws SocksException{ - this.remoteIP = ip; - this.remotePort = port; - this.remoteHost = ip.getHostName(); - doDirect(); - } - - - /** - * These 2 constructors are used by the SocksServerSocket. - * This socket simply overrides remoteHost, remotePort - */ - protected SocksSocket(String host,int port,Proxy proxy){ - this.remotePort = port; - this.proxy = proxy; - this.localIP = proxy.proxySocket.getLocalAddress(); - this.localPort = proxy.proxySocket.getLocalPort(); - this.remoteHost = host; - } - protected SocksSocket(InetAddress ip,int port,Proxy proxy){ - remoteIP = ip; - remotePort = port; - this.proxy = proxy; - this.localIP = proxy.proxySocket.getLocalAddress(); - this.localPort = proxy.proxySocket.getLocalPort(); - remoteHost = remoteIP.getHostName(); - } - - /** - * Same as Socket - */ - public void close() throws IOException{ - if(proxy!= null)proxy.endSession(); - proxy = null; - } - /** - * Same as Socket - */ - public InputStream getInputStream(){ - return proxy.in; - } - /** - * Same as Socket - */ - public OutputStream getOutputStream(){ - return proxy.out; - } - /** - * Same as Socket - */ - public int getPort(){ - return remotePort; - } - /** - * Returns remote host name, it is usefull in cases when addresses - * are resolved by proxy, and we can't create InetAddress object. - @return The name of the host this socket is connected to. - */ - public String getHost(){ - return remoteHost; - } - /** - * Get remote host as InetAddress object, might return null if - * addresses are resolved by proxy, and it is not possible to resolve - * it locally - @return Ip address of the host this socket is connected to, or null - if address was returned by the proxy as DOMAINNAME and can't be - resolved locally. - */ - public InetAddress getInetAddress(){ - if(remoteIP == null){ - try{ - remoteIP = InetAddress.getByName(remoteHost); - }catch(UnknownHostException e){ - return null; - } - } - return remoteIP; - } - - /** - * Get the port assigned by the proxy for the socket, not - * the port on locall machine as in Socket. - @return Port of the socket used on the proxy server. - */ - public int getLocalPort(){ - return localPort; - } - - /** - * Get address assigned by proxy to make a remote connection, - * it might be different from the host specified for the proxy. - * Can return null if socks server returned this address as hostname - * and it can't be resolved locally, use getLocalHost() then. - @return Address proxy is using to make a connection. - */ - public InetAddress getLocalAddress(){ - if(localIP == null){ - try{ - localIP = InetAddress.getByName(localHost); - }catch(UnknownHostException e){ - return null; - } - } - return localIP; - } - /** - Get name of the host, proxy has assigned to make a remote connection - for this socket. This method is usefull when proxy have returned - address as hostname, and we can't resolve it on this machine. - @return The name of the host proxy is using to make a connection. - */ - public String getLocalHost(){ - return localHost; - } - - /** - Same as socket. - */ - public void setSoLinger(boolean on,int val) throws SocketException{ - proxy.proxySocket.setSoLinger(on,val); - } - /** - Same as socket. - */ - public int getSoLinger(int timeout) throws SocketException{ - return proxy.proxySocket.getSoLinger(); - } - /** - Same as socket. - */ - public void setSoTimeout(int timeout) throws SocketException{ - proxy.proxySocket.setSoTimeout(timeout); - } - /** - Same as socket. - */ - public int getSoTimeout(int timeout) throws SocketException{ - return proxy.proxySocket.getSoTimeout(); - } - /** - Same as socket. - */ - public void setTcpNoDelay(boolean on) throws SocketException{ - proxy.proxySocket.setTcpNoDelay(on); - } - /** - Same as socket. - */ - public boolean getTcpNoDelay() throws SocketException{ - return proxy.proxySocket.getTcpNoDelay(); - } - - /** - Get string representation of the socket. - */ - public String toString(){ - if(directSock!=null) return "Direct connection:"+directSock; - return ("Proxy:"+proxy+";"+"addr:"+remoteHost+",port:"+remotePort - +",localport:"+localPort); - - } - -//Private Methods -////////////////// - - private void doDirect()throws SocksException{ - try{ - //System.out.println("IP:"+remoteIP+":"+remotePort); - directSock = new Socket(remoteIP,remotePort); - proxy.out = directSock.getOutputStream(); - proxy.in = directSock.getInputStream(); - proxy.proxySocket = directSock; - localIP = directSock.getLocalAddress(); - localPort = directSock.getLocalPort(); - }catch(IOException io_ex){ - throw new SocksException(Proxy.SOCKS_DIRECT_FAILED, - "Direct connect failed:"+io_ex); - } - } - -} diff --git a/src/net/sourceforge/jsocks/UDPEncapsulation.java b/src/net/sourceforge/jsocks/UDPEncapsulation.java deleted file mode 100644 index e965942..0000000 --- a/src/net/sourceforge/jsocks/UDPEncapsulation.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.sourceforge.jsocks; -/** - This interface provides for datagram encapsulation for SOCKSv5 protocol. - <p> - SOCKSv5 allows for datagrams to be encapsulated for purposes of integrity - and/or authenticity. How it should be done is aggreed during the - authentication stage, and is authentication dependent. This interface is - provided to allow this encapsulation. - @see Authentication -*/ -public interface UDPEncapsulation{ - - /** - This method should provide any authentication depended transformation - on datagrams being send from/to the client. - - @param data Datagram data (including any SOCKS related bytes), to be - encapsulated/decapsulated. - @param out Wether the data is being send out. If true method should - encapsulate/encrypt data, otherwise it should decapsulate/ - decrypt data. - @throw IOException if for some reason data can be transformed correctly. - @return Should return byte array containing data after transformation. - It is possible to return same array as input, if transformation - only involves bit mangling, and no additional data is being - added or removed. - */ - byte[] udpEncapsulate(byte[] data, boolean out) throws java.io.IOException; -} diff --git a/src/net/sourceforge/jsocks/UDPRelayServer.java b/src/net/sourceforge/jsocks/UDPRelayServer.java deleted file mode 100644 index dfa6016..0000000 --- a/src/net/sourceforge/jsocks/UDPRelayServer.java +++ /dev/null @@ -1,212 +0,0 @@ -package net.sourceforge.jsocks; -import net.sourceforge.jsocks.server.*; -import java.net.*; -import java.io.*; - -/** - UDP Relay server, used by ProxyServer to perform udp forwarding. -*/ -class UDPRelayServer implements Runnable{ - - - DatagramSocket client_sock; - DatagramSocket remote_sock; - - Socket controlConnection; - - int relayPort; - InetAddress relayIP; - - Thread pipe_thread1,pipe_thread2; - Thread master_thread; - - ServerAuthenticator auth; - - long lastReadTime; - - static PrintStream log = null; - static Proxy proxy = null; - static int datagramSize = 0xFFFF;//64K, a bit more than max udp size - static int iddleTimeout = 180000;//3 minutes - - - /** - Constructs UDP relay server to communicate with client - on given ip and port. - @param clientIP Address of the client from whom datagrams - will be recieved and to whom they will be forwarded. - @param clientPort Clients port. - @param master_thread Thread which will be interrupted, when - UDP relay server stoppes for some reason. - @param controlConnection Socket which will be closed, before - interrupting the master thread, it is introduced due to a bug - in windows JVM which does not throw InterruptedIOException in - threads which block in I/O operation. - */ - public UDPRelayServer(InetAddress clientIP,int clientPort, - Thread master_thread, - Socket controlConnection, - ServerAuthenticator auth) - throws IOException{ - this.master_thread = master_thread; - this.controlConnection = controlConnection; - this.auth = auth; - - client_sock = new Socks5DatagramSocket(true,auth.getUdpEncapsulation(), - clientIP,clientPort); - relayPort = client_sock.getLocalPort(); - relayIP = client_sock.getLocalAddress(); - - if(relayIP.getHostAddress().equals("0.0.0.0")) - relayIP = InetAddress.getLocalHost(); - - if(proxy == null) - remote_sock = new DatagramSocket(); - else - remote_sock = new Socks5DatagramSocket(proxy,0,null); - } - - -//Public methods -///////////////// - - - /** - Sets the timeout for UDPRelay server.<br> - Zero timeout implies infinity.<br> - Default timeout is 3 minutes. - */ - - static public void setTimeout(int timeout){ - iddleTimeout = timeout; - } - - - /** - Sets the size of the datagrams used in the UDPRelayServer.<br> - Default size is 64K, a bit more than maximum possible size of the - datagram. - */ - static public void setDatagramSize(int size){ - datagramSize = size; - } - - /** - Port to which client should send datagram for association. - */ - public int getRelayPort(){ - return relayPort; - } - /** - IP address to which client should send datagrams for association. - */ - public InetAddress getRelayIP(){ - return relayIP; - } - - /** - Starts udp relay server. - Spawns two threads of execution and returns. - */ - public void start() throws IOException{ - remote_sock.setSoTimeout(iddleTimeout); - client_sock.setSoTimeout(iddleTimeout); - - log("Starting UDP relay server on "+relayIP+":"+relayPort); - log("Remote socket "+remote_sock.getLocalAddress()+":"+ - remote_sock.getLocalPort()); - - pipe_thread1 = new Thread(this,"pipe1"); - pipe_thread2 = new Thread(this,"pipe2"); - - lastReadTime = System.currentTimeMillis(); - - pipe_thread1.start(); - pipe_thread2.start(); - } - - /** - Stops Relay server. - <p> - Does not close control connection, does not interrupt master_thread. - */ - public synchronized void stop(){ - master_thread = null; - controlConnection = null; - abort(); - } - -//Runnable interface -//////////////////// - public void run(){ - try{ - if(Thread.currentThread().getName().equals("pipe1")) - pipe(remote_sock,client_sock,false); - else - pipe(client_sock,remote_sock,true); - }catch(IOException ioe){ - }finally{ - abort(); - log("UDP Pipe thread "+Thread.currentThread().getName()+" stopped."); - } - - } - -//Private methods -///////////////// - private synchronized void abort(){ - if(pipe_thread1 == null) return; - - log("Aborting UDP Relay Server"); - - remote_sock.close(); - client_sock.close(); - - if(controlConnection != null) - try{ controlConnection.close();} catch(IOException ioe){} - - if(master_thread!=null) master_thread.interrupt(); - - pipe_thread1.interrupt(); - pipe_thread2.interrupt(); - - pipe_thread1 = null; - } - - - static private void log(String s){ - if(log != null){ - log.println(s); - log.flush(); - } - } - - private void pipe(DatagramSocket from,DatagramSocket to,boolean out) - throws IOException{ - byte[] data = new byte[datagramSize]; - DatagramPacket dp = new DatagramPacket(data,data.length); - - while(true){ - try{ - from.receive(dp); - lastReadTime = System.currentTimeMillis(); - - if(auth.checkRequest(dp,out)) - to.send(dp); - - }catch(UnknownHostException uhe){ - log("Dropping datagram for unknown host"); - }catch(InterruptedIOException iioe){ - //log("Interrupted: "+iioe); - //If we were interrupted by other thread. - if(iddleTimeout == 0) return; - - //If last datagram was received, long time ago, return. - long timeSinceRead = System.currentTimeMillis() - lastReadTime; - if(timeSinceRead >= iddleTimeout -100) //-100 for adjustment - return; - } - dp.setLength(data.length); - } - } -} diff --git a/src/net/sourceforge/jsocks/server/ServerAuthenticator.java b/src/net/sourceforge/jsocks/server/ServerAuthenticator.java deleted file mode 100644 index cb7f0af..0000000 --- a/src/net/sourceforge/jsocks/server/ServerAuthenticator.java +++ /dev/null @@ -1,120 +0,0 @@ -package net.sourceforge.jsocks.server; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.DatagramPacket; -import java.net.Socket; - -import net.sourceforge.jsocks.ProxyMessage; -import net.sourceforge.jsocks.UDPEncapsulation; - -/** - Classes implementing this interface should provide socks server with - authentication and authorization of users. -**/ -public interface ServerAuthenticator{ - - /** - This method is called when a new connection accepted by the server. - <p> - At this point no data have been extracted from the connection. It is - responsibility of this method to ensure that the next byte in the - stream after this method have been called is the first byte of the - socks request message. For SOCKSv4 there is no authentication data and - the first byte in the stream is part of the request. With SOCKSv5 however - there is an authentication data first. It is expected that implementaions - will process this authentication data. - <p> - If authentication was successful an instance of ServerAuthentication - should be returned, it later will be used by the server to perform - authorization and some other things. If authentication fails null should - be returned, or an exception may be thrown. - - @param s Accepted Socket. - @return An instance of ServerAuthenticator to be used for this connection - or null - */ - ServerAuthenticator startSession(Socket s) throws IOException; - - /** - This method should return input stream which should be used on the - accepted socket. - <p> - SOCKSv5 allows to have multiple authentication methods, and these methods - might require some kind of transformations being made on the data. - <p> - This method is called on the object returned from the startSession - function. - */ - InputStream getInputStream(); - /** - This method should return output stream to use to write to the accepted - socket. - <p> - SOCKSv5 allows to have multiple authentication methods, and these methods - might require some kind of transformations being made on the data. - <p> - This method is called on the object returned from the startSession - function. - */ - OutputStream getOutputStream(); - - /** - This method should return UDPEncapsulation, which should be used - on the datagrams being send in/out. - <p> - If no transformation should be done on the datagrams, this method - should return null. - <p> - This method is called on the object returned from the startSession - function. - */ - - UDPEncapsulation getUdpEncapsulation(); - - /** - This method is called when a request have been read. - <p> - Implementation should decide wether to grant request or not. Returning - true implies granting the request, false means request should be rejected. - <p> - This method is called on the object returned from the startSession - function. - @param msg Request message. - @return true to grant request, false to reject it. - */ - boolean checkRequest(ProxyMessage msg); - - /** - This method is called when datagram is received by the server. - <p> - Implementaions should decide wether it should be forwarded or dropped. - It is expecteed that implementation will use datagram address and port - information to make a decision, as well as anything else. Address and - port of the datagram are always correspond to remote machine. It is - either destination or source address. If out is true address is destination - address, else it is a source address, address of the machine from which - datagram have been received for the client. - <p> - Implementaions should return true if the datagram is to be forwarded, and - false if the datagram should be dropped. - <p> - This method is called on the object returned from the startSession - function. - - @param out If true the datagram is being send out(from the client), - otherwise it is an incoming datagram. - @return True to forward datagram false drop it silently. - */ - boolean checkRequest(DatagramPacket dp, boolean out); - - /** - This method is called when session is completed. Either due to normal - termination or due to any error condition. - <p> - This method is called on the object returned from the startSession - function. - */ - void endSession(); -} diff --git a/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java b/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java deleted file mode 100644 index e4edbe7..0000000 --- a/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java +++ /dev/null @@ -1,169 +0,0 @@ -package net.sourceforge.jsocks.server; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PushbackInputStream; -import java.net.Socket; - -import net.sourceforge.jsocks.ProxyMessage; -import net.sourceforge.jsocks.UDPEncapsulation; - -/** - An implementation of ServerAuthenticator, which does <b>not</b> do - any authentication. -<P> -<FONT size="+3" color ="FF0000"> Warning!!</font><br> Should not be -used on machines which are not behind the firewall. -<p> -It is only provided to make implementing other authentication schemes -easier.<br> -For Example: <tt><pre> - class MyAuth extends socks.server.ServerAuthenticator{ - ... - public ServerAuthenticator startSession(java.net.Socket s){ - if(!checkHost(s.getInetAddress()) return null; - return super.startSession(s); - } - - boolean checkHost(java.net.Inetaddress addr){ - boolean allow; - //Do it somehow - return allow; - } - } -</pre></tt> -*/ -public class ServerAuthenticatorNone implements ServerAuthenticator{ - - static final byte[] socks5response = {5,0}; - - InputStream in; - OutputStream out; - - /** - Creates new instance of the ServerAuthenticatorNone. - */ - public ServerAuthenticatorNone(){ - this.in = null; - this.out = null; - } - /** - Constructs new ServerAuthenticatorNone object suitable for returning - from the startSession function. - @param in Input stream to return from getInputStream method. - @param out Output stream to return from getOutputStream method. - */ - public ServerAuthenticatorNone(InputStream in, OutputStream out){ - this.in = in; - this.out = out; - } - /** - Grants access to everyone.Removes authentication related bytes from - the stream, when a SOCKS5 connection is being made, selects an - authentication NONE. - */ - public ServerAuthenticator startSession(Socket s) - throws IOException{ - - PushbackInputStream in = new PushbackInputStream(s.getInputStream()); - OutputStream out = s.getOutputStream(); - - int version = in.read(); - if(version == 5){ - if(!selectSocks5Authentication(in,out,0)) - return null; - }else if(version == 4){ - //Else it is the request message allready, version 4 - in.unread(version); - }else - return null; - - - return new ServerAuthenticatorNone(in,out); - } - - /** - Get input stream. - @return Input stream speciefied in the constructor. - */ - public InputStream getInputStream(){ - return in; - } - /** - Get output stream. - @return Output stream speciefied in the constructor. - */ - public OutputStream getOutputStream(){ - return out; - } - /** - Allways returns null. - @return null - */ - public UDPEncapsulation getUdpEncapsulation(){ - return null; - } - - /** - Allways returns true. - */ - public boolean checkRequest(ProxyMessage msg){ - return true; - } - - /** - Allways returns true. - */ - public boolean checkRequest(java.net.DatagramPacket dp, boolean out){ - return true; - } - - /** - Does nothing. - */ - public void endSession(){ - } - - /** - Convinience routine for selecting SOCKSv5 authentication. - <p> - This method reads in authentication methods that client supports, - checks wether it supports given method. If it does, the notification - method is written back to client, that this method have been chosen - for authentication. If given method was not found, authentication - failure message is send to client ([5,FF]). - @param in Input stream, version byte should be removed from the stream - before calling this method. - @param out Output stream. - @param methodId Method which should be selected. - @return true if methodId was found, false otherwise. - */ - static public boolean selectSocks5Authentication(InputStream in, - OutputStream out, - int methodId) - throws IOException{ - - int num_methods = in.read(); - if (num_methods <= 0) return false; - byte method_ids[] = new byte[num_methods]; - byte response[] = new byte[2]; - boolean found = false; - - response[0] = (byte) 5; //SOCKS version - response[1] = (byte) 0xFF; //Not found, we are pessimistic - - int bread = 0; //bytes read so far - while(bread < num_methods) - bread += in.read(method_ids,bread,num_methods-bread); - - for(int i=0;i<num_methods;++i) - if(method_ids[i] == methodId){ - found = true; - response[1] = (byte) methodId; - break; - } - - out.write(response); - return found; - } -} diff --git a/src/org/apache/harmony/niochar/charset/additional/IBM437.java b/src/org/apache/harmony/niochar/charset/additional/IBM437.java deleted file mode 100644 index d61ef59..0000000 --- a/src/org/apache/harmony/niochar/charset/additional/IBM437.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.harmony.niochar.charset.additional; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; - -/* TODO: support direct byte buffers -import org.apache.harmony.nio.AddressUtil; -import org.apache.harmony.niochar.CharsetProviderImpl; -*/ - -public class IBM437 extends Charset { - - public IBM437(String csName, String[] aliases) { - super(csName, aliases); - } - - public boolean contains(Charset cs) { - return cs.name().equalsIgnoreCase("IBM367") || cs.name().equalsIgnoreCase("IBM437") || cs.name().equalsIgnoreCase("US-ASCII") ; - } - - public CharsetDecoder newDecoder() { - return new Decoder(this); - } - - public CharsetEncoder newEncoder() { - return new Encoder(this); - } - - private static final class Decoder extends CharsetDecoder{ - private Decoder(Charset cs){ - super(cs, 1, 1); - - } - - private native int nDecode(char[] array, int arrPosition, int remaining, long outAddr, int absolutePos); - - - protected CoderResult decodeLoop(ByteBuffer bb, CharBuffer cb){ - int cbRemaining = cb.remaining(); -/* TODO: support direct byte buffers - if(CharsetProviderImpl.hasLoadedNatives() && bb.isDirect() && bb.hasRemaining() && cb.hasArray()){ - int toProceed = bb.remaining(); - int cbPos = cb.position(); - int bbPos = bb.position(); - boolean throwOverflow = false; - if( cbRemaining < toProceed ) { - toProceed = cbRemaining; - throwOverflow = true; - } - int res = nDecode(cb.array(), cb.arrayOffset()+cbPos, toProceed, AddressUtil.getDirectBufferAddress(bb), bbPos); - bb.position(bbPos+res); - cb.position(cbPos+res); - if(throwOverflow) return CoderResult.OVERFLOW; - }else{ -*/ - if(bb.hasArray() && cb.hasArray()) { - int rem = bb.remaining(); - rem = cbRemaining >= rem ? rem : cbRemaining; - byte[] bArr = bb.array(); - char[] cArr = cb.array(); - int bStart = bb.position(); - int cStart = cb.position(); - int i; - for(i=bStart; i<bStart+rem; i++) { - char in = (char)(bArr[i] & 0xFF); - if(in >= 26){ - int index = (int)in - 26; - cArr[cStart++] = (char)arr[index]; - }else { - cArr[cStart++] = (char)(in & 0xFF); - } - } - bb.position(i); - cb.position(cStart); - if(rem == cbRemaining && bb.hasRemaining()) return CoderResult.OVERFLOW; - } else { - while(bb.hasRemaining()){ - if( cbRemaining == 0 ) return CoderResult.OVERFLOW; - char in = (char)(bb.get() & 0xFF); - if(in >= 26){ - int index = (int)in - 26; - cb.put(arr[index]); - }else { - cb.put((char)(in & 0xFF)); - } - cbRemaining--; - } -/* - } -*/ - } - return CoderResult.UNDERFLOW; - } - - final static char[] arr = { - 0x001C,0x001B,0x007F,0x001D,0x001E,0x001F, - 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, - 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F, - 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, - 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F, - 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, - 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F, - 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, - 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F, - 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, - 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, - 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, - 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x001A, - 0x00C7,0x00FC,0x00E9,0x00E2,0x00E4,0x00E0,0x00E5,0x00E7, - 0x00EA,0x00EB,0x00E8,0x00EF,0x00EE,0x00EC,0x00C4,0x00C5, - 0x00C9,0x00E6,0x00C6,0x00F4,0x00F6,0x00F2,0x00FB,0x00F9, - 0x00FF,0x00D6,0x00DC,0x00A2,0x00A3,0x00A5,0x20A7,0x0192, - 0x00E1,0x00ED,0x00F3,0x00FA,0x00F1,0x00D1,0x00AA,0x00BA, - 0x00BF,0x2310,0x00AC,0x00BD,0x00BC,0x00A1,0x00AB,0x00BB, - 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, - 0x2555,0x2563,0x2551,0x2557,0x255D,0x255C,0x255B,0x2510, - 0x2514,0x2534,0x252C,0x251C,0x2500,0x253C,0x255E,0x255F, - 0x255A,0x2554,0x2569,0x2566,0x2560,0x2550,0x256C,0x2567, - 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256B, - 0x256A,0x2518,0x250C,0x2588,0x2584,0x258C,0x2590,0x2580, - 0x03B1,0x00DF,0x0393,0x03C0,0x03A3,0x03C3,0x03BC,0x03C4, - 0x03A6,0x0398,0x03A9,0x03B4,0x221E,0x03C6,0x03B5,0x2229, - 0x2261,0x00B1,0x2265,0x2264,0x2320,0x2321,0x00F7,0x2248, - 0x00B0,0x2219,0x00B7,0x221A,0x207F,0x00B2,0x25A0,0x00A0 - }; - } - - private static final class Encoder extends CharsetEncoder{ - private Encoder(Charset cs){ - super(cs, 1, 1); - } - - private native void nEncode(long outAddr, int absolutePos, char[] array, int arrPosition, int[] res); - - protected CoderResult encodeLoop(CharBuffer cb, ByteBuffer bb){ - int bbRemaining = bb.remaining(); -/* TODO: support direct byte buffers - if(CharsetProviderImpl.hasLoadedNatives() && bb.isDirect() && cb.hasRemaining() && cb.hasArray()){ - int toProceed = cb.remaining(); - int cbPos = cb.position(); - int bbPos = bb.position(); - boolean throwOverflow = false; - if( bbRemaining < toProceed ) { - toProceed = bbRemaining; - throwOverflow = true; - } - int[] res = {toProceed, 0}; - nEncode(AddressUtil.getDirectBufferAddress(bb), bbPos, cb.array(), cb.arrayOffset()+cbPos, res); - if( res[0] <= 0 ) { - bb.position(bbPos-res[0]); - cb.position(cbPos-res[0]); - if(res[1]!=0) { - if(res[1] < 0) - return CoderResult.malformedForLength(-res[1]); - else - return CoderResult.unmappableForLength(res[1]); - } - }else{ - bb.position(bbPos+res[0]); - cb.position(cbPos+res[0]); - if(throwOverflow) return CoderResult.OVERFLOW; - } - }else{ -*/ - if(bb.hasArray() && cb.hasArray()) { - byte[] byteArr = bb.array(); - char[] charArr = cb.array(); - int rem = cb.remaining(); - int byteArrStart = bb.position(); - rem = bbRemaining <= rem ? bbRemaining : rem; - int x; - for(x = cb.position(); x < cb.position()+rem; x++) { - char c = charArr[x]; - if(c > (char)0x25A0){ - if (c >= 0xD800 && c <= 0xDFFF) { - if(x+1 < cb.limit()) { - char c1 = charArr[x+1]; - if(c1 >= 0xD800 && c1 <= 0xDFFF) { - cb.position(x); bb.position(byteArrStart); - return CoderResult.unmappableForLength(2); - } - } else { - cb.position(x); bb.position(byteArrStart); - return CoderResult.UNDERFLOW; - } - cb.position(x); bb.position(byteArrStart); - return CoderResult.malformedForLength(1); - } - cb.position(x); bb.position(byteArrStart); - return CoderResult.unmappableForLength(1); - }else{ - if(c < 0x1A) { - byteArr[byteArrStart++] = (byte)c; - } else { - int index = (int)c >> 8; - index = encodeIndex[index]; - if(index < 0) { - cb.position(x); bb.position(byteArrStart); - return CoderResult.unmappableForLength(1); - } - index <<= 8; - index += (int)c & 0xFF; - if((byte)arr[index] != 0){ - byteArr[byteArrStart++] = (byte)arr[index]; - }else{ - cb.position(x); bb.position(byteArrStart); - return CoderResult.unmappableForLength(1); - } - } - } - } - cb.position(x); - bb.position(byteArrStart); - if(rem == bbRemaining && cb.hasRemaining()) { - return CoderResult.OVERFLOW; - } - } else { - while(cb.hasRemaining()){ - if( bbRemaining == 0 ) return CoderResult.OVERFLOW; - char c = cb.get(); - if(c > (char)0x25A0){ - if (c >= 0xD800 && c <= 0xDFFF) { - if(cb.hasRemaining()) { - char c1 = cb.get(); - if(c1 >= 0xD800 && c1 <= 0xDFFF) { - cb.position(cb.position()-2); - return CoderResult.unmappableForLength(2); - } else { - cb.position(cb.position()-1); - } - } else { - cb.position(cb.position()-1); - return CoderResult.UNDERFLOW; - } - cb.position(cb.position()-1); - return CoderResult.malformedForLength(1); - } - cb.position(cb.position()-1); - return CoderResult.unmappableForLength(1); - }else{ - if(c < 0x1A) { - bb.put((byte)c); - } else { - int index = (int)c >> 8; - index = encodeIndex[index]; - if(index < 0) { - cb.position(cb.position()-1); - return CoderResult.unmappableForLength(1); - } - index <<= 8; - index += (int)c & 0xFF; - if((byte)arr[index] != 0){ - bb.put((byte)arr[index]); - }else{ - cb.position(cb.position()-1); - return CoderResult.unmappableForLength(1); - } - } - bbRemaining--; - } - } -/* TODO: support direct byte buffers - } -*/ - } - return CoderResult.UNDERFLOW; - } - - final static char arr[] = { - - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x7F,0x1B,0x1A,0x1D,0x1E,0x1F, - 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, - 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, - 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, - 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, - 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x1C, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xFF,0xAD,0x9B,0x9C,0x00,0x9D,0x00,0x00,0x00,0x00,0xA6,0xAE,0xAA,0x00,0x00,0x00, - 0xF8,0xF1,0xFD,0x00,0x00,0x00,0x00,0xFA,0x00,0x00,0xA7,0xAF,0xAC,0xAB,0x00,0xA8, - 0x00,0x00,0x00,0x00,0x8E,0x8F,0x92,0x80,0x00,0x90,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0xA5,0x00,0x00,0x00,0x00,0x99,0x00,0x00,0x00,0x00,0x00,0x9A,0x00,0x00,0xE1, - 0x85,0xA0,0x83,0x00,0x84,0x86,0x91,0x87,0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B, - 0x00,0xA4,0x95,0xA2,0x93,0x00,0x94,0xF6,0x00,0x97,0xA3,0x96,0x81,0x00,0x00,0x98, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x9F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0xE2,0x00,0x00,0x00,0x00,0xE9,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0xE4,0x00,0x00,0xE8,0x00,0x00,0xEA,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0xE0,0x00,0x00,0xEB,0xEE,0x00,0x00,0x00,0x00,0x00,0x00,0xE6,0x00,0x00,0x00, - 0xE3,0x00,0x00,0xE5,0xE7,0x00,0xED,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF9,0xFB,0x00,0x00,0x00,0xEC,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEF,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF7,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0xF0,0x00,0x00,0xF3,0xF2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xA9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xF4,0xF5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - - 0xC4,0x00,0xB3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDA,0x00,0x00,0x00, - 0xBF,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0xD9,0x00,0x00,0x00,0xC3,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xB4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC2,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0xC1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC5,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xCD,0xBA,0xD5,0xD6,0xC9,0xB8,0xB7,0xBB,0xD4,0xD3,0xC8,0xBE,0xBD,0xBC,0xC6,0xC7, - 0xCC,0xB5,0xB6,0xB9,0xD1,0xD2,0xCB,0xCF,0xD0,0xCA,0xD8,0xD7,0xCE,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xDF,0x00,0x00,0x00,0xDC,0x00,0x00,0x00,0xDB,0x00,0x00,0x00,0xDD,0x00,0x00,0x00, - 0xDE,0xB0,0xB1,0xB2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - }; - - final static int[] encodeIndex = { - 0,1,-1,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 3,-1,4,5,-1,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; - } -} diff --git a/src/org/connectbot/ActionBarWrapper.java b/src/org/connectbot/ActionBarWrapper.java deleted file mode 100644 index 0c7b65d..0000000 --- a/src/org/connectbot/ActionBarWrapper.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import org.connectbot.util.PreferenceConstants; - -import android.app.Activity; -import android.app.ActionBar; - -public abstract class ActionBarWrapper { - public interface OnMenuVisibilityListener { - public void onMenuVisibilityChanged(boolean isVisible); - } - - public static ActionBarWrapper getActionBar(Activity activity) { - if (PreferenceConstants.PRE_HONEYCOMB) - return new DummyActionBar(); - else - return new RealActionBar(activity); - } - - public void hide() { - } - - public void show() { - } - - public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { - } - - public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { - } - - private static class DummyActionBar extends ActionBarWrapper { - } - - private static class RealActionBar extends ActionBarWrapper { - private final ActionBar actionBar; - - public RealActionBar(Activity activity) { - actionBar = activity.getActionBar(); - } - - @Override - public void hide() { - actionBar.hide(); - } - - @Override - public void show() { - actionBar.show(); - } - - @Override - public void addOnMenuVisibilityListener(final OnMenuVisibilityListener listener) { - actionBar.addOnMenuVisibilityListener(new ActionBar.OnMenuVisibilityListener() { - public void onMenuVisibilityChanged(boolean isVisible) { - listener.onMenuVisibilityChanged(isVisible); - } - }); - } - - @Override - public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { - actionBar.setDisplayHomeAsUpEnabled(showHomeAsUp); - } - } -} diff --git a/src/org/connectbot/ColorsActivity.java b/src/org/connectbot/ColorsActivity.java deleted file mode 100644 index 38336f7..0000000 --- a/src/org/connectbot/ColorsActivity.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.util.Arrays; -import java.util.List; - -import org.connectbot.util.Colors; -import org.connectbot.util.HostDatabase; -import org.connectbot.util.UberColorPickerDialog; -import org.connectbot.util.UberColorPickerDialog.OnColorChangedListener; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.MenuItem.OnMenuItemClickListener; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.GridView; -import android.widget.Spinner; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView.OnItemSelectedListener; - -/** - * @author Kenny Root - * - */ -public class ColorsActivity extends Activity implements OnItemClickListener, OnColorChangedListener, OnItemSelectedListener { - private GridView mColorGrid; - private Spinner mFgSpinner; - private Spinner mBgSpinner; - - private int mColorScheme; - - private List<Integer> mColorList; - private HostDatabase hostdb; - - private int mCurrentColor = 0; - - private int[] mDefaultColors; - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.act_colors); - - this.setTitle(String.format("%s: %s", - getResources().getText(R.string.app_name), - getResources().getText(R.string.title_colors))); - - mColorScheme = HostDatabase.DEFAULT_COLOR_SCHEME; - - hostdb = new HostDatabase(this); - - mColorList = Arrays.asList(hostdb.getColorsForScheme(mColorScheme)); - mDefaultColors = hostdb.getDefaultColorsForScheme(mColorScheme); - - mColorGrid = (GridView) findViewById(R.id.color_grid); - mColorGrid.setAdapter(new ColorsAdapter(true)); - mColorGrid.setOnItemClickListener(this); - mColorGrid.setSelection(0); - - mFgSpinner = (Spinner) findViewById(R.id.fg); - mFgSpinner.setAdapter(new ColorsAdapter(false)); - mFgSpinner.setSelection(mDefaultColors[0]); - mFgSpinner.setOnItemSelectedListener(this); - - mBgSpinner = (Spinner) findViewById(R.id.bg); - mBgSpinner.setAdapter(new ColorsAdapter(false)); - mBgSpinner.setSelection(mDefaultColors[1]); - mBgSpinner.setOnItemSelectedListener(this); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - - if (hostdb != null) { - hostdb.close(); - hostdb = null; - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (hostdb == null) - hostdb = new HostDatabase(this); - } - - private class ColorsAdapter extends BaseAdapter { - private boolean mSquareViews; - - public ColorsAdapter(boolean squareViews) { - mSquareViews = squareViews; - } - - public View getView(int position, View convertView, ViewGroup parent) { - ColorView c; - - if (convertView == null) { - c = new ColorView(ColorsActivity.this, mSquareViews); - } else { - c = (ColorView) convertView; - } - - c.setColor(mColorList.get(position)); - c.setNumber(position + 1); - - return c; - } - - public int getCount() { - return mColorList.size(); - } - - public Object getItem(int position) { - return mColorList.get(position); - } - - public long getItemId(int position) { - return position; - } - } - - private class ColorView extends View { - private boolean mSquare; - - private Paint mTextPaint; - private Paint mShadowPaint; - - // Things we paint - private int mBackgroundColor; - private String mText; - - private int mAscent; - private int mWidthCenter; - private int mHeightCenter; - - public ColorView(Context context, boolean square) { - super(context); - - mSquare = square; - - mTextPaint = new Paint(); - mTextPaint.setAntiAlias(true); - mTextPaint.setTextSize(16); - mTextPaint.setColor(0xFFFFFFFF); - mTextPaint.setTextAlign(Paint.Align.CENTER); - - mShadowPaint = new Paint(mTextPaint); - mShadowPaint.setStyle(Paint.Style.STROKE); - mShadowPaint.setStrokeCap(Paint.Cap.ROUND); - mShadowPaint.setStrokeJoin(Paint.Join.ROUND); - mShadowPaint.setStrokeWidth(4f); - mShadowPaint.setColor(0xFF000000); - - setPadding(10, 10, 10, 10); - } - - public void setColor(int color) { - mBackgroundColor = color; - } - - public void setNumber(int number) { - mText = Integer.toString(number); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = measureWidth(widthMeasureSpec); - - int height; - if (mSquare) - height = width; - else - height = measureHeight(heightMeasureSpec); - - mAscent = (int) mTextPaint.ascent(); - mWidthCenter = width / 2; - mHeightCenter = height / 2 - mAscent / 2; - - setMeasuredDimension(width, height); - } - - private int measureWidth(int measureSpec) { - int result = 0; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - if (specMode == MeasureSpec.EXACTLY) { - // We were told how big to be - result = specSize; - } else { - // Measure the text - result = (int) mTextPaint.measureText(mText) + getPaddingLeft() - + getPaddingRight(); - if (specMode == MeasureSpec.AT_MOST) { - // Respect AT_MOST value if that was what is called for by - // measureSpec - result = Math.min(result, specSize); - } - } - - return result; - } - - private int measureHeight(int measureSpec) { - int result = 0; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - mAscent = (int) mTextPaint.ascent(); - if (specMode == MeasureSpec.EXACTLY) { - // We were told how big to be - result = specSize; - } else { - // Measure the text (beware: ascent is a negative number) - result = (int) (-mAscent + mTextPaint.descent()) - + getPaddingTop() + getPaddingBottom(); - if (specMode == MeasureSpec.AT_MOST) { - // Respect AT_MOST value if that was what is called for by - // measureSpec - result = Math.min(result, specSize); - } - } - return result; - } - - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - canvas.drawColor(mBackgroundColor); - - canvas.drawText(mText, mWidthCenter, mHeightCenter, mShadowPaint); - canvas.drawText(mText, mWidthCenter, mHeightCenter, mTextPaint); - } - } - - private void editColor(int colorNumber) { - mCurrentColor = colorNumber; - new UberColorPickerDialog(this, this, mColorList.get(colorNumber)).show(); - } - - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - editColor(position); - } - - public void onNothingSelected(AdapterView<?> arg0) { } - - public void colorChanged(int value) { - hostdb.setGlobalColor(mCurrentColor, value); - mColorList.set(mCurrentColor, value); - mColorGrid.invalidateViews(); - } - - public void onItemSelected(AdapterView<?> parent, View view, int position, - long id) { - boolean needUpdate = false; - if (parent == mFgSpinner) { - if (position != mDefaultColors[0]) { - mDefaultColors[0] = position; - needUpdate = true; - } - } else if (parent == mBgSpinner) { - if (position != mDefaultColors[1]) { - mDefaultColors[1] = position; - needUpdate = true; - } - } - - if (needUpdate) - hostdb.setDefaultColorsForScheme(mColorScheme, mDefaultColors[0], mDefaultColors[1]); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuItem reset = menu.add(R.string.menu_colors_reset); - reset.setAlphabeticShortcut('r'); - reset.setNumericShortcut('1'); - reset.setIcon(android.R.drawable.ic_menu_revert); - reset.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem arg0) { - // Reset each individual color to defaults. - for (int i = 0; i < Colors.defaults.length; i++) { - if (mColorList.get(i) != Colors.defaults[i]) { - hostdb.setGlobalColor(i, Colors.defaults[i]); - mColorList.set(i, Colors.defaults[i]); - } - } - mColorGrid.invalidateViews(); - - // Reset the default FG/BG colors as well. - mFgSpinner.setSelection(HostDatabase.DEFAULT_FG_COLOR); - mBgSpinner.setSelection(HostDatabase.DEFAULT_BG_COLOR); - hostdb.setDefaultColorsForScheme(HostDatabase.DEFAULT_COLOR_SCHEME, - HostDatabase.DEFAULT_FG_COLOR, HostDatabase.DEFAULT_BG_COLOR); - - return true; - } - }); - - return true; - } -} diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java deleted file mode 100644 index 2359bea..0000000 --- a/src/org/connectbot/ConsoleActivity.java +++ /dev/null @@ -1,1175 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.lang.ref.WeakReference; -import java.util.List; - -import org.connectbot.bean.SelectionArea; -import org.connectbot.service.PromptHelper; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalKeyListener; -import org.connectbot.service.TerminalManager; -import org.connectbot.util.PreferenceConstants; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.media.AudioManager; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.preference.PreferenceManager; -import android.text.ClipboardManager; -import android.util.Log; -import android.view.GestureDetector; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.WindowManager; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.View.OnClickListener; -import android.view.View.OnKeyListener; -import android.view.View.OnTouchListener; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.view.inputmethod.InputMethodManager; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.RelativeLayout; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.ViewFlipper; -import android.widget.AdapterView.OnItemClickListener; - -import de.mud.terminal.vt320; - -public class ConsoleActivity extends Activity { - public final static String TAG = "ConnectBot.ConsoleActivity"; - - protected static final int REQUEST_EDIT = 1; - - private static final int CLICK_TIME = 400; - private static final float MAX_CLICK_DISTANCE = 25f; - private static final int KEYBOARD_DISPLAY_TIME = 1500; - - // Direction to shift the ViewFlipper - private static final int SHIFT_LEFT = 0; - private static final int SHIFT_RIGHT = 1; - - protected ViewFlipper flip = null; - protected TerminalManager bound = null; - protected LayoutInflater inflater = null; - - private SharedPreferences prefs = null; - - // determines whether or not menuitem accelerators are bound - // otherwise they collide with an external keyboard's CTRL-char - private boolean hardKeyboard = false; - - protected Uri requested; - - protected ClipboardManager clipboard; - private RelativeLayout stringPromptGroup; - protected EditText stringPrompt; - private TextView stringPromptInstructions; - - private RelativeLayout booleanPromptGroup; - private TextView booleanPrompt; - private Button booleanYes, booleanNo; - - private RelativeLayout keyboardGroup; - private Runnable keyboardGroupHider; - - private TextView empty; - - private Animation slide_left_in, slide_left_out, slide_right_in, slide_right_out, fade_stay_hidden, fade_out_delayed; - - private Animation keyboard_fade_in, keyboard_fade_out; - private float lastX, lastY; - - private InputMethodManager inputManager; - - private MenuItem disconnect, copy, paste, portForward, resize, urlscan; - - protected TerminalBridge copySource = null; - private int lastTouchRow, lastTouchCol; - - private boolean forcedOrientation; - - private Handler handler = new Handler(); - - private ImageView mKeyboardButton; - - private ActionBarWrapper actionBar; - private boolean inActionBarMenu = false; - - private ServiceConnection connection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - bound = ((TerminalManager.TerminalBinder) service).getService(); - - // let manager know about our event handling services - bound.disconnectHandler = disconnectHandler; - - Log.d(TAG, String.format("Connected to TerminalManager and found bridges.size=%d", bound.bridges.size())); - - bound.setResizeAllowed(true); - - // clear out any existing bridges and record requested index - flip.removeAllViews(); - - final String requestedNickname = (requested != null) ? requested.getFragment() : null; - int requestedIndex = 0; - - TerminalBridge requestedBridge = bound.getConnectedBridge(requestedNickname); - - // If we didn't find the requested connection, try opening it - if (requestedNickname != null && requestedBridge == null) { - try { - Log.d(TAG, String.format("We couldnt find an existing bridge with URI=%s (nickname=%s), so creating one now", requested.toString(), requestedNickname)); - requestedBridge = bound.openConnection(requested); - } catch(Exception e) { - Log.e(TAG, "Problem while trying to create new requested bridge from URI", e); - } - } - - // create views for all bridges on this service - for (TerminalBridge bridge : bound.bridges) { - - final int currentIndex = addNewTerminalView(bridge); - - // check to see if this bridge was requested - if (bridge == requestedBridge) - requestedIndex = currentIndex; - } - - setDisplayedTerminal(requestedIndex); - } - - public void onServiceDisconnected(ComponentName className) { - // tell each bridge to forget about our prompt handler - synchronized (bound.bridges) { - for(TerminalBridge bridge : bound.bridges) - bridge.promptHelper.setHandler(null); - } - - flip.removeAllViews(); - updateEmptyVisible(); - bound = null; - } - }; - - protected Handler promptHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - // someone below us requested to display a prompt - updatePromptVisible(); - } - }; - - protected Handler disconnectHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - Log.d(TAG, "Someone sending HANDLE_DISCONNECT to parentHandler"); - - // someone below us requested to display a password dialog - // they are sending nickname and requested - TerminalBridge bridge = (TerminalBridge)msg.obj; - - if (bridge.isAwaitingClose()) - closeBridge(bridge); - } - }; - - /** - * @param bridge - */ - private void closeBridge(final TerminalBridge bridge) { - synchronized (flip) { - final int flipIndex = getFlipIndex(bridge); - - if (flipIndex >= 0) { - if (flip.getDisplayedChild() == flipIndex) { - shiftCurrentTerminal(SHIFT_LEFT); - } - flip.removeViewAt(flipIndex); - - /* TODO Remove this workaround when ViewFlipper is fixed to listen - * to view removals. Android Issue 1784 - */ - final int numChildren = flip.getChildCount(); - if (flip.getDisplayedChild() >= numChildren && - numChildren > 0) { - flip.setDisplayedChild(numChildren - 1); - } - - updateEmptyVisible(); - } - - // If we just closed the last bridge, go back to the previous activity. - if (flip.getChildCount() == 0) { - finish(); - } - } - } - - protected View findCurrentView(int id) { - View view = flip.getCurrentView(); - if(view == null) return null; - return view.findViewById(id); - } - - protected PromptHelper getCurrentPromptHelper() { - View view = findCurrentView(R.id.console_flip); - if(!(view instanceof TerminalView)) return null; - return ((TerminalView)view).bridge.promptHelper; - } - - protected void hideAllPrompts() { - stringPromptGroup.setVisibility(View.GONE); - booleanPromptGroup.setVisibility(View.GONE); - } - - private void showEmulatedKeys() { - keyboardGroup.startAnimation(keyboard_fade_in); - keyboardGroup.setVisibility(View.VISIBLE); - actionBar.show(); - - if (keyboardGroupHider != null) - handler.removeCallbacks(keyboardGroupHider); - keyboardGroupHider = new Runnable() { - public void run() { - if (keyboardGroup.getVisibility() == View.GONE || inActionBarMenu) - return; - - keyboardGroup.startAnimation(keyboard_fade_out); - keyboardGroup.setVisibility(View.GONE); - actionBar.hide(); - keyboardGroupHider = null; - } - }; - handler.postDelayed(keyboardGroupHider, KEYBOARD_DISPLAY_TIME); - } - - private void hideEmulatedKeys() { - if (keyboardGroupHider != null) - handler.removeCallbacks(keyboardGroupHider); - keyboardGroup.setVisibility(View.GONE); - actionBar.hide(); - } - - // more like configureLaxMode -- enable network IO on UI thread - private void configureStrictMode() { - try { - Class.forName("android.os.StrictMode"); - StrictModeSetup.run(); - } catch (ClassNotFoundException e) { - } - } - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - configureStrictMode(); - hardKeyboard = getResources().getConfiguration().keyboard == - Configuration.KEYBOARD_QWERTY; - - this.setContentView(R.layout.act_console); - - clipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE); - prefs = PreferenceManager.getDefaultSharedPreferences(this); - - // hide status bar if requested by user - if (prefs.getBoolean(PreferenceConstants.FULLSCREEN, false)) { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - // TODO find proper way to disable volume key beep if it exists. - setVolumeControlStream(AudioManager.STREAM_MUSIC); - - // handle requested console from incoming intent - requested = getIntent().getData(); - - inflater = LayoutInflater.from(this); - - flip = (ViewFlipper)findViewById(R.id.console_flip); - empty = (TextView)findViewById(android.R.id.empty); - - stringPromptGroup = (RelativeLayout) findViewById(R.id.console_password_group); - stringPromptInstructions = (TextView) findViewById(R.id.console_password_instructions); - stringPrompt = (EditText)findViewById(R.id.console_password); - stringPrompt.setOnKeyListener(new OnKeyListener() { - public boolean onKey(View v, int keyCode, KeyEvent event) { - if(event.getAction() == KeyEvent.ACTION_UP) return false; - if(keyCode != KeyEvent.KEYCODE_ENTER) return false; - - // pass collected password down to current terminal - String value = stringPrompt.getText().toString(); - - PromptHelper helper = getCurrentPromptHelper(); - if(helper == null) return false; - helper.setResponse(value); - - // finally clear password for next user - stringPrompt.setText(""); - updatePromptVisible(); - - return true; - } - }); - - booleanPromptGroup = (RelativeLayout) findViewById(R.id.console_boolean_group); - booleanPrompt = (TextView)findViewById(R.id.console_prompt); - - booleanYes = (Button)findViewById(R.id.console_prompt_yes); - booleanYes.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - PromptHelper helper = getCurrentPromptHelper(); - if(helper == null) return; - helper.setResponse(Boolean.TRUE); - updatePromptVisible(); - } - }); - - booleanNo = (Button)findViewById(R.id.console_prompt_no); - booleanNo.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - PromptHelper helper = getCurrentPromptHelper(); - if(helper == null) return; - helper.setResponse(Boolean.FALSE); - updatePromptVisible(); - } - }); - - // preload animations for terminal switching - slide_left_in = AnimationUtils.loadAnimation(this, R.anim.slide_left_in); - slide_left_out = AnimationUtils.loadAnimation(this, R.anim.slide_left_out); - slide_right_in = AnimationUtils.loadAnimation(this, R.anim.slide_right_in); - slide_right_out = AnimationUtils.loadAnimation(this, R.anim.slide_right_out); - - fade_out_delayed = AnimationUtils.loadAnimation(this, R.anim.fade_out_delayed); - fade_stay_hidden = AnimationUtils.loadAnimation(this, R.anim.fade_stay_hidden); - - // Preload animation for keyboard button - keyboard_fade_in = AnimationUtils.loadAnimation(this, R.anim.keyboard_fade_in); - keyboard_fade_out = AnimationUtils.loadAnimation(this, R.anim.keyboard_fade_out); - - inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - - keyboardGroup = (RelativeLayout) findViewById(R.id.keyboard_group); - - mKeyboardButton = (ImageView) findViewById(R.id.button_keyboard); - mKeyboardButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - View flip = findCurrentView(R.id.console_flip); - if (flip == null) - return; - - inputManager.showSoftInput(flip, InputMethodManager.SHOW_FORCED); - hideEmulatedKeys(); - } - }); - - final ImageView ctrlButton = (ImageView) findViewById(R.id.button_ctrl); - ctrlButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - View flip = findCurrentView(R.id.console_flip); - if (flip == null) return; - TerminalView terminal = (TerminalView)flip; - - TerminalKeyListener handler = terminal.bridge.getKeyHandler(); - handler.metaPress(TerminalKeyListener.OUR_CTRL_ON); - hideEmulatedKeys(); - } - }); - - final ImageView escButton = (ImageView) findViewById(R.id.button_esc); - escButton.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - View flip = findCurrentView(R.id.console_flip); - if (flip == null) return; - TerminalView terminal = (TerminalView)flip; - - TerminalKeyListener handler = terminal.bridge.getKeyHandler(); - handler.sendEscape(); - hideEmulatedKeys(); - } - }); - - actionBar = ActionBarWrapper.getActionBar(this); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.hide(); - actionBar.addOnMenuVisibilityListener(new ActionBarWrapper.OnMenuVisibilityListener() { - public void onMenuVisibilityChanged(boolean isVisible) { - inActionBarMenu = isVisible; - if (isVisible == false) { - hideEmulatedKeys(); - } - } - }); - - // detect fling gestures to switch between terminals - final GestureDetector detect = new GestureDetector(new GestureDetector.SimpleOnGestureListener() { - private float totalY = 0; - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - - final float distx = e2.getRawX() - e1.getRawX(); - final float disty = e2.getRawY() - e1.getRawY(); - final int goalwidth = flip.getWidth() / 2; - - // need to slide across half of display to trigger console change - // make sure user kept a steady hand horizontally - if (Math.abs(disty) < (flip.getHeight() / 4)) { - if (distx > goalwidth) { - shiftCurrentTerminal(SHIFT_RIGHT); - return true; - } - - if (distx < -goalwidth) { - shiftCurrentTerminal(SHIFT_LEFT); - return true; - } - - } - - return false; - } - - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - - // if copying, then ignore - if (copySource != null && copySource.isSelectingForCopy()) - return false; - - if (e1 == null || e2 == null) - return false; - - // if releasing then reset total scroll - if (e2.getAction() == MotionEvent.ACTION_UP) { - totalY = 0; - } - - // activate consider if within x tolerance - if (Math.abs(e1.getX() - e2.getX()) < ViewConfiguration.getTouchSlop() * 4) { - - View flip = findCurrentView(R.id.console_flip); - if(flip == null) return false; - TerminalView terminal = (TerminalView)flip; - - // estimate how many rows we have scrolled through - // accumulate distance that doesn't trigger immediate scroll - totalY += distanceY; - final int moved = (int)(totalY / terminal.bridge.charHeight); - - // consume as scrollback only if towards right half of screen - if (e2.getX() > flip.getWidth() / 2) { - if (moved != 0) { - int base = terminal.bridge.buffer.getWindowBase(); - terminal.bridge.buffer.setWindowBase(base + moved); - totalY = 0; - return true; - } - } else { - // otherwise consume as pgup/pgdown for every 5 lines - if (moved > 5) { - ((vt320)terminal.bridge.buffer).keyPressed(vt320.KEY_PAGE_DOWN, ' ', 0); - terminal.bridge.tryKeyVibrate(); - totalY = 0; - return true; - } else if (moved < -5) { - ((vt320)terminal.bridge.buffer).keyPressed(vt320.KEY_PAGE_UP, ' ', 0); - terminal.bridge.tryKeyVibrate(); - totalY = 0; - return true; - } - - } - - } - - return false; - } - - - }); - - flip.setLongClickable(true); - flip.setOnTouchListener(new OnTouchListener() { - - public boolean onTouch(View v, MotionEvent event) { - - // when copying, highlight the area - if (copySource != null && copySource.isSelectingForCopy()) { - int row = (int)Math.floor(event.getY() / copySource.charHeight); - int col = (int)Math.floor(event.getX() / copySource.charWidth); - - SelectionArea area = copySource.getSelectionArea(); - - switch(event.getAction()) { - case MotionEvent.ACTION_DOWN: - // recording starting area - if (area.isSelectingOrigin()) { - area.setRow(row); - area.setColumn(col); - lastTouchRow = row; - lastTouchCol = col; - copySource.redraw(); - } - return true; - case MotionEvent.ACTION_MOVE: - /* ignore when user hasn't moved since last time so - * we can fine-tune with directional pad - */ - if (row == lastTouchRow && col == lastTouchCol) - return true; - - // if the user moves, start the selection for other corner - area.finishSelectingOrigin(); - - // update selected area - area.setRow(row); - area.setColumn(col); - lastTouchRow = row; - lastTouchCol = col; - copySource.redraw(); - return true; - case MotionEvent.ACTION_UP: - /* If they didn't move their finger, maybe they meant to - * select the rest of the text with the directional pad. - */ - if (area.getLeft() == area.getRight() && - area.getTop() == area.getBottom()) { - return true; - } - - // copy selected area to clipboard - String copiedText = area.copyFrom(copySource.buffer); - - clipboard.setText(copiedText); - Toast.makeText(ConsoleActivity.this, getString(R.string.console_copy_done, copiedText.length()), Toast.LENGTH_LONG).show(); - // fall through to clear state - - case MotionEvent.ACTION_CANCEL: - // make sure we clear any highlighted area - area.reset(); - copySource.setSelectingForCopy(false); - copySource.redraw(); - return true; - } - } - - Configuration config = getResources().getConfiguration(); - - if (event.getAction() == MotionEvent.ACTION_DOWN) { - lastX = event.getX(); - lastY = event.getY(); - } else if (event.getAction() == MotionEvent.ACTION_UP - && keyboardGroup.getVisibility() == View.GONE - && event.getEventTime() - event.getDownTime() < CLICK_TIME - && Math.abs(event.getX() - lastX) < MAX_CLICK_DISTANCE - && Math.abs(event.getY() - lastY) < MAX_CLICK_DISTANCE) { - showEmulatedKeys(); - } - - // pass any touch events back to detector - return detect.onTouchEvent(event); - } - - }); - - } - - /** - * - */ - private void configureOrientation() { - String rotateDefault; - if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_NOKEYS) - rotateDefault = PreferenceConstants.ROTATION_PORTRAIT; - else - rotateDefault = PreferenceConstants.ROTATION_LANDSCAPE; - - String rotate = prefs.getString(PreferenceConstants.ROTATION, rotateDefault); - if (PreferenceConstants.ROTATION_DEFAULT.equals(rotate)) - rotate = rotateDefault; - - // request a forced orientation if requested by user - if (PreferenceConstants.ROTATION_LANDSCAPE.equals(rotate)) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - forcedOrientation = true; - } else if (PreferenceConstants.ROTATION_PORTRAIT.equals(rotate)) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - forcedOrientation = true; - } else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - forcedOrientation = false; - } - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - View view = findCurrentView(R.id.console_flip); - final boolean activeTerminal = (view instanceof TerminalView); - boolean sessionOpen = false; - boolean disconnected = false; - boolean canForwardPorts = false; - - if (activeTerminal) { - TerminalBridge bridge = ((TerminalView) view).bridge; - sessionOpen = bridge.isSessionOpen(); - disconnected = bridge.isDisconnected(); - canForwardPorts = bridge.canFowardPorts(); - } - - menu.setQwertyMode(true); - - disconnect = menu.add(R.string.list_host_disconnect); - if (hardKeyboard) - disconnect.setAlphabeticShortcut('w'); - if (!sessionOpen && disconnected) - disconnect.setTitle(R.string.console_menu_close); - disconnect.setEnabled(activeTerminal); - disconnect.setIcon(android.R.drawable.ic_menu_close_clear_cancel); - disconnect.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // disconnect or close the currently visible session - TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); - TerminalBridge bridge = terminalView.bridge; - - bridge.dispatchDisconnect(true); - return true; - } - }); - - copy = menu.add(R.string.console_menu_copy); - if (hardKeyboard) - copy.setAlphabeticShortcut('c'); - copy.setIcon(android.R.drawable.ic_menu_set_as); - copy.setEnabled(activeTerminal); - copy.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // mark as copying and reset any previous bounds - TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); - copySource = terminalView.bridge; - - SelectionArea area = copySource.getSelectionArea(); - area.reset(); - area.setBounds(copySource.buffer.getColumns(), copySource.buffer.getRows()); - - copySource.setSelectingForCopy(true); - - // Make sure we show the initial selection - copySource.redraw(); - - Toast.makeText(ConsoleActivity.this, getString(R.string.console_copy_start), Toast.LENGTH_LONG).show(); - return true; - } - }); - - paste = menu.add(R.string.console_menu_paste); - if (hardKeyboard) - paste.setAlphabeticShortcut('v'); - paste.setIcon(android.R.drawable.ic_menu_edit); - paste.setEnabled(clipboard.hasText() && sessionOpen); - paste.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // force insert of clipboard text into current console - TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); - TerminalBridge bridge = terminalView.bridge; - - // pull string from clipboard and generate all events to force down - String clip = clipboard.getText().toString(); - bridge.injectString(clip); - - return true; - } - }); - - portForward = menu.add(R.string.console_menu_portforwards); - if (hardKeyboard) - portForward.setAlphabeticShortcut('f'); - portForward.setIcon(android.R.drawable.ic_menu_manage); - portForward.setEnabled(sessionOpen && canForwardPorts); - portForward.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); - TerminalBridge bridge = terminalView.bridge; - - Intent intent = new Intent(ConsoleActivity.this, PortForwardListActivity.class); - intent.putExtra(Intent.EXTRA_TITLE, bridge.host.getId()); - ConsoleActivity.this.startActivityForResult(intent, REQUEST_EDIT); - return true; - } - }); - - urlscan = menu.add(R.string.console_menu_urlscan); - if (hardKeyboard) - urlscan.setAlphabeticShortcut('u'); - urlscan.setIcon(android.R.drawable.ic_menu_search); - urlscan.setEnabled(activeTerminal); - urlscan.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - final TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); - - List<String> urls = terminalView.bridge.scanForURLs(); - - Dialog urlDialog = new Dialog(ConsoleActivity.this); - urlDialog.setTitle(R.string.console_menu_urlscan); - - ListView urlListView = new ListView(ConsoleActivity.this); - URLItemListener urlListener = new URLItemListener(ConsoleActivity.this); - urlListView.setOnItemClickListener(urlListener); - - urlListView.setAdapter(new ArrayAdapter<String>(ConsoleActivity.this, android.R.layout.simple_list_item_1, urls)); - urlDialog.setContentView(urlListView); - urlDialog.show(); - - return true; - } - }); - - resize = menu.add(R.string.console_menu_resize); - if (hardKeyboard) - resize.setAlphabeticShortcut('s'); - resize.setIcon(android.R.drawable.ic_menu_crop); - resize.setEnabled(sessionOpen); - resize.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - final TerminalView terminalView = (TerminalView) findCurrentView(R.id.console_flip); - - final View resizeView = inflater.inflate(R.layout.dia_resize, null, false); - new AlertDialog.Builder(ConsoleActivity.this) - .setView(resizeView) - .setPositiveButton(R.string.button_resize, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - int width, height; - try { - width = Integer.parseInt(((EditText) resizeView - .findViewById(R.id.width)) - .getText().toString()); - height = Integer.parseInt(((EditText) resizeView - .findViewById(R.id.height)) - .getText().toString()); - } catch (NumberFormatException nfe) { - // TODO change this to a real dialog where we can - // make the input boxes turn red to indicate an error. - return; - } - - terminalView.forceSize(width, height); - } - }).setNegativeButton(android.R.string.cancel, null).create().show(); - - return true; - } - }); - - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - - setVolumeControlStream(AudioManager.STREAM_NOTIFICATION); - - final View view = findCurrentView(R.id.console_flip); - boolean activeTerminal = (view instanceof TerminalView); - boolean sessionOpen = false; - boolean disconnected = false; - boolean canForwardPorts = false; - - if (activeTerminal) { - TerminalBridge bridge = ((TerminalView) view).bridge; - sessionOpen = bridge.isSessionOpen(); - disconnected = bridge.isDisconnected(); - canForwardPorts = bridge.canFowardPorts(); - } - - disconnect.setEnabled(activeTerminal); - if (sessionOpen || !disconnected) - disconnect.setTitle(R.string.list_host_disconnect); - else - disconnect.setTitle(R.string.console_menu_close); - copy.setEnabled(activeTerminal); - paste.setEnabled(clipboard.hasText() && sessionOpen); - portForward.setEnabled(sessionOpen && canForwardPorts); - urlscan.setEnabled(activeTerminal); - resize.setEnabled(sessionOpen); - - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - Intent intent = new Intent(this, HostListActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - @Override - public void onOptionsMenuClosed(Menu menu) { - super.onOptionsMenuClosed(menu); - - setVolumeControlStream(AudioManager.STREAM_MUSIC); - } - - @Override - public void onStart() { - super.onStart(); - - // connect with manager service to find all bridges - // when connected it will insert all views - bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); - } - - @Override - public void onPause() { - super.onPause(); - Log.d(TAG, "onPause called"); - - if (forcedOrientation && bound != null) - bound.setResizeAllowed(false); - } - - @Override - public void onResume() { - super.onResume(); - Log.d(TAG, "onResume called"); - - // Make sure we don't let the screen fall asleep. - // This also keeps the Wi-Fi chipset from disconnecting us. - if (prefs.getBoolean(PreferenceConstants.KEEP_ALIVE, true)) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } else { - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - configureOrientation(); - - if (forcedOrientation && bound != null) - bound.setResizeAllowed(true); - } - - /* (non-Javadoc) - * @see android.app.Activity#onNewIntent(android.content.Intent) - */ - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - Log.d(TAG, "onNewIntent called"); - - requested = intent.getData(); - - if (requested == null) { - Log.e(TAG, "Got null intent data in onNewIntent()"); - return; - } - - if (bound == null) { - Log.e(TAG, "We're not bound in onNewIntent()"); - return; - } - - TerminalBridge requestedBridge = bound.getConnectedBridge(requested.getFragment()); - int requestedIndex = 0; - - synchronized (flip) { - if (requestedBridge == null) { - // If we didn't find the requested connection, try opening it - - try { - Log.d(TAG, String.format("We couldnt find an existing bridge with URI=%s (nickname=%s),"+ - "so creating one now", requested.toString(), requested.getFragment())); - requestedBridge = bound.openConnection(requested); - } catch(Exception e) { - Log.e(TAG, "Problem while trying to create new requested bridge from URI", e); - // TODO: We should display an error dialog here. - return; - } - - requestedIndex = addNewTerminalView(requestedBridge); - } else { - final int flipIndex = getFlipIndex(requestedBridge); - if (flipIndex > requestedIndex) { - requestedIndex = flipIndex; - } - } - - setDisplayedTerminal(requestedIndex); - } - } - - @Override - public void onStop() { - super.onStop(); - - unbindService(connection); - } - - protected void shiftCurrentTerminal(final int direction) { - View overlay; - synchronized (flip) { - boolean shouldAnimate = flip.getChildCount() > 1; - - // Only show animation if there is something else to go to. - if (shouldAnimate) { - // keep current overlay from popping up again - overlay = findCurrentView(R.id.terminal_overlay); - if (overlay != null) - overlay.startAnimation(fade_stay_hidden); - - if (direction == SHIFT_LEFT) { - flip.setInAnimation(slide_left_in); - flip.setOutAnimation(slide_left_out); - flip.showNext(); - } else if (direction == SHIFT_RIGHT) { - flip.setInAnimation(slide_right_in); - flip.setOutAnimation(slide_right_out); - flip.showPrevious(); - } - } - - ConsoleActivity.this.updateDefault(); - - if (shouldAnimate) { - // show overlay on new slide and start fade - overlay = findCurrentView(R.id.terminal_overlay); - if (overlay != null) - overlay.startAnimation(fade_out_delayed); - } - - updatePromptVisible(); - } - } - - /** - * Save the currently shown {@link TerminalView} as the default. This is - * saved back down into {@link TerminalManager} where we can read it again - * later. - */ - private void updateDefault() { - // update the current default terminal - View view = findCurrentView(R.id.console_flip); - if(!(view instanceof TerminalView)) return; - - TerminalView terminal = (TerminalView)view; - if(bound == null) return; - bound.defaultBridge = terminal.bridge; - } - - protected void updateEmptyVisible() { - // update visibility of empty status message - empty.setVisibility((flip.getChildCount() == 0) ? View.VISIBLE : View.GONE); - } - - /** - * Show any prompts requested by the currently visible {@link TerminalView}. - */ - protected void updatePromptVisible() { - // check if our currently-visible terminalbridge is requesting any prompt services - View view = findCurrentView(R.id.console_flip); - - // Hide all the prompts in case a prompt request was canceled - hideAllPrompts(); - - if(!(view instanceof TerminalView)) { - // we dont have an active view, so hide any prompts - return; - } - - PromptHelper prompt = ((TerminalView)view).bridge.promptHelper; - if(String.class.equals(prompt.promptRequested)) { - stringPromptGroup.setVisibility(View.VISIBLE); - - String instructions = prompt.promptInstructions; - if (instructions != null && instructions.length() > 0) { - stringPromptInstructions.setVisibility(View.VISIBLE); - stringPromptInstructions.setText(instructions); - } else - stringPromptInstructions.setVisibility(View.GONE); - stringPrompt.setText(""); - stringPrompt.setHint(prompt.promptHint); - stringPrompt.requestFocus(); - - } else if(Boolean.class.equals(prompt.promptRequested)) { - booleanPromptGroup.setVisibility(View.VISIBLE); - booleanPrompt.setText(prompt.promptHint); - booleanYes.requestFocus(); - - } else { - hideAllPrompts(); - view.requestFocus(); - } - } - - private class URLItemListener implements OnItemClickListener { - private WeakReference<Context> contextRef; - - URLItemListener(Context context) { - this.contextRef = new WeakReference<Context>(context); - } - - public void onItemClick(AdapterView<?> arg0, View view, int position, long id) { - Context context = contextRef.get(); - - if (context == null) - return; - - try { - TextView urlView = (TextView) view; - - String url = urlView.getText().toString(); - if (url.indexOf("://") < 0) - url = "http://" + url; - - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - context.startActivity(intent); - } catch (Exception e) { - Log.e(TAG, "couldn't open URL", e); - // We should probably tell the user that we couldn't find a handler... - } - } - - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - Log.d(TAG, String.format("onConfigurationChanged; requestedOrientation=%d, newConfig.orientation=%d", getRequestedOrientation(), newConfig.orientation)); - if (bound != null) { - if (forcedOrientation && - (newConfig.orientation != Configuration.ORIENTATION_LANDSCAPE && - getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) || - (newConfig.orientation != Configuration.ORIENTATION_PORTRAIT && - getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)) - bound.setResizeAllowed(false); - else - bound.setResizeAllowed(true); - - bound.hardKeyboardHidden = (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES); - - mKeyboardButton.setVisibility(bound.hardKeyboardHidden ? View.VISIBLE : View.GONE); - } - } - - /** - * Adds a new TerminalBridge to the current set of views in our ViewFlipper. - * - * @param bridge TerminalBridge to add to our ViewFlipper - * @return the child index of the new view in the ViewFlipper - */ - private int addNewTerminalView(TerminalBridge bridge) { - // let them know about our prompt handler services - bridge.promptHelper.setHandler(promptHandler); - - // inflate each terminal view - RelativeLayout view = (RelativeLayout)inflater.inflate(R.layout.item_terminal, flip, false); - - // set the terminal overlay text - TextView overlay = (TextView)view.findViewById(R.id.terminal_overlay); - overlay.setText(bridge.host.getNickname()); - - // and add our terminal view control, using index to place behind overlay - TerminalView terminal = new TerminalView(ConsoleActivity.this, bridge); - terminal.setId(R.id.console_flip); - view.addView(terminal, 0); - - synchronized (flip) { - // finally attach to the flipper - flip.addView(view); - return flip.getChildCount() - 1; - } - } - - private int getFlipIndex(TerminalBridge bridge) { - synchronized (flip) { - final int children = flip.getChildCount(); - for (int i = 0; i < children; i++) { - final View view = flip.getChildAt(i).findViewById(R.id.console_flip); - - if (view == null || !(view instanceof TerminalView)) { - // How did that happen? - continue; - } - - final TerminalView tv = (TerminalView) view; - - if (tv.bridge == bridge) { - return i; - } - } - } - - return -1; - } - - /** - * Displays the child in the ViewFlipper at the requestedIndex and updates the prompts. - * - * @param requestedIndex the index of the terminal view to display - */ - private void setDisplayedTerminal(int requestedIndex) { - synchronized (flip) { - try { - // show the requested bridge if found, also fade out overlay - flip.setDisplayedChild(requestedIndex); - flip.getCurrentView().findViewById(R.id.terminal_overlay) - .startAnimation(fade_out_delayed); - } catch (NullPointerException npe) { - Log.d(TAG, "View went away when we were about to display it", npe); - } - - updatePromptVisible(); - updateEmptyVisible(); - } - } -} diff --git a/src/org/connectbot/GeneratePubkeyActivity.java b/src/org/connectbot/GeneratePubkeyActivity.java deleted file mode 100644 index 3a438c5..0000000 --- a/src/org/connectbot/GeneratePubkeyActivity.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; - -import org.connectbot.bean.PubkeyBean; -import org.connectbot.util.EntropyDialog; -import org.connectbot.util.EntropyView; -import org.connectbot.util.OnEntropyGatheredListener; -import org.connectbot.util.PubkeyDatabase; -import org.connectbot.util.PubkeyUtils; - -import android.app.Activity; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnFocusChangeListener; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.RadioGroup; -import android.widget.RadioGroup.OnCheckedChangeListener; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; - -import com.trilead.ssh2.signature.ECDSASHA2Verify; - -public class GeneratePubkeyActivity extends Activity implements OnEntropyGatheredListener { - /** - * - */ - private static final int RSA_MINIMUM_BITS = 768; - - public final static String TAG = "ConnectBot.GeneratePubkeyActivity"; - - final static int DEFAULT_BITS = 1024; - - final static int[] ECDSA_SIZES = ECDSASHA2Verify.getCurveSizes(); - - final static int ECDSA_DEFAULT_BITS = ECDSA_SIZES[0]; - - private LayoutInflater inflater = null; - - private EditText nickname; - private RadioGroup keyTypeGroup; - private SeekBar bitsSlider; - private EditText bitsText; - private CheckBox unlockAtStartup; - private CheckBox confirmUse; - private Button save; - private Dialog entropyDialog; - private ProgressDialog progress; - - private EditText password1, password2; - - private String keyType = PubkeyDatabase.KEY_TYPE_RSA; - private int minBits = 768; - private int bits = DEFAULT_BITS; - - private byte[] entropy; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - setContentView(R.layout.act_generatepubkey); - - nickname = (EditText) findViewById(R.id.nickname); - - keyTypeGroup = (RadioGroup) findViewById(R.id.key_type); - - bitsText = (EditText) findViewById(R.id.bits); - bitsSlider = (SeekBar) findViewById(R.id.bits_slider); - - password1 = (EditText) findViewById(R.id.password1); - password2 = (EditText) findViewById(R.id.password2); - - unlockAtStartup = (CheckBox) findViewById(R.id.unlock_at_startup); - - confirmUse = (CheckBox) findViewById(R.id.confirm_use); - - save = (Button) findViewById(R.id.save); - - inflater = LayoutInflater.from(this); - - nickname.addTextChangedListener(textChecker); - password1.addTextChangedListener(textChecker); - password2.addTextChangedListener(textChecker); - - keyTypeGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() { - - public void onCheckedChanged(RadioGroup group, int checkedId) { - if (checkedId == R.id.rsa) { - minBits = RSA_MINIMUM_BITS; - - bitsSlider.setEnabled(true); - bitsSlider.setProgress(DEFAULT_BITS - minBits); - - bitsText.setText(String.valueOf(DEFAULT_BITS)); - bitsText.setEnabled(true); - - keyType = PubkeyDatabase.KEY_TYPE_RSA; - } else if (checkedId == R.id.dsa) { - // DSA keys can only be 1024 bits - - bitsSlider.setEnabled(false); - bitsSlider.setProgress(DEFAULT_BITS - minBits); - - bitsText.setText(String.valueOf(DEFAULT_BITS)); - bitsText.setEnabled(false); - - keyType = PubkeyDatabase.KEY_TYPE_DSA; - } else if (checkedId == R.id.ec) { - minBits = ECDSA_DEFAULT_BITS; - - bitsSlider.setEnabled(true); - bitsSlider.setProgress(ECDSA_DEFAULT_BITS - minBits); - - bitsText.setText(String.valueOf(ECDSA_DEFAULT_BITS)); - bitsText.setEnabled(true); - - keyType = PubkeyDatabase.KEY_TYPE_EC; - } - } - }); - - bitsSlider.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { - - public void onProgressChanged(SeekBar seekBar, int progress, - boolean fromTouch) { - if (PubkeyDatabase.KEY_TYPE_EC.equals(keyType)) { - bits = getClosestFieldSize(progress + minBits); - seekBar.setProgress(bits - minBits); - } else { - // Stay evenly divisible by 8 because it looks nicer to have - // 2048 than 2043 bits. - final int ourProgress = progress - (progress % 8); - bits = minBits + ourProgress; - } - - bitsText.setText(String.valueOf(bits)); - } - - public void onStartTrackingTouch(SeekBar seekBar) { - // We don't care about the start. - } - - public void onStopTrackingTouch(SeekBar seekBar) { - // We don't care about the stop. - } - }); - - bitsText.setOnFocusChangeListener(new OnFocusChangeListener() { - public void onFocusChange(View v, boolean hasFocus) { - if (!hasFocus) { - final boolean isEc = PubkeyDatabase.KEY_TYPE_EC.equals(keyType); - try { - bits = Integer.parseInt(bitsText.getText().toString()); - if (bits < minBits) { - bits = minBits; - bitsText.setText(String.valueOf(bits)); - } - if (isEc) { - bits = getClosestFieldSize(bits); - } - } catch (NumberFormatException nfe) { - bits = isEc ? ECDSA_DEFAULT_BITS : DEFAULT_BITS; - bitsText.setText(String.valueOf(bits)); - } - - bitsSlider.setProgress(bits - minBits); - } - } - }); - - save.setOnClickListener(new OnClickListener() { - public void onClick(View view) { - GeneratePubkeyActivity.this.save.setEnabled(false); - - GeneratePubkeyActivity.this.startEntropyGather(); - } - }); - - } - - private void checkEntries() { - boolean allowSave = true; - - if (!password1.getText().toString().equals(password2.getText().toString())) - allowSave = false; - - if (nickname.getText().length() == 0) - allowSave = false; - - save.setEnabled(allowSave); - } - - private void startEntropyGather() { - final View entropyView = inflater.inflate(R.layout.dia_gatherentropy, null, false); - ((EntropyView)entropyView.findViewById(R.id.entropy)).addOnEntropyGatheredListener(GeneratePubkeyActivity.this); - entropyDialog = new EntropyDialog(GeneratePubkeyActivity.this, entropyView); - entropyDialog.show(); - } - - public void onEntropyGathered(byte[] entropy) { - // For some reason the entropy dialog was aborted, exit activity - if (entropy == null) { - finish(); - return; - } - - this.entropy = entropy.clone(); - - int numSetBits = 0; - for (int i = 0; i < 20; i++) - numSetBits += measureNumberOfSetBits(this.entropy[i]); - - Log.d(TAG, "Entropy distribution=" + (int)(100.0 * numSetBits / 160.0) + "%"); - - Log.d(TAG, "entropy gathered; attemping to generate key..."); - startKeyGen(); - } - - private void startKeyGen() { - progress = new ProgressDialog(GeneratePubkeyActivity.this); - progress.setMessage(GeneratePubkeyActivity.this.getResources().getText(R.string.pubkey_generating)); - progress.setIndeterminate(true); - progress.setCancelable(false); - progress.show(); - - Thread keyGenThread = new Thread(mKeyGen); - keyGenThread.setName("KeyGen"); - keyGenThread.start(); - } - - final private Runnable mKeyGen = new Runnable() { - public void run() { - try { - boolean encrypted = false; - - SecureRandom random = new SecureRandom(); - - // Work around JVM bug - random.nextInt(); - random.setSeed(entropy); - - KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(keyType); - - keyPairGen.initialize(bits, random); - - KeyPair pair = keyPairGen.generateKeyPair(); - PrivateKey priv = pair.getPrivate(); - PublicKey pub = pair.getPublic(); - - String secret = password1.getText().toString(); - if (secret.length() > 0) - encrypted = true; - - Log.d(TAG, "private: " + PubkeyUtils.formatKey(priv)); - Log.d(TAG, "public: " + PubkeyUtils.formatKey(pub)); - - PubkeyBean pubkey = new PubkeyBean(); - pubkey.setNickname(nickname.getText().toString()); - pubkey.setType(keyType); - pubkey.setPrivateKey(PubkeyUtils.getEncodedPrivate(priv, secret)); - pubkey.setPublicKey(pub.getEncoded()); - pubkey.setEncrypted(encrypted); - pubkey.setStartup(unlockAtStartup.isChecked()); - pubkey.setConfirmUse(confirmUse.isChecked()); - - PubkeyDatabase pubkeydb = new PubkeyDatabase(GeneratePubkeyActivity.this); - pubkeydb.savePubkey(pubkey); - pubkeydb.close(); - } catch (Exception e) { - Log.e(TAG, "Could not generate key pair"); - - e.printStackTrace(); - } - - GeneratePubkeyActivity.this.runOnUiThread(new Runnable() { - public void run() { - progress.dismiss(); - GeneratePubkeyActivity.this.finish(); - } - }); - } - - }; - - final private TextWatcher textChecker = new TextWatcher() { - public void afterTextChanged(Editable s) {} - - public void beforeTextChanged(CharSequence s, int start, int count, - int after) {} - - public void onTextChanged(CharSequence s, int start, int before, - int count) { - checkEntries(); - } - }; - - private int measureNumberOfSetBits(byte b) { - int numSetBits = 0; - - for (int i = 0; i < 8; i++) { - if ((b & 1) == 1) - numSetBits++; - b >>= 1; - } - - return numSetBits; - } - - private int getClosestFieldSize(int bits) { - int outBits = ECDSA_DEFAULT_BITS; - int distance = Math.abs(bits - ECDSA_DEFAULT_BITS); - - for (int i = 1; i < ECDSA_SIZES.length; i++) { - int thisDistance = Math.abs(bits - ECDSA_SIZES[i]); - if (thisDistance < distance) { - distance = thisDistance; - outBits = ECDSA_SIZES[i]; - } - } - return outBits; - } -} diff --git a/src/org/connectbot/HelpActivity.java b/src/org/connectbot/HelpActivity.java deleted file mode 100644 index d82777d..0000000 --- a/src/org/connectbot/HelpActivity.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.io.IOException; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.AssetManager; -import android.os.Bundle; -import android.util.Log; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.LinearLayout; - -/** - * @author Kenny Root - * - */ -public class HelpActivity extends Activity { - public final static String TAG = "ConnectBot.HelpActivity"; - - public final static String HELPDIR = "help"; - public final static String SUFFIX = ".html"; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.act_help); - - this.setTitle(String.format("%s: %s", - getResources().getText(R.string.app_name), - getResources().getText(R.string.title_help))); - - AssetManager am = this.getAssets(); - LinearLayout content = (LinearLayout)this.findViewById(R.id.topics); - - try { - for (String name : am.list(HELPDIR)) { - if (name.endsWith(SUFFIX)) { - Button button = new Button(this); - final String topic = name.substring(0, name.length() - SUFFIX.length()); - button.setText(topic); - - button.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - Intent intent = new Intent(HelpActivity.this, HelpTopicActivity.class); - intent.putExtra(Intent.EXTRA_TITLE, topic); - HelpActivity.this.startActivity(intent); - } - }); - - content.addView(button); - } - } - } catch (IOException e) { - // TODO Auto-generated catch block - Log.e(TAG, "couldn't get list of help assets", e); - } - } -} diff --git a/src/org/connectbot/HelpTopicActivity.java b/src/org/connectbot/HelpTopicActivity.java deleted file mode 100644 index a5fa8e0..0000000 --- a/src/org/connectbot/HelpTopicActivity.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import org.connectbot.util.HelpTopicView; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; - -/** - * @author Kenny Root - * - */ -public class HelpTopicActivity extends Activity { - public final static String TAG = "ConnectBot.HelpActivity"; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.act_help_topic); - - String topic = getIntent().getStringExtra(Intent.EXTRA_TITLE); - - this.setTitle(String.format("%s: %s - %s", - getResources().getText(R.string.app_name), - getResources().getText(R.string.title_help), - topic)); - - HelpTopicView helpTopic = (HelpTopicView) findViewById(R.id.topic_text); - - helpTopic.setTopic(topic); - } -} diff --git a/src/org/connectbot/HostEditorActivity.java b/src/org/connectbot/HostEditorActivity.java deleted file mode 100644 index 4e8427f..0000000 --- a/src/org/connectbot/HostEditorActivity.java +++ /dev/null @@ -1,433 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -import org.connectbot.bean.HostBean; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalManager; -import org.connectbot.util.HostDatabase; -import org.connectbot.util.PubkeyDatabase; - -import android.content.ComponentName; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.os.Bundle; -import android.os.IBinder; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.util.Log; - -public class HostEditorActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener { - public class CursorPreferenceHack implements SharedPreferences { - protected final String table; - protected final long id; - - protected Map<String, String> values = new HashMap<String, String>(); -// protected Map<String, String> pubkeys = new HashMap<String, String>(); - - public CursorPreferenceHack(String table, long id) { - this.table = table; - this.id = id; - - cacheValues(); - } - - protected final void cacheValues() { - // fill a cursor and cache the values locally - // this makes sure we dont have any floating cursor to dispose later - - SQLiteDatabase db = hostdb.getReadableDatabase(); - Cursor cursor = db.query(table, null, "_id = ?", - new String[] { String.valueOf(id) }, null, null, null); - - if (cursor.moveToFirst()) { - for(int i = 0; i < cursor.getColumnCount(); i++) { - String key = cursor.getColumnName(i); - if(key.equals(HostDatabase.FIELD_HOST_HOSTKEY)) continue; - String value = cursor.getString(i); - values.put(key, value); - } - } - cursor.close(); - db.close(); - -// db = pubkeydb.getReadableDatabase(); -// cursor = db.query(PubkeyDatabase.TABLE_PUBKEYS, -// new String[] { "_id", PubkeyDatabase.FIELD_PUBKEY_NICKNAME }, -// null, null, null, null, null); -// -// if (cursor.moveToFirst()) { -// do { -// String pubkeyid = String.valueOf(cursor.getLong(0)); -// String value = cursor.getString(1); -// pubkeys.put(pubkeyid, value); -// } while (cursor.moveToNext()); -// } -// -// cursor.close(); -// db.close(); - } - - public boolean contains(String key) { - return values.containsKey(key); - } - - public class Editor implements SharedPreferences.Editor { - - private ContentValues update = new ContentValues(); - - public SharedPreferences.Editor clear() { - Log.d(this.getClass().toString(), "clear()"); - update = new ContentValues(); - return this; - } - - public boolean commit() { - //Log.d(this.getClass().toString(), "commit() changes back to database"); - SQLiteDatabase db = hostdb.getWritableDatabase(); - db.update(table, update, "_id = ?", new String[] { String.valueOf(id) }); - db.close(); - - // make sure we refresh the parent cached values - cacheValues(); - - // and update any listeners - for(OnSharedPreferenceChangeListener listener : listeners) { - listener.onSharedPreferenceChanged(CursorPreferenceHack.this, null); - } - - return true; - } - - // Gingerbread compatibility - public void apply() { - commit(); - } - - public android.content.SharedPreferences.Editor putBoolean(String key, boolean value) { - return this.putString(key, Boolean.toString(value)); - } - - public android.content.SharedPreferences.Editor putFloat(String key, float value) { - return this.putString(key, Float.toString(value)); - } - - public android.content.SharedPreferences.Editor putInt(String key, int value) { - return this.putString(key, Integer.toString(value)); - } - - public android.content.SharedPreferences.Editor putLong(String key, long value) { - return this.putString(key, Long.toString(value)); - } - - public android.content.SharedPreferences.Editor putString(String key, String value) { - //Log.d(this.getClass().toString(), String.format("Editor.putString(key=%s, value=%s)", key, value)); - update.put(key, value); - return this; - } - - public android.content.SharedPreferences.Editor remove(String key) { - //Log.d(this.getClass().toString(), String.format("Editor.remove(key=%s)", key)); - update.remove(key); - return this; - } - - public android.content.SharedPreferences.Editor putStringSet(String key, Set<String> value) { - throw new UnsupportedOperationException("HostEditor Prefs do not support Set<String>"); - } - } - - - public Editor edit() { - //Log.d(this.getClass().toString(), "edit()"); - return new Editor(); - } - - public Map<String, ?> getAll() { - return values; - } - - public boolean getBoolean(String key, boolean defValue) { - return Boolean.valueOf(this.getString(key, Boolean.toString(defValue))); - } - - public float getFloat(String key, float defValue) { - return Float.valueOf(this.getString(key, Float.toString(defValue))); - } - - public int getInt(String key, int defValue) { - return Integer.valueOf(this.getString(key, Integer.toString(defValue))); - } - - public long getLong(String key, long defValue) { - return Long.valueOf(this.getString(key, Long.toString(defValue))); - } - - public String getString(String key, String defValue) { - //Log.d(this.getClass().toString(), String.format("getString(key=%s, defValue=%s)", key, defValue)); - - if(!values.containsKey(key)) return defValue; - return values.get(key); - } - - public Set<String> getStringSet(String key, Set<String> defValue) { - throw new ClassCastException("HostEditor Prefs do not support Set<String>"); - } - - protected List<OnSharedPreferenceChangeListener> listeners = new LinkedList<OnSharedPreferenceChangeListener>(); - - public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { - listeners.add(listener); - } - - public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { - listeners.remove(listener); - } - - } - - @Override - public SharedPreferences getSharedPreferences(String name, int mode) { - //Log.d(this.getClass().toString(), String.format("getSharedPreferences(name=%s)", name)); - return this.pref; - } - - protected static final String TAG = "ConnectBot.HostEditorActivity"; - - protected HostDatabase hostdb = null; - private PubkeyDatabase pubkeydb = null; - - private CursorPreferenceHack pref; - private ServiceConnection connection; - - private HostBean host; - protected TerminalBridge hostBridge; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - long hostId = this.getIntent().getLongExtra(Intent.EXTRA_TITLE, -1); - - // TODO: we could pass through a specific ContentProvider uri here - //this.getPreferenceManager().setSharedPreferencesName(uri); - - this.hostdb = new HostDatabase(this); - this.pubkeydb = new PubkeyDatabase(this); - - host = hostdb.findHostById(hostId); - - connection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - TerminalManager bound = ((TerminalManager.TerminalBinder) service).getService(); - - hostBridge = bound.getConnectedBridge(host); - } - - public void onServiceDisconnected(ComponentName name) { - hostBridge = null; - } - }; - - this.pref = new CursorPreferenceHack(HostDatabase.TABLE_HOSTS, hostId); - this.pref.registerOnSharedPreferenceChangeListener(this); - - this.addPreferencesFromResource(R.xml.host_prefs); - - // add all existing pubkeys to our listpreference for user to choose from - // TODO: may be an issue here when this activity is recycled after adding a new pubkey - // TODO: should consider moving into onStart, but we dont have a good way of resetting the listpref after filling once - ListPreference pubkeyPref = (ListPreference)this.findPreference(HostDatabase.FIELD_HOST_PUBKEYID); - - List<CharSequence> pubkeyNicks = new LinkedList<CharSequence>(Arrays.asList(pubkeyPref.getEntries())); - pubkeyNicks.addAll(pubkeydb.allValues(PubkeyDatabase.FIELD_PUBKEY_NICKNAME)); - pubkeyPref.setEntries(pubkeyNicks.toArray(new CharSequence[pubkeyNicks.size()])); - - List<CharSequence> pubkeyIds = new LinkedList<CharSequence>(Arrays.asList(pubkeyPref.getEntryValues())); - pubkeyIds.addAll(pubkeydb.allValues("_id")); - pubkeyPref.setEntryValues(pubkeyIds.toArray(new CharSequence[pubkeyIds.size()])); - - // Populate the character set encoding list with all available - final ListPreference charsetPref = (ListPreference) findPreference(HostDatabase.FIELD_HOST_ENCODING); - - if (CharsetHolder.isInitialized()) { - initCharsetPref(charsetPref); - } else { - String[] currentCharsetPref = new String[1]; - currentCharsetPref[0] = charsetPref.getValue(); - charsetPref.setEntryValues(currentCharsetPref); - charsetPref.setEntries(currentCharsetPref); - - new Thread(new Runnable() { - public void run() { - initCharsetPref(charsetPref); - } - }).start(); - } - - this.updateSummaries(); - } - - @Override - public void onStart() { - super.onStart(); - - bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); - - if(this.hostdb == null) - this.hostdb = new HostDatabase(this); - - if(this.pubkeydb == null) - this.pubkeydb = new PubkeyDatabase(this); - } - - @Override - public void onStop() { - super.onStop(); - - unbindService(connection); - - if(this.hostdb != null) { - this.hostdb.close(); - this.hostdb = null; - } - - if(this.pubkeydb != null) { - this.pubkeydb.close(); - this.pubkeydb = null; - } - } - - private void updateSummaries() { - // for all text preferences, set hint as current database value - for (String key : this.pref.values.keySet()) { - if(key.equals(HostDatabase.FIELD_HOST_POSTLOGIN)) continue; - Preference pref = this.findPreference(key); - if(pref == null) continue; - if(pref instanceof CheckBoxPreference) continue; - CharSequence value = this.pref.getString(key, ""); - - if (key.equals(HostDatabase.FIELD_HOST_PUBKEYID)) { - try { - int pubkeyId = Integer.parseInt((String) value); - if (pubkeyId >= 0) - pref.setSummary(pubkeydb.getNickname(pubkeyId)); - else if(pubkeyId == HostDatabase.PUBKEYID_ANY) - pref.setSummary(R.string.list_pubkeyids_any); - else if(pubkeyId == HostDatabase.PUBKEYID_NEVER) - pref.setSummary(R.string.list_pubkeyids_none); - continue; - } catch (NumberFormatException nfe) { - // Fall through. - } - } else if (pref instanceof ListPreference) { - ListPreference listPref = (ListPreference) pref; - int entryIndex = listPref.findIndexOfValue((String) value); - if (entryIndex >= 0) - value = listPref.getEntries()[entryIndex]; - } - - pref.setSummary(value); - } - - } - - private void initCharsetPref(final ListPreference charsetPref) { - charsetPref.setEntryValues(CharsetHolder.getCharsetIds()); - charsetPref.setEntries(CharsetHolder.getCharsetNames()); - } - - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - // update values on changed preference - this.updateSummaries(); - - // Our CursorPreferenceHack always send null keys, so try to set charset anyway - if (hostBridge != null) - hostBridge.setCharset(sharedPreferences - .getString(HostDatabase.FIELD_HOST_ENCODING, HostDatabase.ENCODING_DEFAULT)); - } - - public static class CharsetHolder { - private static boolean initialized = false; - - private static CharSequence[] charsetIds; - private static CharSequence[] charsetNames; - - public static CharSequence[] getCharsetNames() { - if (charsetNames == null) - initialize(); - - return charsetNames; - } - - public static CharSequence[] getCharsetIds() { - if (charsetIds == null) - initialize(); - - return charsetIds; - } - - private synchronized static void initialize() { - if (initialized) - return; - - List<CharSequence> charsetIdsList = new LinkedList<CharSequence>(); - List<CharSequence> charsetNamesList = new LinkedList<CharSequence>(); - - for (Entry<String, Charset> entry : Charset.availableCharsets().entrySet()) { - Charset c = entry.getValue(); - if (c.canEncode() && c.isRegistered()) { - String key = entry.getKey(); - if (key.startsWith("cp")) { - // Custom CP437 charset changes - charsetIdsList.add("CP437"); - charsetNamesList.add("CP437"); - } - charsetIdsList.add(entry.getKey()); - charsetNamesList.add(c.displayName()); - } - } - - charsetIds = charsetIdsList.toArray(new CharSequence[charsetIdsList.size()]); - charsetNames = charsetNamesList.toArray(new CharSequence[charsetNamesList.size()]); - - initialized = true; - } - - public static boolean isInitialized() { - return initialized; - } - } -} diff --git a/src/org/connectbot/HostListActivity.java b/src/org/connectbot/HostListActivity.java deleted file mode 100644 index 648b705..0000000 --- a/src/org/connectbot/HostListActivity.java +++ /dev/null @@ -1,570 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.util.List; - -import org.connectbot.bean.HostBean; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalManager; -import org.connectbot.transport.TransportFactory; -import org.connectbot.util.HostDatabase; -import org.connectbot.util.PreferenceConstants; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ListActivity; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.content.Intent.ShortcutIconResource; -import android.content.SharedPreferences.Editor; -import android.content.res.ColorStateList; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.preference.PreferenceManager; -import android.util.Log; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.View.OnKeyListener; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.Spinner; -import android.widget.TextView; -import android.widget.AdapterView.OnItemClickListener; - -public class HostListActivity extends ListActivity { - public final static int REQUEST_EDIT = 1; - - public final static int REQUEST_EULA = 2; - - protected TerminalManager bound = null; - - protected HostDatabase hostdb; - private List<HostBean> hosts; - protected LayoutInflater inflater = null; - - protected boolean sortedByColor = false; - - private MenuItem sortcolor; - - private MenuItem sortlast; - - private Spinner transportSpinner; - private TextView quickconnect; - - private SharedPreferences prefs = null; - - protected boolean makingShortcut = false; - - protected Handler updateHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - HostListActivity.this.updateList(); - } - }; - - private ServiceConnection connection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - bound = ((TerminalManager.TerminalBinder) service).getService(); - - // update our listview binder to find the service - HostListActivity.this.updateList(); - } - - public void onServiceDisconnected(ComponentName className) { - bound = null; - HostListActivity.this.updateList(); - } - }; - - @Override - public void onStart() { - super.onStart(); - - // start the terminal manager service - this.bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); - - if(this.hostdb == null) - this.hostdb = new HostDatabase(this); - } - - @Override - public void onStop() { - super.onStop(); - this.unbindService(connection); - - if(this.hostdb != null) { - this.hostdb.close(); - this.hostdb = null; - } - } - - @Override - public void onResume() { - super.onResume(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == REQUEST_EULA) { - if(resultCode == Activity.RESULT_OK) { - // yay they agreed, so store that info - Editor edit = prefs.edit(); - edit.putBoolean(PreferenceConstants.EULA, true); - edit.commit(); - } else { - // user didnt agree, so close - this.finish(); - } - } else if (requestCode == REQUEST_EDIT) { - this.updateList(); - } - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.act_hostlist); - - this.setTitle(String.format("%s: %s", - getResources().getText(R.string.app_name), - getResources().getText(R.string.title_hosts_list))); - - this.prefs = PreferenceManager.getDefaultSharedPreferences(this); - - // detect HTC Dream and apply special preferences - if (Build.MANUFACTURER.equals("HTC") && Build.DEVICE.equals("dream")) { - if (!prefs.contains(PreferenceConstants.SHIFT_FKEYS) && - !prefs.contains(PreferenceConstants.CTRL_FKEYS)) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(PreferenceConstants.SHIFT_FKEYS, true); - editor.putBoolean(PreferenceConstants.CTRL_FKEYS, true); - editor.commit(); - } - } - - // check for eula agreement - boolean agreed = prefs.getBoolean(PreferenceConstants.EULA, false); - if(!agreed) { - this.startActivityForResult(new Intent(this, WizardActivity.class), REQUEST_EULA); - } - - this.makingShortcut = Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction()) - || Intent.ACTION_PICK.equals(getIntent().getAction()); - - // connect with hosts database and populate list - this.hostdb = new HostDatabase(this); - ListView list = this.getListView(); - - this.sortedByColor = prefs.getBoolean(PreferenceConstants.SORT_BY_COLOR, false); - - //this.list.setSelector(R.drawable.highlight_disabled_pressed); - - list.setOnItemClickListener(new OnItemClickListener() { - - public synchronized void onItemClick(AdapterView<?> parent, View view, int position, long id) { - - // launch off to console details - HostBean host = (HostBean) parent.getAdapter().getItem(position); - Uri uri = host.getUri(); - - Intent contents = new Intent(Intent.ACTION_VIEW, uri); - contents.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - - if (makingShortcut) { - // create shortcut if requested - ShortcutIconResource icon = Intent.ShortcutIconResource.fromContext(HostListActivity.this, R.drawable.icon); - - Intent intent = new Intent(); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, contents); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, host.getNickname()); - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon); - - setResult(RESULT_OK, intent); - finish(); - - } else { - // otherwise just launch activity to show this host - HostListActivity.this.startActivity(contents); - } - } - }); - - this.registerForContextMenu(list); - - quickconnect = (TextView) this.findViewById(R.id.front_quickconnect); - quickconnect.setVisibility(makingShortcut ? View.GONE : View.VISIBLE); - quickconnect.setOnKeyListener(new OnKeyListener() { - - public boolean onKey(View v, int keyCode, KeyEvent event) { - - if(event.getAction() == KeyEvent.ACTION_UP) return false; - if(keyCode != KeyEvent.KEYCODE_ENTER) return false; - - return startConsoleActivity(); - } - }); - - transportSpinner = (Spinner)findViewById(R.id.transport_selection); - transportSpinner.setVisibility(makingShortcut ? View.GONE : View.VISIBLE); - ArrayAdapter<String> transportSelection = new ArrayAdapter<String>(this, - android.R.layout.simple_spinner_item, TransportFactory.getTransportNames()); - transportSelection.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - transportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - public void onItemSelected(AdapterView<?> arg0, View view, int position, long id) { - String formatHint = TransportFactory.getFormatHint( - (String) transportSpinner.getSelectedItem(), - HostListActivity.this); - - quickconnect.setHint(formatHint); - quickconnect.setError(null); - quickconnect.requestFocus(); - } - public void onNothingSelected(AdapterView<?> arg0) { } - }); - transportSpinner.setAdapter(transportSelection); - - this.inflater = LayoutInflater.from(this); - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - - // don't offer menus when creating shortcut - if (makingShortcut) return true; - - sortcolor.setVisible(!sortedByColor); - sortlast.setVisible(sortedByColor); - - return true; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - // don't offer menus when creating shortcut - if(makingShortcut) return true; - - // add host, ssh keys, about - sortcolor = menu.add(R.string.list_menu_sortcolor); - sortcolor.setIcon(android.R.drawable.ic_menu_share); - sortcolor.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - sortedByColor = true; - updateList(); - return true; - } - }); - - sortlast = menu.add(R.string.list_menu_sortname); - sortlast.setIcon(android.R.drawable.ic_menu_share); - sortlast.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - sortedByColor = false; - updateList(); - return true; - } - }); - - MenuItem keys = menu.add(R.string.list_menu_pubkeys); - keys.setIcon(android.R.drawable.ic_lock_lock); - keys.setIntent(new Intent(HostListActivity.this, PubkeyListActivity.class)); - - MenuItem colors = menu.add(R.string.title_colors); - colors.setIcon(android.R.drawable.ic_menu_slideshow); - colors.setIntent(new Intent(HostListActivity.this, ColorsActivity.class)); - - MenuItem settings = menu.add(R.string.list_menu_settings); - settings.setIcon(android.R.drawable.ic_menu_preferences); - settings.setIntent(new Intent(HostListActivity.this, SettingsActivity.class)); - - MenuItem help = menu.add(R.string.title_help); - help.setIcon(android.R.drawable.ic_menu_help); - help.setIntent(new Intent(HostListActivity.this, HelpActivity.class)); - - return true; - - } - - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - - // create menu to handle hosts - - // create menu to handle deleting and sharing lists - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - final HostBean host = (HostBean) this.getListView().getItemAtPosition(info.position); - - menu.setHeaderTitle(host.getNickname()); - - // edit, disconnect, delete - MenuItem connect = menu.add(R.string.list_host_disconnect); - final TerminalBridge bridge = bound.getConnectedBridge(host); - connect.setEnabled((bridge != null)); - connect.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - bridge.dispatchDisconnect(true); - updateHandler.sendEmptyMessage(-1); - return true; - } - }); - - MenuItem edit = menu.add(R.string.list_host_edit); - edit.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - Intent intent = new Intent(HostListActivity.this, HostEditorActivity.class); - intent.putExtra(Intent.EXTRA_TITLE, host.getId()); - HostListActivity.this.startActivityForResult(intent, REQUEST_EDIT); - return true; - } - }); - - MenuItem portForwards = menu.add(R.string.list_host_portforwards); - portForwards.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - Intent intent = new Intent(HostListActivity.this, PortForwardListActivity.class); - intent.putExtra(Intent.EXTRA_TITLE, host.getId()); - HostListActivity.this.startActivityForResult(intent, REQUEST_EDIT); - return true; - } - }); - if (!TransportFactory.canForwardPorts(host.getProtocol())) - portForwards.setEnabled(false); - - MenuItem delete = menu.add(R.string.list_host_delete); - delete.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // prompt user to make sure they really want this - new AlertDialog.Builder(HostListActivity.this) - .setMessage(getString(R.string.delete_message, host.getNickname())) - .setPositiveButton(R.string.delete_pos, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // make sure we disconnect - if(bridge != null) - bridge.dispatchDisconnect(true); - - hostdb.deleteHost(host); - updateHandler.sendEmptyMessage(-1); - } - }) - .setNegativeButton(R.string.delete_neg, null).create().show(); - - return true; - } - }); - } - - /** - * @param text - * @return - */ - private boolean startConsoleActivity() { - Uri uri = TransportFactory.getUri((String) transportSpinner - .getSelectedItem(), quickconnect.getText().toString()); - - if (uri == null) { - quickconnect.setError(getString(R.string.list_format_error, - TransportFactory.getFormatHint( - (String) transportSpinner.getSelectedItem(), - HostListActivity.this))); - return false; - } - - HostBean host = TransportFactory.findHost(hostdb, uri); - if (host == null) { - host = TransportFactory.getTransport(uri.getScheme()).createHost(uri); - host.setColor(HostDatabase.COLOR_GRAY); - host.setPubkeyId(HostDatabase.PUBKEYID_ANY); - hostdb.saveHost(host); - } - - Intent intent = new Intent(HostListActivity.this, ConsoleActivity.class); - intent.setData(uri); - startActivity(intent); - - return true; - } - - protected void updateList() { - if (prefs.getBoolean(PreferenceConstants.SORT_BY_COLOR, false) != sortedByColor) { - Editor edit = prefs.edit(); - edit.putBoolean(PreferenceConstants.SORT_BY_COLOR, sortedByColor); - edit.commit(); - } - - if (hostdb == null) - hostdb = new HostDatabase(this); - - hosts = hostdb.getHosts(sortedByColor); - - // Don't lose hosts that are connected via shortcuts but not in the database. - if (bound != null) { - for (TerminalBridge bridge : bound.bridges) { - if (!hosts.contains(bridge.host)) - hosts.add(0, bridge.host); - } - } - - HostAdapter adapter = new HostAdapter(this, hosts, bound); - - this.setListAdapter(adapter); - } - - class HostAdapter extends ArrayAdapter<HostBean> { - private List<HostBean> hosts; - private final TerminalManager manager; - private final ColorStateList red, green, blue; - - public final static int STATE_UNKNOWN = 1, STATE_CONNECTED = 2, STATE_DISCONNECTED = 3; - - class ViewHolder { - public TextView nickname; - public TextView caption; - public ImageView icon; - } - - public HostAdapter(Context context, List<HostBean> hosts, TerminalManager manager) { - super(context, R.layout.item_host, hosts); - - this.hosts = hosts; - this.manager = manager; - - red = context.getResources().getColorStateList(R.color.red); - green = context.getResources().getColorStateList(R.color.green); - blue = context.getResources().getColorStateList(R.color.blue); - } - - /** - * Check if we're connected to a terminal with the given host. - */ - private int getConnectedState(HostBean host) { - // always disconnected if we dont have backend service - if (this.manager == null) - return STATE_UNKNOWN; - - if (manager.getConnectedBridge(host) != null) - return STATE_CONNECTED; - - if (manager.disconnected.contains(host)) - return STATE_DISCONNECTED; - - return STATE_UNKNOWN; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - ViewHolder holder; - - if (convertView == null) { - convertView = inflater.inflate(R.layout.item_host, null, false); - - holder = new ViewHolder(); - - holder.nickname = (TextView)convertView.findViewById(android.R.id.text1); - holder.caption = (TextView)convertView.findViewById(android.R.id.text2); - holder.icon = (ImageView)convertView.findViewById(android.R.id.icon); - - convertView.setTag(holder); - } else - holder = (ViewHolder) convertView.getTag(); - - HostBean host = hosts.get(position); - if (host == null) { - // Well, something bad happened. We can't continue. - Log.e("HostAdapter", "Host bean is null!"); - - holder.nickname.setText("Error during lookup"); - holder.caption.setText("see 'adb logcat' for more"); - return convertView; - } - - holder.nickname.setText(host.getNickname()); - - switch (this.getConnectedState(host)) { - case STATE_UNKNOWN: - holder.icon.setImageState(new int[] { }, true); - break; - case STATE_CONNECTED: - holder.icon.setImageState(new int[] { android.R.attr.state_checked }, true); - break; - case STATE_DISCONNECTED: - holder.icon.setImageState(new int[] { android.R.attr.state_expanded }, true); - break; - } - - ColorStateList chosen = null; - if (HostDatabase.COLOR_RED.equals(host.getColor())) - chosen = this.red; - else if (HostDatabase.COLOR_GREEN.equals(host.getColor())) - chosen = this.green; - else if (HostDatabase.COLOR_BLUE.equals(host.getColor())) - chosen = this.blue; - - Context context = convertView.getContext(); - - if (chosen != null) { - // set color normally if not selected - holder.nickname.setTextColor(chosen); - holder.caption.setTextColor(chosen); - } else { - // selected, so revert back to default black text - holder.nickname.setTextAppearance(context, android.R.attr.textAppearanceLarge); - holder.caption.setTextAppearance(context, android.R.attr.textAppearanceSmall); - } - - long now = System.currentTimeMillis() / 1000; - - String nice = context.getString(R.string.bind_never); - if (host.getLastConnect() > 0) { - int minutes = (int)((now - host.getLastConnect()) / 60); - if (minutes >= 60) { - int hours = (minutes / 60); - if (hours >= 24) { - int days = (hours / 24); - nice = context.getString(R.string.bind_days, days); - } else - nice = context.getString(R.string.bind_hours, hours); - } else - nice = context.getString(R.string.bind_minutes, minutes); - } - - holder.caption.setText(nice); - - return convertView; - } - } -} diff --git a/src/org/connectbot/PortForwardListActivity.java b/src/org/connectbot/PortForwardListActivity.java deleted file mode 100644 index f9982e4..0000000 --- a/src/org/connectbot/PortForwardListActivity.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.util.List; - -import org.connectbot.bean.HostBean; -import org.connectbot.bean.PortForwardBean; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalManager; -import org.connectbot.util.HostDatabase; - -import android.app.AlertDialog; -import android.app.ListActivity; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.res.Resources; -import android.database.SQLException; -import android.graphics.Paint; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.util.Log; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.MenuItem.OnMenuItemClickListener; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ListView; -import android.widget.Spinner; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.AdapterView.OnItemSelectedListener; - -/** - * List all portForwards for a particular host and provide a way for users to add more portForwards, - * edit existing portForwards, and delete portForwards. - * - * @author Kenny Root - */ -public class PortForwardListActivity extends ListActivity { - public final static String TAG = "ConnectBot.PortForwardListActivity"; - - private static final int LISTENER_CYCLE_TIME = 500; - - protected HostDatabase hostdb; - - private List<PortForwardBean> portForwards; - - private ServiceConnection connection = null; - protected TerminalBridge hostBridge = null; - protected LayoutInflater inflater = null; - - private HostBean host; - - @Override - public void onStart() { - super.onStart(); - - this.bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); - - if(this.hostdb == null) - this.hostdb = new HostDatabase(this); - } - - @Override - public void onStop() { - super.onStop(); - - this.unbindService(connection); - - if(this.hostdb != null) { - this.hostdb.close(); - this.hostdb = null; - } - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - long hostId = this.getIntent().getLongExtra(Intent.EXTRA_TITLE, -1); - - setContentView(R.layout.act_portforwardlist); - - // connect with hosts database and populate list - this.hostdb = new HostDatabase(this); - host = hostdb.findHostById(hostId); - - { - final String nickname = host != null ? host.getNickname() : null; - final Resources resources = getResources(); - - if (nickname != null) { - this.setTitle(String.format("%s: %s (%s)", - resources.getText(R.string.app_name), - resources.getText(R.string.title_port_forwards_list), - nickname)); - } else { - this.setTitle(String.format("%s: %s", - resources.getText(R.string.app_name), - resources.getText(R.string.title_port_forwards_list))); - } - } - - connection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - TerminalManager bound = ((TerminalManager.TerminalBinder) service).getService(); - - hostBridge = bound.getConnectedBridge(host); - updateHandler.sendEmptyMessage(-1); - } - - public void onServiceDisconnected(ComponentName name) { - hostBridge = null; - } - }; - - this.updateList(); - - this.registerForContextMenu(this.getListView()); - - this.getListView().setOnItemClickListener(new OnItemClickListener() { - public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { - ListView lv = PortForwardListActivity.this.getListView(); - PortForwardBean pfb = (PortForwardBean) lv.getItemAtPosition(position); - - if (hostBridge != null) { - if (pfb.isEnabled()) - hostBridge.disablePortForward(pfb); - else { - if (!hostBridge.enablePortForward(pfb)) - Toast.makeText(PortForwardListActivity.this, getString(R.string.portforward_problem), Toast.LENGTH_LONG).show(); - } - - updateHandler.sendEmptyMessage(-1); - } - } - }); - - this.inflater = LayoutInflater.from(this); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuItem add = menu.add(R.string.portforward_menu_add); - add.setIcon(android.R.drawable.ic_menu_add); - add.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // build dialog to prompt user about updating - final View portForwardView = inflater.inflate(R.layout.dia_portforward, null, false); - final EditText destEdit = (EditText) portForwardView.findViewById(R.id.portforward_destination); - final Spinner typeSpinner = (Spinner)portForwardView.findViewById(R.id.portforward_type); - - typeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected(AdapterView<?> value, View view, - int position, long id) { - destEdit.setEnabled(position != 2); - } - public void onNothingSelected(AdapterView<?> arg0) { - } - }); - - new AlertDialog.Builder(PortForwardListActivity.this) - .setView(portForwardView) - .setPositiveButton(R.string.portforward_pos, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - try { - final EditText nicknameEdit = (EditText) portForwardView.findViewById(R.id.nickname); - final EditText sourcePortEdit = (EditText) portForwardView.findViewById(R.id.portforward_source); - - String type = HostDatabase.PORTFORWARD_LOCAL; - switch (typeSpinner.getSelectedItemPosition()) { - case 0: - type = HostDatabase.PORTFORWARD_LOCAL; - break; - case 1: - type = HostDatabase.PORTFORWARD_REMOTE; - break; - case 2: - type = HostDatabase.PORTFORWARD_DYNAMIC5; - break; - } - - PortForwardBean pfb = new PortForwardBean( - host != null ? host.getId() : -1, - nicknameEdit.getText().toString(), type, - sourcePortEdit.getText().toString(), - destEdit.getText().toString()); - - if (hostBridge != null) { - hostBridge.addPortForward(pfb); - hostBridge.enablePortForward(pfb); - } - - if (host != null && !hostdb.savePortForward(pfb)) - throw new SQLException("Could not save port forward"); - - updateHandler.sendEmptyMessage(-1); - } catch (Exception e) { - Log.e(TAG, "Could not update port forward", e); - // TODO Show failure dialog. - } - } - }) - .setNegativeButton(R.string.delete_neg, null).create().show(); - - return true; - } - }); - - return true; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - // Create menu to handle deleting and editing port forward - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - final PortForwardBean pfb = (PortForwardBean) this.getListView().getItemAtPosition(info.position); - - menu.setHeaderTitle(pfb.getNickname()); - - MenuItem edit = menu.add(R.string.portforward_edit); - edit.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - final View editTunnelView = inflater.inflate(R.layout.dia_portforward, null, false); - - final Spinner typeSpinner = (Spinner) editTunnelView.findViewById(R.id.portforward_type); - if (HostDatabase.PORTFORWARD_LOCAL.equals(pfb.getType())) - typeSpinner.setSelection(0); - else if (HostDatabase.PORTFORWARD_REMOTE.equals(pfb.getType())) - typeSpinner.setSelection(1); - else - typeSpinner.setSelection(2); - - final EditText nicknameEdit = (EditText) editTunnelView.findViewById(R.id.nickname); - nicknameEdit.setText(pfb.getNickname()); - - final EditText sourcePortEdit = (EditText) editTunnelView.findViewById(R.id.portforward_source); - sourcePortEdit.setText(String.valueOf(pfb.getSourcePort())); - - final EditText destEdit = (EditText) editTunnelView.findViewById(R.id.portforward_destination); - if (HostDatabase.PORTFORWARD_DYNAMIC5.equals(pfb.getType())) { - destEdit.setEnabled(false); - } else { - destEdit.setText(String.format("%s:%d", pfb.getDestAddr(), pfb.getDestPort())); - } - - typeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { - public void onItemSelected(AdapterView<?> value, View view, - int position, long id) { - destEdit.setEnabled(position != 2); - } - public void onNothingSelected(AdapterView<?> arg0) { - } - }); - - new AlertDialog.Builder(PortForwardListActivity.this) - .setView(editTunnelView) - .setPositiveButton(R.string.button_change, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - try { - if (hostBridge != null) - hostBridge.disablePortForward(pfb); - - pfb.setNickname(nicknameEdit.getText().toString()); - - switch (typeSpinner.getSelectedItemPosition()) { - case 0: - pfb.setType(HostDatabase.PORTFORWARD_LOCAL); - break; - case 1: - pfb.setType(HostDatabase.PORTFORWARD_REMOTE); - break; - case 2: - pfb.setType(HostDatabase.PORTFORWARD_DYNAMIC5); - break; - } - - pfb.setSourcePort(Integer.parseInt(sourcePortEdit.getText().toString())); - pfb.setDest(destEdit.getText().toString()); - - // Use the new settings for the existing connection. - if (hostBridge != null) - updateHandler.postDelayed(new Runnable() { - public void run() { - hostBridge.enablePortForward(pfb); - updateHandler.sendEmptyMessage(-1); - } - }, LISTENER_CYCLE_TIME); - - - if (!hostdb.savePortForward(pfb)) - throw new SQLException("Could not save port forward"); - - updateHandler.sendEmptyMessage(-1); - } catch (Exception e) { - Log.e(TAG, "Could not update port forward", e); - // TODO Show failure dialog. - } - } - }) - .setNegativeButton(android.R.string.cancel, null).create().show(); - - return true; - } - }); - - MenuItem delete = menu.add(R.string.portforward_delete); - delete.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // prompt user to make sure they really want this - new AlertDialog.Builder(PortForwardListActivity.this) - .setMessage(getString(R.string.delete_message, pfb.getNickname())) - .setPositiveButton(R.string.delete_pos, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - try { - // Delete the port forward from the host if needed. - if (hostBridge != null) - hostBridge.removePortForward(pfb); - - hostdb.deletePortForward(pfb); - } catch (Exception e) { - Log.e(TAG, "Could not delete port forward", e); - } - - updateHandler.sendEmptyMessage(-1); - } - }) - .setNegativeButton(R.string.delete_neg, null).create().show(); - - return true; - } - }); - } - - protected Handler updateHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - PortForwardListActivity.this.updateList(); - } - }; - - protected void updateList() { - if (hostBridge != null) { - this.portForwards = hostBridge.getPortForwards(); - } else { - if (this.hostdb == null) return; - this.portForwards = this.hostdb.getPortForwardsForHost(host); - } - - PortForwardAdapter adapter = new PortForwardAdapter(this, portForwards); - - this.setListAdapter(adapter); - } - - class PortForwardAdapter extends ArrayAdapter<PortForwardBean> { - class ViewHolder { - public TextView nickname; - public TextView caption; - } - - private List<PortForwardBean> portForwards; - - public PortForwardAdapter(Context context, List<PortForwardBean> portForwards) { - super(context, R.layout.item_portforward, portForwards); - - this.portForwards = portForwards; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - ViewHolder holder; - - if (convertView == null) { - convertView = inflater.inflate(R.layout.item_portforward, null, false); - - holder = new ViewHolder(); - holder.nickname = (TextView)convertView.findViewById(android.R.id.text1); - holder.caption = (TextView)convertView.findViewById(android.R.id.text2); - - convertView.setTag(holder); - } else - holder = (ViewHolder) convertView.getTag(); - - PortForwardBean pfb = portForwards.get(position); - holder.nickname.setText(pfb.getNickname()); - holder.caption.setText(pfb.getDescription()); - - if (hostBridge != null && !pfb.isEnabled()) { - holder.nickname.setPaintFlags(holder.nickname.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - holder.caption.setPaintFlags(holder.caption.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - } - - return convertView; - } - } -} diff --git a/src/org/connectbot/PubkeyListActivity.java b/src/org/connectbot/PubkeyListActivity.java deleted file mode 100644 index be7a46f..0000000 --- a/src/org/connectbot/PubkeyListActivity.java +++ /dev/null @@ -1,673 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.util.Collections; -import java.util.EventListener; -import java.util.LinkedList; -import java.util.List; - -import org.connectbot.bean.PubkeyBean; -import org.connectbot.service.TerminalManager; -import org.connectbot.util.PubkeyDatabase; -import org.connectbot.util.PubkeyUtils; -import org.openintents.intents.FileManagerIntents; - -import android.app.AlertDialog; -import android.app.ListActivity; -import android.content.ActivityNotFoundException; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.ServiceConnection; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.os.IBinder; -import android.text.ClipboardManager; -import android.util.Log; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.TableRow; -import android.widget.TextView; -import android.widget.Toast; - -import com.trilead.ssh2.crypto.Base64; -import com.trilead.ssh2.crypto.PEMDecoder; -import com.trilead.ssh2.crypto.PEMStructure; - -/** - * List public keys in database by nickname and describe their properties. Allow users to import, - * generate, rename, and delete key pairs. - * - * @author Kenny Root - */ -public class PubkeyListActivity extends ListActivity implements EventListener { - public final static String TAG = "ConnectBot.PubkeyListActivity"; - - private static final int MAX_KEYFILE_SIZE = 8192; - private static final int REQUEST_CODE_PICK_FILE = 1; - - // Constants for AndExplorer's file picking intent - private static final String ANDEXPLORER_TITLE = "explorer_title"; - private static final String MIME_TYPE_ANDEXPLORER_FILE = "vnd.android.cursor.dir/lysesoft.andexplorer.file"; - - protected PubkeyDatabase pubkeydb; - private List<PubkeyBean> pubkeys; - - protected ClipboardManager clipboard; - - protected LayoutInflater inflater = null; - - protected TerminalManager bound = null; - - private MenuItem onstartToggle = null; - private MenuItem confirmUse = null; - - private ServiceConnection connection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - bound = ((TerminalManager.TerminalBinder) service).getService(); - - // update our listview binder to find the service - updateList(); - } - - public void onServiceDisconnected(ComponentName className) { - bound = null; - updateList(); - } - }; - - @Override - public void onStart() { - super.onStart(); - - bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); - - if(pubkeydb == null) - pubkeydb = new PubkeyDatabase(this); - } - - @Override - public void onStop() { - super.onStop(); - - unbindService(connection); - - if(pubkeydb != null) { - pubkeydb.close(); - pubkeydb = null; - } - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.act_pubkeylist); - - this.setTitle(String.format("%s: %s", - getResources().getText(R.string.app_name), - getResources().getText(R.string.title_pubkey_list))); - - // connect with hosts database and populate list - pubkeydb = new PubkeyDatabase(this); - - updateList(); - - registerForContextMenu(getListView()); - - getListView().setOnItemClickListener(new OnItemClickListener() { - public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { - PubkeyBean pubkey = (PubkeyBean) getListView().getItemAtPosition(position); - boolean loaded = bound.isKeyLoaded(pubkey.getNickname()); - - // handle toggling key in-memory on/off - if(loaded) { - bound.removeKey(pubkey.getNickname()); - updateList(); - } else { - handleAddKey(pubkey); - } - - } - }); - - clipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE); - - inflater = LayoutInflater.from(this); - } - - /** - * Read given file into memory as <code>byte[]</code>. - */ - protected static byte[] readRaw(File file) throws Exception { - InputStream is = new FileInputStream(file); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - - int bytesRead; - byte[] buffer = new byte[1024]; - while ((bytesRead = is.read(buffer)) != -1) { - os.write(buffer, 0, bytesRead); - } - - os.flush(); - os.close(); - is.close(); - - return os.toByteArray(); - - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - - MenuItem generatekey = menu.add(R.string.pubkey_generate); - generatekey.setIcon(android.R.drawable.ic_menu_manage); - generatekey.setIntent(new Intent(PubkeyListActivity.this, GeneratePubkeyActivity.class)); - - MenuItem importkey = menu.add(R.string.pubkey_import); - importkey.setIcon(android.R.drawable.ic_menu_upload); - importkey.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - Uri sdcard = Uri.fromFile(Environment.getExternalStorageDirectory()); - String pickerTitle = getString(R.string.pubkey_list_pick); - - // Try to use OpenIntent's file browser to pick a file - Intent intent = new Intent(FileManagerIntents.ACTION_PICK_FILE); - intent.setData(sdcard); - intent.putExtra(FileManagerIntents.EXTRA_TITLE, pickerTitle); - intent.putExtra(FileManagerIntents.EXTRA_BUTTON_TEXT, getString(android.R.string.ok)); - - try { - startActivityForResult(intent, REQUEST_CODE_PICK_FILE); - } catch (ActivityNotFoundException e) { - // If OI didn't work, try AndExplorer - intent = new Intent(Intent.ACTION_PICK); - intent.setDataAndType(sdcard, MIME_TYPE_ANDEXPLORER_FILE); - intent.putExtra(ANDEXPLORER_TITLE, pickerTitle); - - try { - startActivityForResult(intent, REQUEST_CODE_PICK_FILE); - } catch (ActivityNotFoundException e1) { - pickFileSimple(); - } - } - - return true; - } - }); - - return true; - } - - protected void handleAddKey(final PubkeyBean pubkey) { - if (pubkey.isEncrypted()) { - final View view = inflater.inflate(R.layout.dia_password, null); - final EditText passwordField = (EditText)view.findViewById(android.R.id.text1); - - new AlertDialog.Builder(PubkeyListActivity.this) - .setView(view) - .setPositiveButton(R.string.pubkey_unlock, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - handleAddKey(pubkey, passwordField.getText().toString()); - } - }) - .setNegativeButton(android.R.string.cancel, null).create().show(); - } else { - handleAddKey(pubkey, null); - } - } - - protected void handleAddKey(PubkeyBean keybean, String password) { - KeyPair pair = null; - if(PubkeyDatabase.KEY_TYPE_IMPORTED.equals(keybean.getType())) { - // load specific key using pem format - try { - pair = PEMDecoder.decode(new String(keybean.getPrivateKey()).toCharArray(), password); - } catch(Exception e) { - String message = getResources().getString(R.string.pubkey_failed_add, keybean.getNickname()); - Log.e(TAG, message, e); - Toast.makeText(PubkeyListActivity.this, message, Toast.LENGTH_LONG).show(); - } - } else { - // load using internal generated format - try { - PrivateKey privKey = PubkeyUtils.decodePrivate(keybean.getPrivateKey(), keybean.getType(), password); - PublicKey pubKey = PubkeyUtils.decodePublic(keybean.getPublicKey(), keybean.getType()); - Log.d(TAG, "Unlocked key " + PubkeyUtils.formatKey(pubKey)); - - pair = new KeyPair(pubKey, privKey); - } catch (Exception e) { - String message = getResources().getString(R.string.pubkey_failed_add, keybean.getNickname()); - Log.e(TAG, message, e); - Toast.makeText(PubkeyListActivity.this, message, Toast.LENGTH_LONG).show(); - return; - } - } - - if (pair == null) { - return; - } - - Log.d(TAG, String.format("Unlocked key '%s'", keybean.getNickname())); - - // save this key in memory - bound.addKey(keybean, pair, true); - - updateList(); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - // Create menu to handle deleting and editing pubkey - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - final PubkeyBean pubkey = (PubkeyBean) getListView().getItemAtPosition(info.position); - - menu.setHeaderTitle(pubkey.getNickname()); - - // TODO: option load/unload key from in-memory list - // prompt for password as needed for passworded keys - - // cant change password or clipboard imported keys - final boolean imported = PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType()); - final boolean loaded = bound.isKeyLoaded(pubkey.getNickname()); - - MenuItem load = menu.add(loaded ? R.string.pubkey_memory_unload : R.string.pubkey_memory_load); - load.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - if(loaded) { - bound.removeKey(pubkey.getNickname()); - updateList(); - } else { - handleAddKey(pubkey); - //bound.addKey(nickname, trileadKey); - } - return true; - } - }); - - onstartToggle = menu.add(R.string.pubkey_load_on_start); - onstartToggle.setEnabled(!pubkey.isEncrypted()); - onstartToggle.setCheckable(true); - onstartToggle.setChecked(pubkey.isStartup()); - onstartToggle.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // toggle onstart status - pubkey.setStartup(!pubkey.isStartup()); - pubkeydb.savePubkey(pubkey); - updateList(); - return true; - } - }); - - MenuItem copyPublicToClipboard = menu.add(R.string.pubkey_copy_public); - copyPublicToClipboard.setEnabled(!imported); - copyPublicToClipboard.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - try { - PublicKey pk = PubkeyUtils.decodePublic(pubkey.getPublicKey(), pubkey.getType()); - String openSSHPubkey = PubkeyUtils.convertToOpenSSHFormat(pk, pubkey.getNickname()); - - clipboard.setText(openSSHPubkey); - } catch (Exception e) { - e.printStackTrace(); - } - return true; - } - }); - - MenuItem copyPrivateToClipboard = menu.add(R.string.pubkey_copy_private); - copyPrivateToClipboard.setEnabled(!pubkey.isEncrypted() || imported); - copyPrivateToClipboard.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - try { - String data = null; - - if (imported) - data = new String(pubkey.getPrivateKey()); - else { - PrivateKey pk = PubkeyUtils.decodePrivate(pubkey.getPrivateKey(), pubkey.getType()); - data = PubkeyUtils.exportPEM(pk, null); - } - - clipboard.setText(data); - } catch (Exception e) { - e.printStackTrace(); - } - return true; - } - }); - - MenuItem changePassword = menu.add(R.string.pubkey_change_password); - changePassword.setEnabled(!imported); - changePassword.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - final View changePasswordView = inflater.inflate(R.layout.dia_changepassword, null, false); - ((TableRow)changePasswordView.findViewById(R.id.old_password_prompt)) - .setVisibility(pubkey.isEncrypted() ? View.VISIBLE : View.GONE); - new AlertDialog.Builder(PubkeyListActivity.this) - .setView(changePasswordView) - .setPositiveButton(R.string.button_change, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - String oldPassword = ((EditText)changePasswordView.findViewById(R.id.old_password)).getText().toString(); - String password1 = ((EditText)changePasswordView.findViewById(R.id.password1)).getText().toString(); - String password2 = ((EditText)changePasswordView.findViewById(R.id.password2)).getText().toString(); - - if (!password1.equals(password2)) { - new AlertDialog.Builder(PubkeyListActivity.this) - .setMessage(R.string.alert_passwords_do_not_match_msg) - .setPositiveButton(android.R.string.ok, null) - .create().show(); - return; - } - - try { - if (!pubkey.changePassword(oldPassword, password1)) - new AlertDialog.Builder(PubkeyListActivity.this) - .setMessage(R.string.alert_wrong_password_msg) - .setPositiveButton(android.R.string.ok, null) - .create().show(); - else { - pubkeydb.savePubkey(pubkey); - updateList(); - } - } catch (Exception e) { - Log.e(TAG, "Could not change private key password", e); - new AlertDialog.Builder(PubkeyListActivity.this) - .setMessage(R.string.alert_key_corrupted_msg) - .setPositiveButton(android.R.string.ok, null) - .create().show(); - } - } - }) - .setNegativeButton(android.R.string.cancel, null).create().show(); - - return true; - } - }); - - confirmUse = menu.add(R.string.pubkey_confirm_use); - confirmUse.setCheckable(true); - confirmUse.setChecked(pubkey.isConfirmUse()); - confirmUse.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // toggle confirm use - pubkey.setConfirmUse(!pubkey.isConfirmUse()); - pubkeydb.savePubkey(pubkey); - updateList(); - return true; - } - }); - - MenuItem delete = menu.add(R.string.pubkey_delete); - delete.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - // prompt user to make sure they really want this - new AlertDialog.Builder(PubkeyListActivity.this) - .setMessage(getString(R.string.delete_message, pubkey.getNickname())) - .setPositiveButton(R.string.delete_pos, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - - // dont forget to remove from in-memory - if(loaded) - bound.removeKey(pubkey.getNickname()); - - // delete from backend database and update gui - pubkeydb.deletePubkey(pubkey); - updateList(); - } - }) - .setNegativeButton(R.string.delete_neg, null).create().show(); - - return true; - } - }); - - } - - protected void updateList() { - if (pubkeydb == null) return; - - pubkeys = pubkeydb.allPubkeys(); - PubkeyAdapter adapter = new PubkeyAdapter(this, pubkeys); - - this.setListAdapter(adapter); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent intent) { - super.onActivityResult(requestCode, resultCode, intent); - - switch (requestCode) { - case REQUEST_CODE_PICK_FILE: - if (resultCode == RESULT_OK && intent != null) { - Uri uri = intent.getData(); - try { - if (uri != null) { - readKeyFromFile(new File(URI.create(uri.toString()))); - } else { - String filename = intent.getDataString(); - if (filename != null) - readKeyFromFile(new File(URI.create(filename))); - } - } catch (IllegalArgumentException e) { - Log.e(TAG, "Couldn't read from picked file", e); - } - } - break; - } - } - - /** - * @param name - */ - private void readKeyFromFile(File file) { - PubkeyBean pubkey = new PubkeyBean(); - - // find the exact file selected - pubkey.setNickname(file.getName()); - - if (file.length() > MAX_KEYFILE_SIZE) { - Toast.makeText(PubkeyListActivity.this, - R.string.pubkey_import_parse_problem, - Toast.LENGTH_LONG).show(); - return; - } - - // parse the actual key once to check if its encrypted - // then save original file contents into our database - try { - byte[] raw = readRaw(file); - - String data = new String(raw); - if (data.startsWith(PubkeyUtils.PKCS8_START)) { - int start = data.indexOf(PubkeyUtils.PKCS8_START) + PubkeyUtils.PKCS8_START.length(); - int end = data.indexOf(PubkeyUtils.PKCS8_END); - - if (end > start) { - char[] encoded = data.substring(start, end - 1).toCharArray(); - Log.d(TAG, "encoded: " + new String(encoded)); - byte[] decoded = Base64.decode(encoded); - - KeyPair kp = PubkeyUtils.recoverKeyPair(decoded); - - pubkey.setType(kp.getPrivate().getAlgorithm()); - pubkey.setPrivateKey(kp.getPrivate().getEncoded()); - pubkey.setPublicKey(kp.getPublic().getEncoded()); - } else { - Log.e(TAG, "Problem parsing PKCS#8 file; corrupt?"); - Toast.makeText(PubkeyListActivity.this, - R.string.pubkey_import_parse_problem, - Toast.LENGTH_LONG).show(); - } - } else { - PEMStructure struct = PEMDecoder.parsePEM(new String(raw).toCharArray()); - pubkey.setEncrypted(PEMDecoder.isPEMEncrypted(struct)); - pubkey.setType(PubkeyDatabase.KEY_TYPE_IMPORTED); - pubkey.setPrivateKey(raw); - } - - // write new value into database - if (pubkeydb == null) - pubkeydb = new PubkeyDatabase(this); - pubkeydb.savePubkey(pubkey); - - updateList(); - } catch(Exception e) { - Log.e(TAG, "Problem parsing imported private key", e); - Toast.makeText(PubkeyListActivity.this, R.string.pubkey_import_parse_problem, Toast.LENGTH_LONG).show(); - } - } - - /** - * - */ - private void pickFileSimple() { - // build list of all files in sdcard root - final File sdcard = Environment.getExternalStorageDirectory(); - Log.d(TAG, sdcard.toString()); - - // Don't show a dialog if the SD card is completely absent. - final String state = Environment.getExternalStorageState(); - if (!Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) - && !Environment.MEDIA_MOUNTED.equals(state)) { - new AlertDialog.Builder(PubkeyListActivity.this) - .setMessage(R.string.alert_sdcard_absent) - .setNegativeButton(android.R.string.cancel, null).create().show(); - return; - } - - List<String> names = new LinkedList<String>(); - { - File[] files = sdcard.listFiles(); - if (files != null) { - for(File file : sdcard.listFiles()) { - if(file.isDirectory()) continue; - names.add(file.getName()); - } - } - } - Collections.sort(names); - - final String[] namesList = names.toArray(new String[] {}); - Log.d(TAG, names.toString()); - - // prompt user to select any file from the sdcard root - new AlertDialog.Builder(PubkeyListActivity.this) - .setTitle(R.string.pubkey_list_pick) - .setItems(namesList, new OnClickListener() { - public void onClick(DialogInterface arg0, int arg1) { - String name = namesList[arg1]; - - readKeyFromFile(new File(sdcard, name)); - } - }) - .setNegativeButton(android.R.string.cancel, null).create().show(); - } - - class PubkeyAdapter extends ArrayAdapter<PubkeyBean> { - private List<PubkeyBean> pubkeys; - - class ViewHolder { - public TextView nickname; - public TextView caption; - public ImageView icon; - } - - public PubkeyAdapter(Context context, List<PubkeyBean> pubkeys) { - super(context, R.layout.item_pubkey, pubkeys); - - this.pubkeys = pubkeys; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - ViewHolder holder; - - if (convertView == null) { - convertView = inflater.inflate(R.layout.item_pubkey, null, false); - - holder = new ViewHolder(); - - holder.nickname = (TextView) convertView.findViewById(android.R.id.text1); - holder.caption = (TextView) convertView.findViewById(android.R.id.text2); - holder.icon = (ImageView) convertView.findViewById(android.R.id.icon1); - - convertView.setTag(holder); - } else - holder = (ViewHolder) convertView.getTag(); - - PubkeyBean pubkey = pubkeys.get(position); - holder.nickname.setText(pubkey.getNickname()); - - boolean imported = PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType()); - - if (imported) { - try { - PEMStructure struct = PEMDecoder.parsePEM(new String(pubkey.getPrivateKey()).toCharArray()); - String type = (struct.pemType == PEMDecoder.PEM_RSA_PRIVATE_KEY) ? "RSA" : "DSA"; - holder.caption.setText(String.format("%s unknown-bit", type)); - } catch (IOException e) { - Log.e(TAG, "Error decoding IMPORTED public key at " + pubkey.getId(), e); - } - } else { - try { - holder.caption.setText(pubkey.getDescription()); - } catch (Exception e) { - Log.e(TAG, "Error decoding public key at " + pubkey.getId(), e); - holder.caption.setText(R.string.pubkey_unknown_format); - } - } - - if (bound == null) { - holder.icon.setVisibility(View.GONE); - } else { - holder.icon.setVisibility(View.VISIBLE); - - if (bound.isKeyLoaded(pubkey.getNickname())) - holder.icon.setImageState(new int[] { android.R.attr.state_checked }, true); - else - holder.icon.setImageState(new int[] { }, true); - } - - return convertView; - } - } -} diff --git a/src/org/connectbot/SettingsActivity.java b/src/org/connectbot/SettingsActivity.java deleted file mode 100644 index 460805d..0000000 --- a/src/org/connectbot/SettingsActivity.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import org.connectbot.util.PreferenceConstants; - -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import android.preference.PreferenceManager; -import android.util.Log; - -public class SettingsActivity extends PreferenceActivity { - private static final String TAG = "ConnectBot.Settings"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - try { - addPreferencesFromResource(R.xml.preferences); - } catch (ClassCastException e) { - Log.e(TAG, "Shared preferences are corrupt! Resetting to default values."); - - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - - // Blow away all the preferences - SharedPreferences.Editor editor = preferences.edit(); - editor.clear(); - editor.commit(); - - PreferenceManager.setDefaultValues(this, R.xml.preferences, true); - - // Since they were able to get to the Settings activity, they already agreed to the EULA - editor = preferences.edit(); - editor.putBoolean(PreferenceConstants.EULA, true); - editor.commit(); - - addPreferencesFromResource(R.xml.preferences); - } - - // TODO: add parse checking here to make sure we have integer value for scrollback - - } - -} diff --git a/src/org/connectbot/StrictModeSetup.java b/src/org/connectbot/StrictModeSetup.java deleted file mode 100644 index 3a2000e..0000000 --- a/src/org/connectbot/StrictModeSetup.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.connectbot; -import android.os.StrictMode; -public class StrictModeSetup { - public static void run() { - StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX); - } -} diff --git a/src/org/connectbot/TerminalView.java b/src/org/connectbot/TerminalView.java deleted file mode 100644 index 02683c2..0000000 --- a/src/org/connectbot/TerminalView.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.connectbot.bean.SelectionArea; -import org.connectbot.service.FontSizeChangedListener; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalKeyListener; - -import android.app.Activity; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ResolveInfo; -import android.database.Cursor; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PixelXorXfermode; -import android.graphics.RectF; -import android.net.Uri; -import android.os.AsyncTask; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; -import android.view.inputmethod.BaseInputConnection; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; -import android.widget.Toast; -import de.mud.terminal.VDUBuffer; - -/** - * User interface {@link View} for showing a TerminalBridge in an - * {@link Activity}. Handles drawing bitmap updates and passing keystrokes down - * to terminal. - * - * @author jsharkey - */ -public class TerminalView extends View implements FontSizeChangedListener { - - private final Context context; - public final TerminalBridge bridge; - private final Paint paint; - private final Paint cursorPaint; - private final Paint cursorStrokePaint; - - // Cursor paints to distinguish modes - private Path ctrlCursor, altCursor, shiftCursor; - private RectF tempSrc, tempDst; - private Matrix scaleMatrix; - private static final Matrix.ScaleToFit scaleType = Matrix.ScaleToFit.FILL; - - private Toast notification = null; - private String lastNotification = null; - private volatile boolean notifications = true; - - // Related to Accessibility Features - private boolean mAccessibilityInitialized = false; - private boolean mAccessibilityActive = true; - private Object[] mAccessibilityLock = new Object[0]; - private StringBuffer mAccessibilityBuffer; - private Pattern mControlCodes = null; - private Matcher mCodeMatcher = null; - private AccessibilityEventSender mEventSender = null; - - private static final String BACKSPACE_CODE = "\\x08\\x1b\\[K"; - private static final String CONTROL_CODE_PATTERN = "\\x1b\\[K[^m]+[m|:]"; - - private static final int ACCESSIBILITY_EVENT_THRESHOLD = 1000; - private static final String SCREENREADER_INTENT_ACTION = "android.accessibilityservice.AccessibilityService"; - private static final String SCREENREADER_INTENT_CATEGORY = "android.accessibilityservice.category.FEEDBACK_SPOKEN"; - - public TerminalView(Context context, TerminalBridge bridge) { - super(context); - - this.context = context; - this.bridge = bridge; - paint = new Paint(); - - setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); - setFocusable(true); - setFocusableInTouchMode(true); - - cursorPaint = new Paint(); - cursorPaint.setColor(bridge.color[bridge.defaultFg]); - cursorPaint.setXfermode(new PixelXorXfermode(bridge.color[bridge.defaultBg])); - cursorPaint.setAntiAlias(true); - - cursorStrokePaint = new Paint(cursorPaint); - cursorStrokePaint.setStrokeWidth(0.1f); - cursorStrokePaint.setStyle(Paint.Style.STROKE); - - /* - * Set up our cursor indicators on a 1x1 Path object which we can later - * transform to our character width and height - */ - // TODO make this into a resource somehow - shiftCursor = new Path(); - shiftCursor.lineTo(0.5f, 0.33f); - shiftCursor.lineTo(1.0f, 0.0f); - - altCursor = new Path(); - altCursor.moveTo(0.0f, 1.0f); - altCursor.lineTo(0.5f, 0.66f); - altCursor.lineTo(1.0f, 1.0f); - - ctrlCursor = new Path(); - ctrlCursor.moveTo(0.0f, 0.25f); - ctrlCursor.lineTo(1.0f, 0.5f); - ctrlCursor.lineTo(0.0f, 0.75f); - - // For creating the transform when the terminal resizes - tempSrc = new RectF(); - tempSrc.set(0.0f, 0.0f, 1.0f, 1.0f); - tempDst = new RectF(); - scaleMatrix = new Matrix(); - - bridge.addFontSizeChangedListener(this); - - // connect our view up to the bridge - setOnKeyListener(bridge.getKeyHandler()); - - mAccessibilityBuffer = new StringBuffer(); - - // Enable accessibility features if a screen reader is active. - new AccessibilityStateTester().execute((Void) null); - } - - public void destroy() { - // tell bridge to destroy its bitmap - bridge.parentDestroyed(); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - bridge.parentChanged(this); - - scaleCursors(); - } - - public void onFontSizeChanged(float size) { - scaleCursors(); - } - - private void scaleCursors() { - // Create a scale matrix to scale our 1x1 representation of the cursor - tempDst.set(0.0f, 0.0f, bridge.charWidth, bridge.charHeight); - scaleMatrix.setRectToRect(tempSrc, tempDst, scaleType); - } - - @Override - public void onDraw(Canvas canvas) { - if(bridge.bitmap != null) { - // draw the bitmap - bridge.onDraw(); - - // draw the bridge bitmap if it exists - canvas.drawBitmap(bridge.bitmap, 0, 0, paint); - - // also draw cursor if visible - if (bridge.buffer.isCursorVisible()) { - int cursorColumn = bridge.buffer.getCursorColumn(); - final int cursorRow = bridge.buffer.getCursorRow(); - - final int columns = bridge.buffer.getColumns(); - - if (cursorColumn == columns) - cursorColumn = columns - 1; - - if (cursorColumn < 0 || cursorRow < 0) - return; - - int currentAttribute = bridge.buffer.getAttributes( - cursorColumn, cursorRow); - boolean onWideCharacter = (currentAttribute & VDUBuffer.FULLWIDTH) != 0; - - int x = cursorColumn * bridge.charWidth; - int y = (bridge.buffer.getCursorRow() - + bridge.buffer.screenBase - bridge.buffer.windowBase) - * bridge.charHeight; - - // Save the current clip and translation - canvas.save(); - - canvas.translate(x, y); - canvas.clipRect(0, 0, - bridge.charWidth * (onWideCharacter ? 2 : 1), - bridge.charHeight); - canvas.drawPaint(cursorPaint); - - final int deadKey = bridge.getKeyHandler().getDeadKey(); - if (deadKey != 0) { - canvas.drawText(new char[] { (char)deadKey }, 0, 1, 0, 0, cursorStrokePaint); - } - - // Make sure we scale our decorations to the correct size. - canvas.concat(scaleMatrix); - - int metaState = bridge.getKeyHandler().getMetaState(); - - if ((metaState & TerminalKeyListener.OUR_SHIFT_ON) != 0) - canvas.drawPath(shiftCursor, cursorStrokePaint); - else if ((metaState & TerminalKeyListener.OUR_SHIFT_LOCK) != 0) - canvas.drawPath(shiftCursor, cursorPaint); - - if ((metaState & TerminalKeyListener.OUR_ALT_ON) != 0) - canvas.drawPath(altCursor, cursorStrokePaint); - else if ((metaState & TerminalKeyListener.OUR_ALT_LOCK) != 0) - canvas.drawPath(altCursor, cursorPaint); - - if ((metaState & TerminalKeyListener.OUR_CTRL_ON) != 0) - canvas.drawPath(ctrlCursor, cursorStrokePaint); - else if ((metaState & TerminalKeyListener.OUR_CTRL_LOCK) != 0) - canvas.drawPath(ctrlCursor, cursorPaint); - - // Restore previous clip region - canvas.restore(); - } - - // draw any highlighted area - if (bridge.isSelectingForCopy()) { - SelectionArea area = bridge.getSelectionArea(); - canvas.save(Canvas.CLIP_SAVE_FLAG); - canvas.clipRect( - area.getLeft() * bridge.charWidth, - area.getTop() * bridge.charHeight, - (area.getRight() + 1) * bridge.charWidth, - (area.getBottom() + 1) * bridge.charHeight - ); - canvas.drawPaint(cursorPaint); - canvas.restore(); - } - } - } - - public void notifyUser(String message) { - if (!notifications) - return; - - if (notification != null) { - // Don't keep telling the user the same thing. - if (lastNotification != null && lastNotification.equals(message)) - return; - - notification.setText(message); - notification.show(); - } else { - notification = Toast.makeText(context, message, Toast.LENGTH_SHORT); - notification.show(); - } - - lastNotification = message; - } - - /** - * Ask the {@link TerminalBridge} we're connected to to resize to a specific size. - * @param width - * @param height - */ - public void forceSize(int width, int height) { - bridge.resizeComputed(width, height, getWidth(), getHeight()); - } - - /** - * Sets the ability for the TerminalView to display Toast notifications to the user. - * @param value whether to enable notifications or not - */ - public void setNotifications(boolean value) { - notifications = value; - } - - @Override - public boolean onCheckIsTextEditor() { - return true; - } - - @Override - public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - outAttrs.imeOptions |= - EditorInfo.IME_FLAG_NO_EXTRACT_UI | - EditorInfo.IME_FLAG_NO_ENTER_ACTION | - EditorInfo.IME_ACTION_NONE; - outAttrs.inputType = EditorInfo.TYPE_NULL; - return new BaseInputConnection(this, false) { - @Override - public boolean deleteSurroundingText (int leftLength, int rightLength) { - if (rightLength == 0 && leftLength == 0) { - return this.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); - } - for (int i = 0; i < leftLength; i++) { - this.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); - } - // TODO: forward delete - return true; - } - }; - } - - public void propagateConsoleText(char[] rawText, int length) { - if (mAccessibilityActive) { - synchronized (mAccessibilityLock) { - mAccessibilityBuffer.append(rawText, 0, length); - } - - if (mAccessibilityInitialized) { - if (mEventSender != null) { - removeCallbacks(mEventSender); - } else { - mEventSender = new AccessibilityEventSender(); - } - - postDelayed(mEventSender, ACCESSIBILITY_EVENT_THRESHOLD); - } - } - } - - private class AccessibilityEventSender implements Runnable { - public void run() { - synchronized (mAccessibilityLock) { - if (mCodeMatcher == null) { - mCodeMatcher = mControlCodes.matcher(mAccessibilityBuffer); - } else { - mCodeMatcher.reset(mAccessibilityBuffer); - } - - // Strip all control codes out. - mAccessibilityBuffer = new StringBuffer(mCodeMatcher.replaceAll(" ")); - - // Apply Backspaces using backspace character sequence - int i = mAccessibilityBuffer.indexOf(BACKSPACE_CODE); - while (i != -1) { - mAccessibilityBuffer = mAccessibilityBuffer.replace(i == 0 ? 0 : i - 1, i - + BACKSPACE_CODE.length(), ""); - i = mAccessibilityBuffer.indexOf(BACKSPACE_CODE); - } - - if (mAccessibilityBuffer.length() > 0) { - AccessibilityEvent event = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); - event.setFromIndex(0); - event.setAddedCount(mAccessibilityBuffer.length()); - event.getText().add(mAccessibilityBuffer); - - sendAccessibilityEventUnchecked(event); - mAccessibilityBuffer.setLength(0); - } - } - } - } - - private class AccessibilityStateTester extends AsyncTask<Void, Void, Boolean> { - @Override - protected Boolean doInBackground(Void... params) { - /* - * Presumably if the accessibility manager is not enabled, we don't - * need to send accessibility events. - */ - final AccessibilityManager accessibility = (AccessibilityManager) context - .getSystemService(Context.ACCESSIBILITY_SERVICE); - if (!accessibility.isEnabled()) { - return false; - } - - /* - * Restrict the set of intents to only accessibility services that - * have the category FEEDBACK_SPOKEN (aka, screen readers). - */ - final Intent screenReaderIntent = new Intent(SCREENREADER_INTENT_ACTION); - screenReaderIntent.addCategory(SCREENREADER_INTENT_CATEGORY); - - final ContentResolver cr = context.getContentResolver(); - - final List<ResolveInfo> screenReaders = context.getPackageManager().queryIntentServices( - screenReaderIntent, 0); - - boolean foundScreenReader = false; - - final int N = screenReaders.size(); - for (int i = 0; i < N; i++) { - final ResolveInfo screenReader = screenReaders.get(i); - - /* - * All screen readers are expected to implement a content - * provider that responds to: - * content://<nameofpackage>.providers.StatusProvider - */ - final Cursor cursor = cr.query( - Uri.parse("content://" + screenReader.serviceInfo.packageName - + ".providers.StatusProvider"), null, null, null, null); - if (cursor != null && cursor.moveToFirst()) { - /* - * These content providers use a special cursor that only has - * one element, an integer that is 1 if the screen reader is - * running. - */ - final int status = cursor.getInt(0); - - cursor.close(); - - if (status == 1) { - foundScreenReader = true; - break; - } - } - } - - if (foundScreenReader) { - mControlCodes = Pattern.compile(CONTROL_CODE_PATTERN); - } - - return foundScreenReader; - } - - @Override - protected void onPostExecute(Boolean result) { - mAccessibilityActive = result; - - mAccessibilityInitialized = true; - - if (result) { - mEventSender = new AccessibilityEventSender(); - postDelayed(mEventSender, ACCESSIBILITY_EVENT_THRESHOLD); - } else { - mAccessibilityBuffer = null; - } - } - } -} diff --git a/src/org/connectbot/WizardActivity.java b/src/org/connectbot/WizardActivity.java deleted file mode 100644 index 35a60ca..0000000 --- a/src/org/connectbot/WizardActivity.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot; - -import org.connectbot.util.HelpTopicView; - -import android.app.Activity; -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.ViewFlipper; - -/** - * Show a series of wizard-like steps to the user, which might include an EULA, - * program credits, and helpful hints. - * - * @author jsharkey - */ -public class WizardActivity extends Activity { - protected ViewFlipper flipper = null; - private Button next, prev; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.act_wizard); - - this.flipper = (ViewFlipper) findViewById(R.id.wizard_flipper); - - // inflate the layout for EULA step - LayoutInflater inflater = LayoutInflater.from(this); - this.flipper.addView(inflater.inflate(R.layout.wiz_eula, this.flipper, false)); - - // Add a view for each help topic we want the user to see. - String[] topics = getResources().getStringArray(R.array.list_wizard_topics); - for (String topic : topics) { - flipper.addView(new HelpTopicView(this).setTopic(topic)); - } - - next = (Button)this.findViewById(R.id.action_next); - next.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - if(isLastDisplayed()) { - // user walked past end of wizard, so return okay - WizardActivity.this.setResult(Activity.RESULT_OK); - WizardActivity.this.finish(); - } else { - // show next step and update buttons - flipper.showNext(); - updateButtons(); - } - } - }); - - prev = (Button)this.findViewById(R.id.action_prev); - prev.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - if(isFirstDisplayed()) { - // user walked past beginning of wizard, so return that they cancelled - WizardActivity.this.setResult(Activity.RESULT_CANCELED); - WizardActivity.this.finish(); - } else { - // show previous step and update buttons - flipper.showPrevious(); - updateButtons(); - } - } - }); - - this.updateButtons(); - } - - protected boolean isFirstDisplayed() { - return (flipper.getDisplayedChild() == 0); - } - - protected boolean isLastDisplayed() { - return (flipper.getDisplayedChild() == flipper.getChildCount() - 1); - } - - protected void updateButtons() { - boolean eula = (flipper.getDisplayedChild() == 0); - - next.setText(eula ? getString(R.string.wizard_agree) : getString(R.string.wizard_next)); - prev.setText(eula ? getString(R.string.delete_neg) : getString(R.string.wizard_back)); - } -} diff --git a/src/org/connectbot/bean/AbstractBean.java b/src/org/connectbot/bean/AbstractBean.java deleted file mode 100644 index 7f55785..0000000 --- a/src/org/connectbot/bean/AbstractBean.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.bean; - -import java.util.Map.Entry; - -import org.connectbot.util.XmlBuilder; - -import android.content.ContentValues; - -/** - * @author Kenny Root - * - */ -abstract class AbstractBean { - public abstract ContentValues getValues(); - public abstract String getBeanName(); - - public String toXML() { - XmlBuilder xml = new XmlBuilder(); - - xml.append(String.format("<%s>", getBeanName())); - - ContentValues values = getValues(); - for (Entry<String, Object> entry : values.valueSet()) { - Object value = entry.getValue(); - if (value != null) - xml.append(entry.getKey(), value); - } - xml.append(String.format("</%s>", getBeanName())); - - return xml.toString(); - } -} diff --git a/src/org/connectbot/bean/HostBean.java b/src/org/connectbot/bean/HostBean.java deleted file mode 100644 index 2fd7bfb..0000000 --- a/src/org/connectbot/bean/HostBean.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.bean; - -import org.connectbot.util.HostDatabase; - -import android.content.ContentValues; -import android.net.Uri; - -/** - * @author Kenny Root - * - */ -public class HostBean extends AbstractBean { - public static final String BEAN_NAME = "host"; - - /* Database fields */ - private long id = -1; - private String nickname = null; - private String username = null; - private String hostname = null; - private int port = 22; - private String protocol = "ssh"; - private String hostKeyAlgo = null; - private byte[] hostKey = null; - private long lastConnect = -1; - private String color; - private boolean useKeys = true; - private String useAuthAgent = HostDatabase.AUTHAGENT_NO; - private String postLogin = null; - private long pubkeyId = -1; - private boolean wantSession = true; - private String delKey = HostDatabase.DELKEY_DEL; - private int fontSize = -1; - private boolean compression = false; - private String encoding = HostDatabase.ENCODING_DEFAULT; - private boolean stayConnected = false; - - public HostBean() { - - } - - @Override - public String getBeanName() { - return BEAN_NAME; - } - - public HostBean(String nickname, String protocol, String username, String hostname, int port) { - this.nickname = nickname; - this.protocol = protocol; - this.username = username; - this.hostname = hostname; - this.port = port; - } - - public void setId(long id) { - this.id = id; - } - public long getId() { - return id; - } - public void setNickname(String nickname) { - this.nickname = nickname; - } - public String getNickname() { - return nickname; - } - public void setUsername(String username) { - this.username = username; - } - public String getUsername() { - return username; - } - public void setHostname(String hostname) { - this.hostname = hostname; - } - public String getHostname() { - return hostname; - } - public void setPort(int port) { - this.port = port; - } - public int getPort() { - return port; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public String getProtocol() { - return protocol; - } - - public void setHostKeyAlgo(String hostKeyAlgo) { - this.hostKeyAlgo = hostKeyAlgo; - } - public String getHostKeyAlgo() { - return hostKeyAlgo; - } - public void setHostKey(byte[] hostKey) { - if (hostKey == null) - this.hostKey = null; - else - this.hostKey = hostKey.clone(); - } - public byte[] getHostKey() { - if (hostKey == null) - return null; - else - return hostKey.clone(); - } - public void setLastConnect(long lastConnect) { - this.lastConnect = lastConnect; - } - public long getLastConnect() { - return lastConnect; - } - public void setColor(String color) { - this.color = color; - } - public String getColor() { - return color; - } - public void setUseKeys(boolean useKeys) { - this.useKeys = useKeys; - } - public boolean getUseKeys() { - return useKeys; - } - public void setUseAuthAgent(String useAuthAgent) { - this.useAuthAgent = useAuthAgent; - } - public String getUseAuthAgent() { - return useAuthAgent; - } - public void setPostLogin(String postLogin) { - this.postLogin = postLogin; - } - public String getPostLogin() { - return postLogin; - } - public void setPubkeyId(long pubkeyId) { - this.pubkeyId = pubkeyId; - } - public long getPubkeyId() { - return pubkeyId; - } - public void setWantSession(boolean wantSession) { - this.wantSession = wantSession; - } - public boolean getWantSession() { - return wantSession; - } - public void setDelKey(String delKey) { - this.delKey = delKey; - } - public String getDelKey() { - return delKey; - } - public void setFontSize(int fontSize) { - this.fontSize = fontSize; - } - public int getFontSize() { - return fontSize; - } - public void setCompression(boolean compression) { - this.compression = compression; - } - public boolean getCompression() { - return compression; - } - - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - public String getEncoding() { - return this.encoding; - } - - public void setStayConnected(boolean stayConnected) { - this.stayConnected = stayConnected; - } - - public boolean getStayConnected() { - return stayConnected; - } - - public String getDescription() { - String description = String.format("%s@%s", username, hostname); - - if (port != 22) - description += String.format(":%d", port); - - return description; - } - - @Override - public ContentValues getValues() { - ContentValues values = new ContentValues(); - - values.put(HostDatabase.FIELD_HOST_NICKNAME, nickname); - values.put(HostDatabase.FIELD_HOST_PROTOCOL, protocol); - values.put(HostDatabase.FIELD_HOST_USERNAME, username); - values.put(HostDatabase.FIELD_HOST_HOSTNAME, hostname); - values.put(HostDatabase.FIELD_HOST_PORT, port); - values.put(HostDatabase.FIELD_HOST_HOSTKEYALGO, hostKeyAlgo); - values.put(HostDatabase.FIELD_HOST_HOSTKEY, hostKey); - values.put(HostDatabase.FIELD_HOST_LASTCONNECT, lastConnect); - values.put(HostDatabase.FIELD_HOST_COLOR, color); - values.put(HostDatabase.FIELD_HOST_USEKEYS, Boolean.toString(useKeys)); - values.put(HostDatabase.FIELD_HOST_USEAUTHAGENT, useAuthAgent); - values.put(HostDatabase.FIELD_HOST_POSTLOGIN, postLogin); - values.put(HostDatabase.FIELD_HOST_PUBKEYID, pubkeyId); - values.put(HostDatabase.FIELD_HOST_WANTSESSION, Boolean.toString(wantSession)); - values.put(HostDatabase.FIELD_HOST_DELKEY, delKey); - values.put(HostDatabase.FIELD_HOST_FONTSIZE, fontSize); - values.put(HostDatabase.FIELD_HOST_COMPRESSION, Boolean.toString(compression)); - values.put(HostDatabase.FIELD_HOST_ENCODING, encoding); - values.put(HostDatabase.FIELD_HOST_STAYCONNECTED, stayConnected); - - return values; - } - - @Override - public boolean equals(Object o) { - if (o == null || !(o instanceof HostBean)) - return false; - - HostBean host = (HostBean)o; - - if (id != -1 && host.getId() != -1) - return host.getId() == id; - - if (nickname == null) { - if (host.getNickname() != null) - return false; - } else if (!nickname.equals(host.getNickname())) - return false; - - if (protocol == null) { - if (host.getProtocol() != null) - return false; - } else if (!protocol.equals(host.getProtocol())) - return false; - - if (username == null) { - if (host.getUsername() != null) - return false; - } else if (!username.equals(host.getUsername())) - return false; - - if (hostname == null) { - if (host.getHostname() != null) - return false; - } else if (!hostname.equals(host.getHostname())) - return false; - - if (port != host.getPort()) - return false; - - return true; - } - - @Override - public int hashCode() { - int hash = 7; - - if (id != -1) - return (int)id; - - hash = 31 * hash + (null == nickname ? 0 : nickname.hashCode()); - hash = 31 * hash + (null == protocol ? 0 : protocol.hashCode()); - hash = 31 * hash + (null == username ? 0 : username.hashCode()); - hash = 31 * hash + (null == hostname ? 0 : hostname.hashCode()); - hash = 31 * hash + port; - - return hash; - } - - /** - * @return URI identifying this HostBean - */ - public Uri getUri() { - StringBuilder sb = new StringBuilder(); - sb.append(protocol) - .append("://"); - - if (username != null) - sb.append(Uri.encode(username)) - .append('@'); - - sb.append(Uri.encode(hostname)) - .append(':') - .append(port) - .append("/#") - .append(nickname); - return Uri.parse(sb.toString()); - } - -} diff --git a/src/org/connectbot/bean/PortForwardBean.java b/src/org/connectbot/bean/PortForwardBean.java deleted file mode 100644 index 2bdaf20..0000000 --- a/src/org/connectbot/bean/PortForwardBean.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.bean; - -import org.connectbot.util.HostDatabase; - -import android.content.ContentValues; - - -/** - * @author Kenny Root - * - */ -public class PortForwardBean extends AbstractBean { - public static final String BEAN_NAME = "portforward"; - - /* Database fields */ - private long id = -1; - private long hostId = -1; - private String nickname = null; - private String type = null; - private int sourcePort = -1; - private String destAddr = null; - private int destPort = -1; - - /* Transient values */ - private boolean enabled = false; - private Object identifier = null; - - /** - * @param id database ID of port forward - * @param nickname Nickname to use to identify port forward - * @param type One of the port forward types from {@link HostDatabase} - * @param sourcePort Source port number - * @param destAddr Destination hostname or IP address - * @param destPort Destination port number - */ - public PortForwardBean(long id, long hostId, String nickname, String type, int sourcePort, String destAddr, int destPort) { - this.id = id; - this.hostId = hostId; - this.nickname = nickname; - this.type = type; - this.sourcePort = sourcePort; - this.destAddr = destAddr; - this.destPort = destPort; - } - - /** - * @param type One of the port forward types from {@link HostDatabase} - * @param source Source port number - * @param dest Destination is "host:port" format - */ - public PortForwardBean(long hostId, String nickname, String type, String source, String dest) { - this.hostId = hostId; - this.nickname = nickname; - this.type = type; - this.sourcePort = Integer.parseInt(source); - - setDest(dest); - } - - public String getBeanName() { - return BEAN_NAME; - } - - /** - * @param id the id to set - */ - public void setId(long id) { - this.id = id; - } - - /** - * @return the id - */ - public long getId() { - return id; - } - - /** - * @param nickname the nickname to set - */ - public void setNickname(String nickname) { - this.nickname = nickname; - } - - /** - * @return the nickname - */ - public String getNickname() { - return nickname; - } - - /** - * @param type the type to set - */ - public void setType(String type) { - this.type = type; - } - - /** - * @return the type - */ - public String getType() { - return type; - } - - /** - * @param sourcePort the sourcePort to set - */ - public void setSourcePort(int sourcePort) { - this.sourcePort = sourcePort; - } - - /** - * @return the sourcePort - */ - public int getSourcePort() { - return sourcePort; - } - - /** - * @param dest The destination in "host:port" format - */ - public final void setDest(String dest) { - String[] destSplit = dest.split(":"); - this.destAddr = destSplit[0]; - if (destSplit.length > 1) - this.destPort = Integer.parseInt(destSplit[1]); - } - - /** - * @param destAddr the destAddr to set - */ - public void setDestAddr(String destAddr) { - this.destAddr = destAddr; - } - - /** - * @return the destAddr - */ - public String getDestAddr() { - return destAddr; - } - - /** - * @param destPort the destPort to set - */ - public void setDestPort(int destPort) { - this.destPort = destPort; - } - - /** - * @return the destPort - */ - public int getDestPort() { - return destPort; - } - - /** - * @param enabled the enabled to set - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - /** - * @return the enabled - */ - public boolean isEnabled() { - return enabled; - } - - /** - * @param identifier the identifier of this particular type to set - */ - public void setIdentifier(Object identifier) { - this.identifier = identifier; - } - - /** - * @return the identifier used by this particular type - */ - public Object getIdentifier() { - return identifier; - } - - /** - * @return human readable description of the port forward - */ - public CharSequence getDescription() { - String description = "Unknown type"; - - if (HostDatabase.PORTFORWARD_LOCAL.equals(type)) { - description = String.format("Local port %d to %s:%d", sourcePort, destAddr, destPort); - } else if (HostDatabase.PORTFORWARD_REMOTE.equals(type)) { - description = String.format("Remote port %d to %s:%d", sourcePort, destAddr, destPort); -/* I don't think we need the SOCKS4 type. - } else if (HostDatabase.PORTFORWARD_DYNAMIC4.equals(type)) { - description = String.format("Dynamic port %d (SOCKS4)", sourcePort); -*/ - } else if (HostDatabase.PORTFORWARD_DYNAMIC5.equals(type)) { - description = String.format("Dynamic port %d (SOCKS)", sourcePort); - } - - return description; - } - - /** - * @return - */ - public ContentValues getValues() { - ContentValues values = new ContentValues(); - - values.put(HostDatabase.FIELD_PORTFORWARD_HOSTID, hostId); - values.put(HostDatabase.FIELD_PORTFORWARD_NICKNAME, nickname); - values.put(HostDatabase.FIELD_PORTFORWARD_TYPE, type); - values.put(HostDatabase.FIELD_PORTFORWARD_SOURCEPORT, sourcePort); - values.put(HostDatabase.FIELD_PORTFORWARD_DESTADDR, destAddr); - values.put(HostDatabase.FIELD_PORTFORWARD_DESTPORT, destPort); - - return values; - } -} diff --git a/src/org/connectbot/bean/PubkeyBean.java b/src/org/connectbot/bean/PubkeyBean.java deleted file mode 100644 index 656c6af..0000000 --- a/src/org/connectbot/bean/PubkeyBean.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.bean; - -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; - -import org.connectbot.util.PubkeyDatabase; -import org.connectbot.util.PubkeyUtils; - -import android.content.ContentValues; - -/** - * @author Kenny Root - * - */ -public class PubkeyBean extends AbstractBean { - public static final String BEAN_NAME = "pubkey"; - - private static final String KEY_TYPE_RSA = "RSA"; - - private static final String KEY_TYPE_DSA = "DSA"; - - private static final String KEY_TYPE_EC = "EC"; - - /* Database fields */ - private long id; - private String nickname; - private String type; - private byte[] privateKey; - private byte[] publicKey; - private boolean encrypted = false; - private boolean startup = false; - private boolean confirmUse = false; - private int lifetime = 0; - - /* Transient values */ - private transient boolean unlocked = false; - private transient Object unlockedPrivate = null; - private transient String description; - - @Override - public String getBeanName() { - return BEAN_NAME; - } - - public void setId(long id) { - this.id = id; - } - - public long getId() { - return id; - } - - public void setNickname(String nickname) { - this.nickname = nickname; - } - - public String getNickname() { - return nickname; - } - - public void setType(String type) { - this.type = type; - } - - public String getType() { - return type; - } - - public void setPrivateKey(byte[] privateKey) { - if (privateKey == null) - this.privateKey = null; - else - this.privateKey = privateKey.clone(); - } - - public byte[] getPrivateKey() { - if (privateKey == null) - return null; - else - return privateKey.clone(); - } - - public void setPublicKey(byte[] encoded) { - if (encoded == null) - publicKey = null; - else - publicKey = encoded.clone(); - } - - public byte[] getPublicKey() { - if (publicKey == null) - return null; - else - return publicKey.clone(); - } - - public void setEncrypted(boolean encrypted) { - this.encrypted = encrypted; - } - - public boolean isEncrypted() { - return encrypted; - } - - public void setStartup(boolean startup) { - this.startup = startup; - } - - public boolean isStartup() { - return startup; - } - - public void setConfirmUse(boolean confirmUse) { - this.confirmUse = confirmUse; - } - - public boolean isConfirmUse() { - return confirmUse; - } - - public void setLifetime(int lifetime) { - this.lifetime = lifetime; - } - - public int getLifetime() { - return lifetime; - } - - public void setUnlocked(boolean unlocked) { - this.unlocked = unlocked; - } - - public boolean isUnlocked() { - return unlocked; - } - - public void setUnlockedPrivate(Object unlockedPrivate) { - this.unlockedPrivate = unlockedPrivate; - } - - public Object getUnlockedPrivate() { - return unlockedPrivate; - } - - public String getDescription() { - if (description == null) { - final StringBuilder sb = new StringBuilder(); - try { - final PublicKey pubKey = PubkeyUtils.decodePublic(privateKey, type); - if (PubkeyDatabase.KEY_TYPE_RSA.equals(type)) { - int bits = ((RSAPublicKey) pubKey).getModulus().bitLength(); - sb.append("RSA "); - sb.append(bits); - sb.append("-bit"); - } else if (PubkeyDatabase.KEY_TYPE_DSA.equals(type)) { - sb.append("DSA 1024-bit"); - } else if (PubkeyDatabase.KEY_TYPE_EC.equals(type)) { - int bits = ((ECPublicKey) pubKey).getParams().getCurve().getField() - .getFieldSize(); - sb.append("EC "); - sb.append(bits); - sb.append("-bit"); - } else { - sb.append("Unknown Key Type"); - } - } catch (NoSuchAlgorithmException e) { - sb.append("Unknown Key Type"); - } catch (InvalidKeySpecException e) { - sb.append("Unknown Key Type"); - } - - if (encrypted) - sb.append(" (encrypted)"); - - description = sb.toString(); - } - return description; - } - - /* (non-Javadoc) - * @see org.connectbot.bean.AbstractBean#getValues() - */ - @Override - public ContentValues getValues() { - ContentValues values = new ContentValues(); - - values.put(PubkeyDatabase.FIELD_PUBKEY_NICKNAME, nickname); - values.put(PubkeyDatabase.FIELD_PUBKEY_TYPE, type); - values.put(PubkeyDatabase.FIELD_PUBKEY_PRIVATE, privateKey); - values.put(PubkeyDatabase.FIELD_PUBKEY_PUBLIC, publicKey); - values.put(PubkeyDatabase.FIELD_PUBKEY_ENCRYPTED, encrypted ? 1 : 0); - values.put(PubkeyDatabase.FIELD_PUBKEY_STARTUP, startup ? 1 : 0); - values.put(PubkeyDatabase.FIELD_PUBKEY_CONFIRMUSE, confirmUse ? 1 : 0); - values.put(PubkeyDatabase.FIELD_PUBKEY_LIFETIME, lifetime); - - return values; - } - - public boolean changePassword(String oldPassword, String newPassword) throws Exception { - PrivateKey priv; - - try { - priv = PubkeyUtils.decodePrivate(getPrivateKey(), getType(), oldPassword); - } catch (Exception e) { - return false; - } - - setPrivateKey(PubkeyUtils.getEncodedPrivate(priv, newPassword)); - setEncrypted(newPassword.length() > 0); - - return true; - } -} diff --git a/src/org/connectbot/bean/SelectionArea.java b/src/org/connectbot/bean/SelectionArea.java deleted file mode 100644 index 4e6207d..0000000 --- a/src/org/connectbot/bean/SelectionArea.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.bean; - -import de.mud.terminal.VDUBuffer; - -/** - * @author Kenny Root - * Keep track of a selection area for the terminal copying mechanism. - * If the orientation is flipped one way, swap the bottom and top or - * left and right to keep it in the correct orientation. - */ -public class SelectionArea { - private int top; - private int bottom; - private int left; - private int right; - private int maxColumns; - private int maxRows; - private boolean selectingOrigin; - - public SelectionArea() { - reset(); - } - - public final void reset() { - top = left = bottom = right = 0; - selectingOrigin = true; - } - - /** - * @param columns - * @param rows - */ - public void setBounds(int columns, int rows) { - maxColumns = columns - 1; - maxRows = rows - 1; - } - - private int checkBounds(int value, int max) { - if (value < 0) - return 0; - else if (value > max) - return max; - else - return value; - } - - public boolean isSelectingOrigin() { - return selectingOrigin; - } - - public void finishSelectingOrigin() { - selectingOrigin = false; - } - - public void decrementRow() { - if (selectingOrigin) - setTop(top - 1); - else - setBottom(bottom - 1); - } - - public void incrementRow() { - if (selectingOrigin) - setTop(top + 1); - else - setBottom(bottom + 1); - } - - public void setRow(int row) { - if (selectingOrigin) - setTop(row); - else - setBottom(row); - } - - private void setTop(int top) { - this.top = bottom = checkBounds(top, maxRows); - } - - public int getTop() { - return Math.min(top, bottom); - } - - private void setBottom(int bottom) { - this.bottom = checkBounds(bottom, maxRows); - } - - public int getBottom() { - return Math.max(top, bottom); - } - - public void decrementColumn() { - if (selectingOrigin) - setLeft(left - 1); - else - setRight(right - 1); - } - - public void incrementColumn() { - if (selectingOrigin) - setLeft(left + 1); - else - setRight(right + 1); - } - - public void setColumn(int column) { - if (selectingOrigin) - setLeft(column); - else - setRight(column); - } - - private void setLeft(int left) { - this.left = right = checkBounds(left, maxColumns); - } - - public int getLeft() { - return Math.min(left, right); - } - - private void setRight(int right) { - this.right = checkBounds(right, maxColumns); - } - - public int getRight() { - return Math.max(left, right); - } - - public String copyFrom(VDUBuffer vb) { - int size = (getRight() - getLeft() + 1) * (getBottom() - getTop() + 1); - - StringBuffer buffer = new StringBuffer(size); - - for(int y = getTop(); y <= getBottom(); y++) { - int lastNonSpace = buffer.length(); - - for (int x = getLeft(); x <= getRight(); x++) { - // only copy printable chars - char c = vb.getChar(x, y); - - if (!Character.isDefined(c) || - (Character.isISOControl(c) && c != '\t')) - c = ' '; - - if (c != ' ') - lastNonSpace = buffer.length(); - - buffer.append(c); - } - - // Don't leave a bunch of spaces in our copy buffer. - if (buffer.length() > lastNonSpace) - buffer.delete(lastNonSpace + 1, buffer.length()); - - if (y != bottom) - buffer.append("\n"); - } - - return buffer.toString(); - } - - @Override - public String toString() { - StringBuilder buffer = new StringBuilder(); - - buffer.append("SelectionArea[top="); - buffer.append(top); - buffer.append(", bottom="); - buffer.append(bottom); - buffer.append(", left="); - buffer.append(left); - buffer.append(", right="); - buffer.append(right); - buffer.append(", maxColumns="); - buffer.append(maxColumns); - buffer.append(", maxRows="); - buffer.append(maxRows); - buffer.append(", isSelectingOrigin="); - buffer.append(isSelectingOrigin()); - buffer.append("]"); - - return buffer.toString(); - } -} diff --git a/src/org/connectbot/service/BackupAgent.java b/src/org/connectbot/service/BackupAgent.java deleted file mode 100644 index 1e3bd81..0000000 --- a/src/org/connectbot/service/BackupAgent.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2010 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -import java.io.IOException; - -import org.connectbot.util.HostDatabase; -import org.connectbot.util.PreferenceConstants; -import org.connectbot.util.PubkeyDatabase; - -import android.app.backup.BackupAgentHelper; -import android.app.backup.BackupDataInput; -import android.app.backup.BackupDataOutput; -import android.app.backup.FileBackupHelper; -import android.app.backup.SharedPreferencesBackupHelper; -import android.os.ParcelFileDescriptor; -import android.util.Log; - -/** - * @author kroot - * - */ -public class BackupAgent extends BackupAgentHelper { - @Override - public void onCreate() { - Log.d("ConnectBot.BackupAgent", "onCreate called"); - - SharedPreferencesBackupHelper prefs = new SharedPreferencesBackupHelper(this, getPackageName() + "_preferences"); - addHelper(PreferenceConstants.BACKUP_PREF_KEY, prefs); - - FileBackupHelper hosts = new FileBackupHelper(this, "../databases/" + HostDatabase.DB_NAME); - addHelper(HostDatabase.DB_NAME, hosts); - - FileBackupHelper pubkeys = new FileBackupHelper(this, "../databases/" + PubkeyDatabase.DB_NAME); - addHelper(PubkeyDatabase.DB_NAME, pubkeys); - - } - - @Override - public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, - ParcelFileDescriptor newState) throws IOException { - synchronized (HostDatabase.dbLock) { - super.onBackup(oldState, data, newState); - } - } - - @Override - public void onRestore(BackupDataInput data, int appVersionCode, - ParcelFileDescriptor newState) throws IOException { - Log.d("ConnectBot.BackupAgent", "onRestore called"); - - synchronized (HostDatabase.dbLock) { - Log.d("ConnectBot.BackupAgent", "onRestore in-lock"); - - super.onRestore(data, appVersionCode, newState); - } - } -} diff --git a/src/org/connectbot/service/BackupWrapper.java b/src/org/connectbot/service/BackupWrapper.java deleted file mode 100644 index bfc7535..0000000 --- a/src/org/connectbot/service/BackupWrapper.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2010 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -import org.connectbot.util.PreferenceConstants; - -import android.app.backup.BackupManager; -import android.content.Context; - -/** - * @author kroot - * - */ -public abstract class BackupWrapper { - public static BackupWrapper getInstance() { - if (PreferenceConstants.PRE_FROYO) - return PreFroyo.Holder.sInstance; - else - return FroyoAndBeyond.Holder.sInstance; - } - - public abstract void onDataChanged(Context context); - - private static class PreFroyo extends BackupWrapper { - private static class Holder { - private static final PreFroyo sInstance = new PreFroyo(); - } - - @Override - public void onDataChanged(Context context) { - // do nothing for now - } - } - - private static class FroyoAndBeyond extends BackupWrapper { - private static class Holder { - private static final FroyoAndBeyond sInstance = new FroyoAndBeyond(); - } - - private static BackupManager mBackupManager; - - @Override - public void onDataChanged(Context context) { - checkBackupManager(context); - if (mBackupManager != null) { - mBackupManager.dataChanged(); - } - } - - private void checkBackupManager(Context context) { - if (mBackupManager == null) { - mBackupManager = new BackupManager(context); - } - } - } -} diff --git a/src/org/connectbot/service/BridgeDisconnectedListener.java b/src/org/connectbot/service/BridgeDisconnectedListener.java deleted file mode 100644 index 21c41d1..0000000 --- a/src/org/connectbot/service/BridgeDisconnectedListener.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -public interface BridgeDisconnectedListener { - public void onDisconnected(TerminalBridge bridge); -} diff --git a/src/org/connectbot/service/ConnectionNotifier.java b/src/org/connectbot/service/ConnectionNotifier.java deleted file mode 100644 index d276761..0000000 --- a/src/org/connectbot/service/ConnectionNotifier.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2010 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import org.connectbot.ConsoleActivity; -import org.connectbot.R; -import org.connectbot.bean.HostBean; -import org.connectbot.util.HostDatabase; -import org.connectbot.util.PreferenceConstants; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.graphics.Color; - -/** - * @author Kenny Root - * - * Based on the concept from jasta's blog post. - */ -public abstract class ConnectionNotifier { - private static final int ONLINE_NOTIFICATION = 1; - private static final int ACTIVITY_NOTIFICATION = 2; - - public static ConnectionNotifier getInstance() { - if (PreferenceConstants.PRE_ECLAIR) - return PreEclair.Holder.sInstance; - else - return EclairAndBeyond.Holder.sInstance; - } - - protected NotificationManager getNotificationManager(Context context) { - return (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); - } - - protected Notification newNotification(Context context) { - Notification notification = new Notification(); - notification.icon = R.drawable.notification_icon; - notification.when = System.currentTimeMillis(); - - return notification; - } - - protected Notification newActivityNotification(Context context, HostBean host) { - Notification notification = newNotification(context); - - Resources res = context.getResources(); - - String contentText = res.getString( - R.string.notification_text, host.getNickname()); - - Intent notificationIntent = new Intent(context, ConsoleActivity.class); - notificationIntent.setAction("android.intent.action.VIEW"); - notificationIntent.setData(host.getUri()); - - PendingIntent contentIntent = PendingIntent.getActivity(context, 0, - notificationIntent, 0); - - notification.setLatestEventInfo(context, res.getString(R.string.app_name), contentText, contentIntent); - - notification.flags = Notification.FLAG_AUTO_CANCEL; - - notification.flags |= Notification.DEFAULT_LIGHTS; - if (HostDatabase.COLOR_RED.equals(host.getColor())) - notification.ledARGB = Color.RED; - else if (HostDatabase.COLOR_GREEN.equals(host.getColor())) - notification.ledARGB = Color.GREEN; - else if (HostDatabase.COLOR_BLUE.equals(host.getColor())) - notification.ledARGB = Color.BLUE; - else - notification.ledARGB = Color.WHITE; - notification.ledOnMS = 300; - notification.ledOffMS = 1000; - notification.flags |= Notification.FLAG_SHOW_LIGHTS; - - return notification; - } - - protected Notification newRunningNotification(Context context) { - Notification notification = newNotification(context); - - notification.flags = Notification.FLAG_ONGOING_EVENT - | Notification.FLAG_NO_CLEAR; - notification.when = 0; - - notification.contentIntent = PendingIntent.getActivity(context, - ONLINE_NOTIFICATION, - new Intent(context, ConsoleActivity.class), 0); - - Resources res = context.getResources(); - - notification.setLatestEventInfo(context, - res.getString(R.string.app_name), - res.getString(R.string.app_is_running), - notification.contentIntent); - - return notification; - } - - public void showActivityNotification(Service context, HostBean host) { - getNotificationManager(context).notify(ACTIVITY_NOTIFICATION, newActivityNotification(context, host)); - } - - public void hideActivityNotification(Service context) { - getNotificationManager(context).cancel(ACTIVITY_NOTIFICATION); - } - - public abstract void showRunningNotification(Service context); - public abstract void hideRunningNotification(Service context); - - private static class PreEclair extends ConnectionNotifier { - private static final Class<?>[] setForegroundSignature = new Class[] {boolean.class}; - private Method setForeground = null; - - private static class Holder { - private static final PreEclair sInstance = new PreEclair(); - } - - public PreEclair() { - try { - setForeground = Service.class.getMethod("setForeground", setForegroundSignature); - } catch (Exception e) { - } - } - - @Override - public void showRunningNotification(Service context) { - if (setForeground != null) { - Object[] setForegroundArgs = new Object[1]; - setForegroundArgs[0] = Boolean.TRUE; - try { - setForeground.invoke(context, setForegroundArgs); - } catch (InvocationTargetException e) { - } catch (IllegalAccessException e) { - } - getNotificationManager(context).notify(ONLINE_NOTIFICATION, newRunningNotification(context)); - } - } - - @Override - public void hideRunningNotification(Service context) { - if (setForeground != null) { - Object[] setForegroundArgs = new Object[1]; - setForegroundArgs[0] = Boolean.FALSE; - try { - setForeground.invoke(context, setForegroundArgs); - } catch (InvocationTargetException e) { - } catch (IllegalAccessException e) { - } - getNotificationManager(context).cancel(ONLINE_NOTIFICATION); - } - } - } - - private static class EclairAndBeyond extends ConnectionNotifier { - private static class Holder { - private static final EclairAndBeyond sInstance = new EclairAndBeyond(); - } - - @Override - public void showRunningNotification(Service context) { - context.startForeground(ONLINE_NOTIFICATION, newRunningNotification(context)); - } - - @Override - public void hideRunningNotification(Service context) { - context.stopForeground(true); - } - } -} diff --git a/src/org/connectbot/service/ConnectivityReceiver.java b/src/org/connectbot/service/ConnectivityReceiver.java deleted file mode 100644 index 3248a2a..0000000 --- a/src/org/connectbot/service/ConnectivityReceiver.java +++ /dev/null @@ -1,154 +0,0 @@ -/** - * - */ -package org.connectbot.service; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.NetworkInfo.State; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.WifiLock; -import android.util.Log; - -/** - * @author kroot - * - */ -public class ConnectivityReceiver extends BroadcastReceiver { - private static final String TAG = "ConnectBot.ConnectivityManager"; - - private boolean mIsConnected = false; - - final private TerminalManager mTerminalManager; - - final private WifiLock mWifiLock; - - private int mNetworkRef = 0; - - private boolean mLockingWifi; - - private Object[] mLock = new Object[0]; - - public ConnectivityReceiver(TerminalManager manager, boolean lockingWifi) { - mTerminalManager = manager; - - final ConnectivityManager cm = - (ConnectivityManager) manager.getSystemService(Context.CONNECTIVITY_SERVICE); - - final WifiManager wm = (WifiManager) manager.getSystemService(Context.WIFI_SERVICE); - mWifiLock = wm.createWifiLock(TAG); - - final NetworkInfo info = cm.getActiveNetworkInfo(); - if (info != null) { - mIsConnected = (info.getState() == State.CONNECTED); - } - - mLockingWifi = lockingWifi; - - final IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - manager.registerReceiver(this, filter); - } - - /* (non-Javadoc) - * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent) - */ - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - - if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - Log.w(TAG, "onReceived() called: " + intent); - return; - } - - boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); - boolean isFailover = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false); - - Log.d(TAG, "onReceived() called; noConnectivity? " + noConnectivity + "; isFailover? " + isFailover); - - if (noConnectivity && !isFailover && mIsConnected) { - mIsConnected = false; - mTerminalManager.onConnectivityLost(); - } else if (!mIsConnected) { - NetworkInfo info = (NetworkInfo) intent.getExtras() - .get(ConnectivityManager.EXTRA_NETWORK_INFO); - - if (mIsConnected = (info.getState() == State.CONNECTED)) { - mTerminalManager.onConnectivityRestored(); - } - } - } - - /** - * - */ - public void cleanup() { - if (mWifiLock.isHeld()) - mWifiLock.release(); - - mTerminalManager.unregisterReceiver(this); - } - - /** - * Increase the number of things using the network. Acquire a Wi-Fi lock - * if necessary. - */ - public void incRef() { - synchronized (mLock) { - mNetworkRef += 1; - - acquireWifiLockIfNecessaryLocked(); - } - } - - /** - * Decrease the number of things using the network. Release the Wi-Fi lock - * if necessary. - */ - public void decRef() { - synchronized (mLock) { - mNetworkRef -= 1; - - releaseWifiLockIfNecessaryLocked(); - } - } - - /** - * @param mLockingWifi - */ - public void setWantWifiLock(boolean lockingWifi) { - synchronized (mLock) { - mLockingWifi = lockingWifi; - - if (mLockingWifi) { - acquireWifiLockIfNecessaryLocked(); - } else { - releaseWifiLockIfNecessaryLocked(); - } - } - } - - private void acquireWifiLockIfNecessaryLocked() { - if (mLockingWifi && mNetworkRef > 0 && !mWifiLock.isHeld()) { - mWifiLock.acquire(); - } - } - - private void releaseWifiLockIfNecessaryLocked() { - if (mNetworkRef == 0 && mWifiLock.isHeld()) { - mWifiLock.release(); - } - } - - /** - * @return whether we're connected to a network - */ - public boolean isConnected() { - return mIsConnected; - } -} diff --git a/src/org/connectbot/service/FontSizeChangedListener.java b/src/org/connectbot/service/FontSizeChangedListener.java deleted file mode 100644 index eb1c33d..0000000 --- a/src/org/connectbot/service/FontSizeChangedListener.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -/** - * @author Kenny Root - * - */ -public interface FontSizeChangedListener { - - /** - * @param size - * new font size - */ - void onFontSizeChanged(float size); -} diff --git a/src/org/connectbot/service/KeyEventUtil.java b/src/org/connectbot/service/KeyEventUtil.java deleted file mode 100644 index 8ad645d..0000000 --- a/src/org/connectbot/service/KeyEventUtil.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2014 Torne Wuff - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.connectbot.service; - -import android.view.KeyEvent; - -public class KeyEventUtil { - static final char CONTROL_LIMIT = ' '; - static final char PRINTABLE_LIMIT = '\u007e'; - static final char[] HEX_DIGITS = new char[] { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - - static String printableRepresentation(String source) { - if (source == null) - return null; - - final StringBuilder sb = new StringBuilder(); - final int limit = source.length(); - char[] hexbuf = null; - int pointer = 0; - - sb.append('"'); - while (pointer < limit) { - int ch = source.charAt(pointer++); - switch (ch) { - case '\0': - sb.append("\\0"); - break; - case '\t': - sb.append("\\t"); - break; - case '\n': - sb.append("\\n"); - break; - case '\r': - sb.append("\\r"); - break; - case '\"': - sb.append("\\\""); - break; - case '\\': - sb.append("\\\\"); - break; - default: - if (CONTROL_LIMIT <= ch && ch <= PRINTABLE_LIMIT) { - sb.append((char) ch); - } else { - sb.append("\\u"); - if (hexbuf == null) - hexbuf = new char[4]; - for (int offs = 4; offs > 0; ) { - hexbuf[--offs] = HEX_DIGITS[ch & 0xf]; - ch >>>= 4; - } - sb.append(hexbuf, 0, 4); - } - } - } - return sb.append('"').toString(); - } - - public static String describeKeyEvent(int keyCode, KeyEvent event) { - StringBuilder d = new StringBuilder(); - d.append("keyCode=").append(keyCode); - d.append(", keyCodeToString=").append(KeyEvent.keyCodeToString(keyCode)); - d.append(", event.toString=").append(event.toString()); - d.append(", action=").append(event.getAction()); - d.append(", characters=").append(printableRepresentation(event.getCharacters())); - d.append(", deviceId=").append(event.getDeviceId()); - d.append(", displayLabel=").append((int) event.getDisplayLabel()); - d.append(", flags=0x").append(Integer.toHexString(event.getFlags())); - d.append(", printingKey=").append(event.isPrintingKey()); - d.append(", keyCode=").append(event.getKeyCode()); - d.append(", metaState=0x").append(Integer.toHexString(event.getMetaState())); - d.append(", modifiers=0x").append(Integer.toHexString(event.getModifiers())); - d.append(", number=").append((int) event.getNumber()); - d.append(", scanCode=").append(event.getScanCode()); - d.append(", source=").append(event.getSource()); - d.append(", unicodeChar=").append(event.getUnicodeChar()); - return d.toString(); - } -} diff --git a/src/org/connectbot/service/PromptHelper.java b/src/org/connectbot/service/PromptHelper.java deleted file mode 100644 index f0a37be..0000000 --- a/src/org/connectbot/service/PromptHelper.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -import java.util.concurrent.Semaphore; - -import android.os.Handler; -import android.os.Message; - -/** - * Helps provide a relay for prompts and responses between a possible user - * interface and some underlying service. - * - * @author jsharkey - */ -public class PromptHelper { - private final Object tag; - - private Handler handler = null; - - private Semaphore promptToken; - private Semaphore promptResponse; - - public String promptInstructions = null; - public String promptHint = null; - public Object promptRequested = null; - - private Object response = null; - - public PromptHelper(Object tag) { - this.tag = tag; - - // Threads must acquire this before they can send a prompt. - promptToken = new Semaphore(1); - - // Responses will release this semaphore. - promptResponse = new Semaphore(0); - } - - - /** - * Register a user interface handler, if available. - */ - public void setHandler(Handler handler) { - this.handler = handler; - } - - /** - * Set an incoming value from an above user interface. Will automatically - * notify any waiting requests. - */ - public void setResponse(Object value) { - response = value; - promptRequested = null; - promptInstructions = null; - promptHint = null; - promptResponse.release(); - } - - /** - * Return the internal response value just before erasing and returning it. - */ - protected Object popResponse() { - Object value = response; - response = null; - return value; - } - - - /** - * Request a prompt response from parent. This is a blocking call until user - * interface returns a value. - * Only one thread can call this at a time. cancelPrompt() will force this to - * immediately return. - */ - private Object requestPrompt(String instructions, String hint, Object type) throws InterruptedException { - Object response = null; - - promptToken.acquire(); - - try { - promptInstructions = instructions; - promptHint = hint; - promptRequested = type; - - // notify any parent watching for live events - if (handler != null) - Message.obtain(handler, -1, tag).sendToTarget(); - - // acquire lock until user passes back value - promptResponse.acquire(); - - response = popResponse(); - } finally { - promptToken.release(); - } - - return response; - } - - /** - * Request a string response from parent. This is a blocking call until user - * interface returns a value. - * @param hint prompt hint for user to answer - * @return string user has entered - */ - public String requestStringPrompt(String instructions, String hint) { - String value = null; - try { - value = (String)this.requestPrompt(instructions, hint, String.class); - } catch(Exception e) { - } - return value; - } - - /** - * Request a boolean response from parent. This is a blocking call until user - * interface returns a value. - * @param hint prompt hint for user to answer - * @return choice user has made (yes/no) - */ - public Boolean requestBooleanPrompt(String instructions, String hint) { - Boolean value = null; - try { - value = (Boolean)this.requestPrompt(instructions, hint, Boolean.class); - } catch(Exception e) { - } - return value; - } - - /** - * Cancel an in-progress prompt. - */ - public void cancelPrompt() { - if (!promptToken.tryAcquire()) { - // A thread has the token, so try to interrupt it - response = null; - promptResponse.release(); - } else { - // No threads have acquired the token - promptToken.release(); - } - } -} diff --git a/src/org/connectbot/service/Relay.java b/src/org/connectbot/service/Relay.java deleted file mode 100644 index 36672ec..0000000 --- a/src/org/connectbot/service/Relay.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; - -import org.apache.harmony.niochar.charset.additional.IBM437; -import org.connectbot.transport.AbsTransport; -import org.connectbot.util.EastAsianWidth; - -import android.util.Log; -import de.mud.terminal.vt320; - -/** - * @author Kenny Root - */ -public class Relay implements Runnable { - private static final String TAG = "ConnectBot.Relay"; - - private static final int BUFFER_SIZE = 4096; - - private TerminalBridge bridge; - - private Charset currentCharset; - private CharsetDecoder decoder; - - private AbsTransport transport; - - private vt320 buffer; - - private ByteBuffer byteBuffer; - private CharBuffer charBuffer; - - private byte[] byteArray; - private char[] charArray; - - public Relay(TerminalBridge bridge, AbsTransport transport, vt320 buffer, String encoding) { - setCharset(encoding); - this.bridge = bridge; - this.transport = transport; - this.buffer = buffer; - } - - public void setCharset(String encoding) { - Log.d("ConnectBot.Relay", "changing charset to " + encoding); - Charset charset; - if (encoding.equals("CP437")) - charset = new IBM437("IBM437", - new String[] { "IBM437", "CP437" }); - else - charset = Charset.forName(encoding); - - if (charset == currentCharset || charset == null) - return; - - CharsetDecoder newCd = charset.newDecoder(); - newCd.onUnmappableCharacter(CodingErrorAction.REPLACE); - newCd.onMalformedInput(CodingErrorAction.REPLACE); - - currentCharset = charset; - synchronized (this) { - decoder = newCd; - } - } - - public Charset getCharset() { - return currentCharset; - } - - public void run() { - byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); - charBuffer = CharBuffer.allocate(BUFFER_SIZE); - - /* for East Asian character widths */ - byte[] wideAttribute = new byte[BUFFER_SIZE]; - - byteArray = byteBuffer.array(); - charArray = charBuffer.array(); - - CoderResult result; - - int bytesRead = 0; - byteBuffer.limit(0); - int bytesToRead; - int offset; - int charWidth; - - EastAsianWidth measurer = EastAsianWidth.getInstance(); - - try { - while (true) { - charWidth = bridge.charWidth; - bytesToRead = byteBuffer.capacity() - byteBuffer.limit(); - offset = byteBuffer.arrayOffset() + byteBuffer.limit(); - bytesRead = transport.read(byteArray, offset, bytesToRead); - - if (bytesRead > 0) { - byteBuffer.limit(byteBuffer.limit() + bytesRead); - - synchronized (this) { - result = decoder.decode(byteBuffer, charBuffer, false); - } - - if (result.isUnderflow() && - byteBuffer.limit() == byteBuffer.capacity()) { - byteBuffer.compact(); - byteBuffer.limit(byteBuffer.position()); - byteBuffer.position(0); - } - - offset = charBuffer.position(); - - measurer.measure(charArray, 0, offset, wideAttribute, bridge.defaultPaint, charWidth); - buffer.putString(charArray, wideAttribute, 0, charBuffer.position()); - bridge.propagateConsoleText(charArray, charBuffer.position()); - charBuffer.clear(); - bridge.redraw(); - } - } - } catch (IOException e) { - Log.e(TAG, "Problem while handling incoming data in relay thread", e); - } - } -} diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java deleted file mode 100644 index 6b87b74..0000000 --- a/src/org/connectbot/service/TerminalBridge.java +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.LinkedList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.connectbot.R; -import org.connectbot.TerminalView; -import org.connectbot.bean.HostBean; -import org.connectbot.bean.PortForwardBean; -import org.connectbot.bean.SelectionArea; -import org.connectbot.transport.AbsTransport; -import org.connectbot.transport.TransportFactory; -import org.connectbot.util.HostDatabase; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.FontMetrics; -import android.graphics.Typeface; -import android.text.ClipboardManager; -import android.util.Log; -import de.mud.terminal.VDUBuffer; -import de.mud.terminal.VDUDisplay; -import de.mud.terminal.vt320; - - -/** - * Provides a bridge between a MUD terminal buffer and a possible TerminalView. - * This separation allows us to keep the TerminalBridge running in a background - * service. A TerminalView shares down a bitmap that we can use for rendering - * when available. - * - * This class also provides SSH hostkey verification prompting, and password - * prompting. - */ -@SuppressWarnings("deprecation") // for ClipboardManager -public class TerminalBridge implements VDUDisplay { - public final static String TAG = "ConnectBot.TerminalBridge"; - - public final static int DEFAULT_FONT_SIZE = 10; - private final static int FONT_SIZE_STEP = 2; - - public Integer[] color; - - public int defaultFg = HostDatabase.DEFAULT_FG_COLOR; - public int defaultBg = HostDatabase.DEFAULT_BG_COLOR; - - protected final TerminalManager manager; - - public HostBean host; - - /* package */ AbsTransport transport; - - final Paint defaultPaint; - - private Relay relay; - - private final String emulation; - private final int scrollback; - - public Bitmap bitmap = null; - public VDUBuffer buffer = null; - - private TerminalView parent = null; - private final Canvas canvas = new Canvas(); - - private boolean disconnected = false; - private boolean awaitingClose = false; - - private boolean forcedSize = false; - private int columns; - private int rows; - - /* package */ final TerminalKeyListener keyListener; - - private boolean selectingForCopy = false; - private final SelectionArea selectionArea; - - // TODO add support for the new clipboard API - private ClipboardManager clipboard; - - public int charWidth = -1; - public int charHeight = -1; - private int charTop = -1; - - private float fontSize = -1; - - private final List<FontSizeChangedListener> fontSizeChangedListeners; - - private final List<String> localOutput; - - /** - * Flag indicating if we should perform a full-screen redraw during our next - * rendering pass. - */ - private boolean fullRedraw = false; - - public PromptHelper promptHelper; - - protected BridgeDisconnectedListener disconnectListener = null; - - /** - * Create a new terminal bridge suitable for unit testing. - */ - public TerminalBridge() { - buffer = new vt320() { - @Override - public void write(byte[] b) {} - @Override - public void write(int b) {} - @Override - public void sendTelnetCommand(byte cmd) {} - @Override - public void setWindowSize(int c, int r) {} - @Override - public void debug(String s) {} - }; - - emulation = null; - manager = null; - - defaultPaint = new Paint(); - - selectionArea = new SelectionArea(); - scrollback = 1; - - localOutput = new LinkedList<String>(); - - fontSizeChangedListeners = new LinkedList<FontSizeChangedListener>(); - - transport = null; - - keyListener = new TerminalKeyListener(manager, this, buffer, null); - } - - /** - * Create new terminal bridge with following parameters. We will immediately - * launch thread to start SSH connection and handle any hostkey verification - * and password authentication. - */ - public TerminalBridge(final TerminalManager manager, final HostBean host) throws IOException { - this.manager = manager; - this.host = host; - - emulation = manager.getEmulation(); - scrollback = manager.getScrollback(); - - // create prompt helper to relay password and hostkey requests up to gui - promptHelper = new PromptHelper(this); - - // create our default paint - defaultPaint = new Paint(); - defaultPaint.setAntiAlias(true); - defaultPaint.setTypeface(Typeface.MONOSPACE); - defaultPaint.setFakeBoldText(true); // more readable? - - localOutput = new LinkedList<String>(); - - fontSizeChangedListeners = new LinkedList<FontSizeChangedListener>(); - - int hostFontSize = host.getFontSize(); - if (hostFontSize <= 0) - hostFontSize = DEFAULT_FONT_SIZE; - setFontSize(hostFontSize); - - // create terminal buffer and handle outgoing data - // this is probably status reply information - buffer = new vt320() { - @Override - public void debug(String s) { - Log.d(TAG, s); - } - - @Override - public void write(byte[] b) { - try { - if (b != null && transport != null) - transport.write(b); - } catch (IOException e) { - Log.e(TAG, "Problem writing outgoing data in vt320() thread", e); - } - } - - @Override - public void write(int b) { - try { - if (transport != null) - transport.write(b); - } catch (IOException e) { - Log.e(TAG, "Problem writing outgoing data in vt320() thread", e); - } - } - - // We don't use telnet sequences. - @Override - public void sendTelnetCommand(byte cmd) { - } - - // We don't want remote to resize our window. - @Override - public void setWindowSize(int c, int r) { - } - - @Override - public void beep() { - if (parent.isShown()) - manager.playBeep(); - else - manager.sendActivityNotification(host); - } - }; - - // Don't keep any scrollback if a session is not being opened. - if (host.getWantSession()) - buffer.setBufferSize(scrollback); - else - buffer.setBufferSize(0); - - resetColors(); - buffer.setDisplay(this); - - selectionArea = new SelectionArea(); - - keyListener = new TerminalKeyListener(manager, this, buffer, host.getEncoding()); - } - - public PromptHelper getPromptHelper() { - return promptHelper; - } - - /** - * Spawn thread to open connection and start login process. - */ - protected void startConnection() { - transport = TransportFactory.getTransport(host.getProtocol()); - transport.setBridge(this); - transport.setManager(manager); - transport.setHost(host); - - // TODO make this more abstract so we don't litter on AbsTransport - transport.setCompression(host.getCompression()); - transport.setUseAuthAgent(host.getUseAuthAgent()); - transport.setEmulation(emulation); - - if (transport.canForwardPorts()) { - for (PortForwardBean portForward : manager.hostdb.getPortForwardsForHost(host)) - transport.addPortForward(portForward); - } - - outputLine(manager.res.getString(R.string.terminal_connecting, host.getHostname(), host.getPort(), host.getProtocol())); - - Thread connectionThread = new Thread(new Runnable() { - public void run() { - transport.connect(); - } - }); - connectionThread.setName("Connection"); - connectionThread.setDaemon(true); - connectionThread.start(); - } - - /** - * Handle challenges from keyboard-interactive authentication mode. - */ - public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) { - String[] responses = new String[numPrompts]; - for(int i = 0; i < numPrompts; i++) { - // request response from user for each prompt - responses[i] = promptHelper.requestStringPrompt(instruction, prompt[i]); - } - return responses; - } - - /** - * @return charset in use by bridge - */ - public Charset getCharset() { - return relay.getCharset(); - } - - /** - * Sets the encoding used by the terminal. If the connection is live, - * then the character set is changed for the next read. - * @param encoding the canonical name of the character encoding - */ - public void setCharset(String encoding) { - if (relay != null) - relay.setCharset(encoding); - keyListener.setCharset(encoding); - } - - /** - * Convenience method for writing a line into the underlying MUD buffer. - * Should never be called once the session is established. - */ - public final void outputLine(String line) { - if (transport != null && transport.isSessionOpen()) - Log.e(TAG, "Session established, cannot use outputLine!", new IOException("outputLine call traceback")); - - synchronized (localOutput) { - final String s = line + "\r\n"; - - localOutput.add(s); - - ((vt320) buffer).putString(s); - - // For accessibility - final char[] charArray = s.toCharArray(); - propagateConsoleText(charArray, charArray.length); - } - } - - /** - * Inject a specific string into this terminal. Used for post-login strings - * and pasting clipboard. - */ - public void injectString(final String string) { - if (string == null || string.length() == 0) - return; - - Thread injectStringThread = new Thread(new Runnable() { - public void run() { - try { - transport.write(string.getBytes(host.getEncoding())); - } catch (Exception e) { - Log.e(TAG, "Couldn't inject string to remote host: ", e); - } - } - }); - injectStringThread.setName("InjectString"); - injectStringThread.start(); - } - - /** - * Internal method to request actual PTY terminal once we've finished - * authentication. If called before authenticated, it will just fail. - */ - public void onConnected() { - disconnected = false; - - ((vt320) buffer).reset(); - - // We no longer need our local output. - localOutput.clear(); - - // previously tried vt100 and xterm for emulation modes - // "screen" works the best for color and escape codes - ((vt320) buffer).setAnswerBack(emulation); - - if (HostDatabase.DELKEY_BACKSPACE.equals(host.getDelKey())) - ((vt320) buffer).setBackspace(vt320.DELETE_IS_BACKSPACE); - else - ((vt320) buffer).setBackspace(vt320.DELETE_IS_DEL); - - // create thread to relay incoming connection data to buffer - relay = new Relay(this, transport, (vt320) buffer, host.getEncoding()); - Thread relayThread = new Thread(relay); - relayThread.setDaemon(true); - relayThread.setName("Relay"); - relayThread.start(); - - // force font-size to make sure we resizePTY as needed - setFontSize(fontSize); - - // finally send any post-login string, if requested - injectString(host.getPostLogin()); - } - - /** - * @return whether a session is open or not - */ - public boolean isSessionOpen() { - if (transport != null) - return transport.isSessionOpen(); - return false; - } - - public void setOnDisconnectedListener(BridgeDisconnectedListener disconnectListener) { - this.disconnectListener = disconnectListener; - } - - /** - * Force disconnection of this terminal bridge. - */ - public void dispatchDisconnect(boolean immediate) { - // We don't need to do this multiple times. - synchronized (this) { - if (disconnected && !immediate) - return; - - disconnected = true; - } - - // Cancel any pending prompts. - promptHelper.cancelPrompt(); - - // disconnection request hangs if we havent really connected to a host yet - // temporary fix is to just spawn disconnection into a thread - Thread disconnectThread = new Thread(new Runnable() { - public void run() { - if (transport != null && transport.isConnected()) - transport.close(); - } - }); - disconnectThread.setName("Disconnect"); - disconnectThread.start(); - - if (immediate) { - awaitingClose = true; - if (disconnectListener != null) - disconnectListener.onDisconnected(TerminalBridge.this); - } else { - { - final String line = manager.res.getString(R.string.alert_disconnect_msg); - ((vt320) buffer).putString("\r\n" + line + "\r\n"); - } - if (host.getStayConnected()) { - manager.requestReconnect(this); - return; - } - Thread disconnectPromptThread = new Thread(new Runnable() { - public void run() { - Boolean result = promptHelper.requestBooleanPrompt(null, - manager.res.getString(R.string.prompt_host_disconnected)); - if (result == null || result.booleanValue()) { - awaitingClose = true; - - // Tell the TerminalManager that we can be destroyed now. - if (disconnectListener != null) - disconnectListener.onDisconnected(TerminalBridge.this); - } - } - }); - disconnectPromptThread.setName("DisconnectPrompt"); - disconnectPromptThread.setDaemon(true); - disconnectPromptThread.start(); - } - } - - public void setSelectingForCopy(boolean selectingForCopy) { - this.selectingForCopy = selectingForCopy; - } - - public boolean isSelectingForCopy() { - return selectingForCopy; - } - - public SelectionArea getSelectionArea() { - return selectionArea; - } - - public synchronized void tryKeyVibrate() { - manager.tryKeyVibrate(); - } - - /** - * Request a different font size. Will make call to parentChanged() to make - * sure we resize PTY if needed. - */ - /* package */ final void setFontSize(float size) { - if (size <= 0.0) - return; - - defaultPaint.setTextSize(size); - fontSize = size; - - // read new metrics to get exact pixel dimensions - FontMetrics fm = defaultPaint.getFontMetrics(); - charTop = (int)Math.ceil(fm.top); - - float[] widths = new float[1]; - defaultPaint.getTextWidths("X", widths); - charWidth = (int)Math.ceil(widths[0]); - charHeight = (int)Math.ceil(fm.descent - fm.top); - - // refresh any bitmap with new font size - if(parent != null) - parentChanged(parent); - - for (FontSizeChangedListener ofscl : fontSizeChangedListeners) - ofscl.onFontSizeChanged(size); - - host.setFontSize((int) fontSize); - manager.hostdb.updateFontSize(host); - - forcedSize = false; - } - - /** - * Add an {@link FontSizeChangedListener} to the list of listeners for this - * bridge. - * - * @param listener - * listener to add - */ - public void addFontSizeChangedListener(FontSizeChangedListener listener) { - fontSizeChangedListeners.add(listener); - } - - /** - * Remove an {@link FontSizeChangedListener} from the list of listeners for - * this bridge. - * - * @param listener - */ - public void removeFontSizeChangedListener(FontSizeChangedListener listener) { - fontSizeChangedListeners.remove(listener); - } - - /** - * Something changed in our parent {@link TerminalView}, maybe it's a new - * parent, or maybe it's an updated font size. We should recalculate - * terminal size information and request a PTY resize. - */ - public final synchronized void parentChanged(TerminalView parent) { - if (manager != null && !manager.isResizeAllowed()) { - Log.d(TAG, "Resize is not allowed now"); - return; - } - - this.parent = parent; - final int width = parent.getWidth(); - final int height = parent.getHeight(); - - // Something has gone wrong with our layout; we're 0 width or height! - if (width <= 0 || height <= 0) - return; - - clipboard = (ClipboardManager) parent.getContext().getSystemService(Context.CLIPBOARD_SERVICE); - keyListener.setClipboardManager(clipboard); - - if (!forcedSize) { - // recalculate buffer size - int newColumns, newRows; - - newColumns = width / charWidth; - newRows = height / charHeight; - - // If nothing has changed in the terminal dimensions and not an intial - // draw then don't blow away scroll regions and such. - if (newColumns == columns && newRows == rows) - return; - - columns = newColumns; - rows = newRows; - } - - // reallocate new bitmap if needed - boolean newBitmap = (bitmap == null); - if(bitmap != null) - newBitmap = (bitmap.getWidth() != width || bitmap.getHeight() != height); - - if (newBitmap) { - discardBitmap(); - bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); - canvas.setBitmap(bitmap); - } - - // clear out any old buffer information - defaultPaint.setColor(Color.BLACK); - canvas.drawPaint(defaultPaint); - - // Stroke the border of the terminal if the size is being forced; - if (forcedSize) { - int borderX = (columns * charWidth) + 1; - int borderY = (rows * charHeight) + 1; - - defaultPaint.setColor(Color.GRAY); - defaultPaint.setStrokeWidth(0.0f); - if (width >= borderX) - canvas.drawLine(borderX, 0, borderX, borderY + 1, defaultPaint); - if (height >= borderY) - canvas.drawLine(0, borderY, borderX + 1, borderY, defaultPaint); - } - - try { - // request a terminal pty resize - synchronized (buffer) { - buffer.setScreenSize(columns, rows, true); - } - - if(transport != null) - transport.setDimensions(columns, rows, width, height); - } catch(Exception e) { - Log.e(TAG, "Problem while trying to resize screen or PTY", e); - } - - // redraw local output if we don't have a sesson to receive our resize request - if (transport == null) { - synchronized (localOutput) { - ((vt320) buffer).reset(); - - for (String line : localOutput) - ((vt320) buffer).putString(line); - } - } - - // force full redraw with new buffer size - fullRedraw = true; - redraw(); - - parent.notifyUser(String.format("%d x %d", columns, rows)); - - Log.i(TAG, String.format("parentChanged() now width=%d, height=%d", columns, rows)); - } - - /** - * Somehow our parent {@link TerminalView} was destroyed. Now we don't need - * to redraw anywhere, and we can recycle our internal bitmap. - */ - public synchronized void parentDestroyed() { - parent = null; - discardBitmap(); - } - - private void discardBitmap() { - if (bitmap != null) - bitmap.recycle(); - bitmap = null; - } - - public void setVDUBuffer(VDUBuffer buffer) { - this.buffer = buffer; - } - - public VDUBuffer getVDUBuffer() { - return buffer; - } - - public void propagateConsoleText(char[] rawText, int length) { - if (parent != null) { - parent.propagateConsoleText(rawText, length); - } - } - - public void onDraw() { - int fg, bg; - synchronized (buffer) { - boolean entireDirty = buffer.update[0] || fullRedraw; - boolean isWideCharacter = false; - - // walk through all lines in the buffer - for(int l = 0; l < buffer.height; l++) { - - // check if this line is dirty and needs to be repainted - // also check for entire-buffer dirty flags - if (!entireDirty && !buffer.update[l + 1]) continue; - - // reset dirty flag for this line - buffer.update[l + 1] = false; - - // walk through all characters in this line - for (int c = 0; c < buffer.width; c++) { - int addr = 0; - int currAttr = buffer.charAttributes[buffer.windowBase + l][c]; - - { - int fgcolor = defaultFg; - - // check if foreground color attribute is set - if ((currAttr & VDUBuffer.COLOR_FG) != 0) - fgcolor = ((currAttr & VDUBuffer.COLOR_FG) >> VDUBuffer.COLOR_FG_SHIFT) - 1; - - if (fgcolor < 8 && (currAttr & VDUBuffer.BOLD) != 0) - fg = color[fgcolor + 8]; - else - fg = color[fgcolor]; - } - - // check if background color attribute is set - if ((currAttr & VDUBuffer.COLOR_BG) != 0) - bg = color[((currAttr & VDUBuffer.COLOR_BG) >> VDUBuffer.COLOR_BG_SHIFT) - 1]; - else - bg = color[defaultBg]; - - // support character inversion by swapping background and foreground color - if ((currAttr & VDUBuffer.INVERT) != 0) { - int swapc = bg; - bg = fg; - fg = swapc; - } - - // set underlined attributes if requested - defaultPaint.setUnderlineText((currAttr & VDUBuffer.UNDERLINE) != 0); - - isWideCharacter = (currAttr & VDUBuffer.FULLWIDTH) != 0; - - if (isWideCharacter) - addr++; - else { - // determine the amount of continuous characters with the same settings and print them all at once - while(c + addr < buffer.width - && buffer.charAttributes[buffer.windowBase + l][c + addr] == currAttr) { - addr++; - } - } - - // Save the current clip region - canvas.save(Canvas.CLIP_SAVE_FLAG); - - // clear this dirty area with background color - defaultPaint.setColor(bg); - if (isWideCharacter) { - canvas.clipRect(c * charWidth, - l * charHeight, - (c + 2) * charWidth, - (l + 1) * charHeight); - } else { - canvas.clipRect(c * charWidth, - l * charHeight, - (c + addr) * charWidth, - (l + 1) * charHeight); - } - canvas.drawPaint(defaultPaint); - - // write the text string starting at 'c' for 'addr' number of characters - defaultPaint.setColor(fg); - if((currAttr & VDUBuffer.INVISIBLE) == 0) - canvas.drawText(buffer.charArray[buffer.windowBase + l], c, - addr, c * charWidth, (l * charHeight) - charTop, - defaultPaint); - - // Restore the previous clip region - canvas.restore(); - - // advance to the next text block with different characteristics - c += addr - 1; - if (isWideCharacter) - c++; - } - } - - // reset entire-buffer flags - buffer.update[0] = false; - } - fullRedraw = false; - } - - public void redraw() { - if (parent != null) - parent.postInvalidate(); - } - - // We don't have a scroll bar. - public void updateScrollBar() { - } - - /** - * Resize terminal to fit [rows]x[cols] in screen of size [width]x[height] - * @param rows - * @param cols - * @param width - * @param height - */ - public synchronized void resizeComputed(int cols, int rows, int width, int height) { - float size = 8.0f; - float step = 8.0f; - float limit = 0.125f; - - int direction; - - while ((direction = fontSizeCompare(size, cols, rows, width, height)) < 0) - size += step; - - if (direction == 0) { - Log.d("fontsize", String.format("Found match at %f", size)); - return; - } - - step /= 2.0f; - size -= step; - - while ((direction = fontSizeCompare(size, cols, rows, width, height)) != 0 - && step >= limit) { - step /= 2.0f; - if (direction > 0) { - size -= step; - } else { - size += step; - } - } - - if (direction > 0) - size -= step; - - this.columns = cols; - this.rows = rows; - setFontSize(size); - forcedSize = true; - } - - private int fontSizeCompare(float size, int cols, int rows, int width, int height) { - // read new metrics to get exact pixel dimensions - defaultPaint.setTextSize(size); - FontMetrics fm = defaultPaint.getFontMetrics(); - - float[] widths = new float[1]; - defaultPaint.getTextWidths("X", widths); - int termWidth = (int)widths[0] * cols; - int termHeight = (int)Math.ceil(fm.descent - fm.top) * rows; - - Log.d("fontsize", String.format("font size %f resulted in %d x %d", size, termWidth, termHeight)); - - // Check to see if it fits in resolution specified. - if (termWidth > width || termHeight > height) - return 1; - - if (termWidth == width || termHeight == height) - return 0; - - return -1; - } - - /** - * @return whether underlying transport can forward ports - */ - public boolean canFowardPorts() { - return transport.canForwardPorts(); - } - - /** - * Adds the {@link PortForwardBean} to the list. - * @param portForward the port forward bean to add - * @return true on successful addition - */ - public boolean addPortForward(PortForwardBean portForward) { - return transport.addPortForward(portForward); - } - - /** - * Removes the {@link PortForwardBean} from the list. - * @param portForward the port forward bean to remove - * @return true on successful removal - */ - public boolean removePortForward(PortForwardBean portForward) { - return transport.removePortForward(portForward); - } - - /** - * @return the list of port forwards - */ - public List<PortForwardBean> getPortForwards() { - return transport.getPortForwards(); - } - - /** - * Enables a port forward member. After calling this method, the port forward should - * be operational. - * @param portForward member of our current port forwards list to enable - * @return true on successful port forward setup - */ - public boolean enablePortForward(PortForwardBean portForward) { - if (!transport.isConnected()) { - Log.i(TAG, "Attempt to enable port forward while not connected"); - return false; - } - - return transport.enablePortForward(portForward); - } - - /** - * Disables a port forward member. After calling this method, the port forward should - * be non-functioning. - * @param portForward member of our current port forwards list to enable - * @return true on successful port forward tear-down - */ - public boolean disablePortForward(PortForwardBean portForward) { - if (!transport.isConnected()) { - Log.i(TAG, "Attempt to disable port forward while not connected"); - return false; - } - - return transport.disablePortForward(portForward); - } - - /** - * @return whether the TerminalBridge should close - */ - public boolean isAwaitingClose() { - return awaitingClose; - } - - /** - * @return whether this connection had started and subsequently disconnected - */ - public boolean isDisconnected() { - return disconnected; - } - - /* (non-Javadoc) - * @see de.mud.terminal.VDUDisplay#setColor(byte, byte, byte, byte) - */ - public void setColor(int index, int red, int green, int blue) { - // Don't allow the system colors to be overwritten for now. May violate specs. - if (index < color.length && index >= 16) - color[index] = 0xff000000 | red << 16 | green << 8 | blue; - } - - public final void resetColors() { - int[] defaults = manager.hostdb.getDefaultColorsForScheme(HostDatabase.DEFAULT_COLOR_SCHEME); - defaultFg = defaults[0]; - defaultBg = defaults[1]; - - color = manager.hostdb.getColorsForScheme(HostDatabase.DEFAULT_COLOR_SCHEME); - } - - private static Pattern urlPattern = null; - - /** - * @return - */ - public List<String> scanForURLs() { - List<String> urls = new LinkedList<String>(); - - if (urlPattern == null) { - // based on http://www.ietf.org/rfc/rfc2396.txt - String scheme = "[A-Za-z][-+.0-9A-Za-z]*"; - String unreserved = "[-._~0-9A-Za-z]"; - String pctEncoded = "%[0-9A-Fa-f]{2}"; - String subDelims = "[!$&'()*+,;:=]"; - String userinfo = "(?:" + unreserved + "|" + pctEncoded + "|" + subDelims + "|:)*"; - String h16 = "[0-9A-Fa-f]{1,4}"; - String decOctet = "(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"; - String ipv4address = decOctet + "\\." + decOctet + "\\." + decOctet + "\\." + decOctet; - String ls32 = "(?:" + h16 + ":" + h16 + "|" + ipv4address + ")"; - String ipv6address = "(?:(?:" + h16 + "){6}" + ls32 + ")"; - String ipvfuture = "v[0-9A-Fa-f]+.(?:" + unreserved + "|" + subDelims + "|:)+"; - String ipLiteral = "\\[(?:" + ipv6address + "|" + ipvfuture + ")\\]"; - String regName = "(?:" + unreserved + "|" + pctEncoded + "|" + subDelims + ")*"; - String host = "(?:" + ipLiteral + "|" + ipv4address + "|" + regName + ")"; - String port = "[0-9]*"; - String authority = "(?:" + userinfo + "@)?" + host + "(?::" + port + ")?"; - String pchar = "(?:" + unreserved + "|" + pctEncoded + "|" + subDelims + "|@)"; - String segment = pchar + "*"; - String pathAbempty = "(?:/" + segment + ")*"; - String segmentNz = pchar + "+"; - String pathAbsolute = "/(?:" + segmentNz + "(?:/" + segment + ")*)?"; - String pathRootless = segmentNz + "(?:/" + segment + ")*"; - String hierPart = "(?://" + authority + pathAbempty + "|" + pathAbsolute + "|" + pathRootless + ")"; - String query = "(?:" + pchar + "|/|\\?)*"; - String fragment = "(?:" + pchar + "|/|\\?)*"; - String uriRegex = scheme + ":" + hierPart + "(?:" + query + ")?(?:#" + fragment + ")?"; - urlPattern = Pattern.compile(uriRegex); - } - - char[] visibleBuffer = new char[buffer.height * buffer.width]; - for (int l = 0; l < buffer.height; l++) - System.arraycopy(buffer.charArray[buffer.windowBase + l], 0, - visibleBuffer, l * buffer.width, buffer.width); - - Matcher urlMatcher = urlPattern.matcher(new String(visibleBuffer)); - while (urlMatcher.find()) - urls.add(urlMatcher.group()); - - return urls; - } - - /** - * @return - */ - public boolean isUsingNetwork() { - return transport.usesNetwork(); - } - - /** - * @return - */ - public TerminalKeyListener getKeyHandler() { - return keyListener; - } - - /** - * - */ - public void resetScrollPosition() { - // if we're in scrollback, scroll to bottom of window on input - if (buffer.windowBase != buffer.screenBase) - buffer.setWindowBase(buffer.screenBase); - } - - /** - * - */ - public void increaseFontSize() { - setFontSize(fontSize + FONT_SIZE_STEP); - } - - /** - * - */ - public void decreaseFontSize() { - setFontSize(fontSize - FONT_SIZE_STEP); - } -} diff --git a/src/org/connectbot/service/TerminalKeyListener.java b/src/org/connectbot/service/TerminalKeyListener.java deleted file mode 100644 index 7ff21df..0000000 --- a/src/org/connectbot/service/TerminalKeyListener.java +++ /dev/null @@ -1,558 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2010 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.connectbot.service; - -import java.io.IOException; - -import org.connectbot.TerminalView; -import org.connectbot.bean.SelectionArea; -import org.connectbot.util.PreferenceConstants; - -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.content.res.Configuration; -import android.preference.PreferenceManager; -import android.text.ClipboardManager; -import android.util.Log; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; -import android.view.View; -import android.view.View.OnKeyListener; -import de.mud.terminal.VDUBuffer; -import de.mud.terminal.vt320; - -/** - * @author kenny - * - */ -@SuppressWarnings("deprecation") // for ClipboardManager -public class TerminalKeyListener implements OnKeyListener, OnSharedPreferenceChangeListener { - private static final String TAG = "ConnectBot.OnKeyListener"; - - // Constants for our private tracking of modifier state - public final static int OUR_CTRL_ON = 0x01; - public final static int OUR_CTRL_LOCK = 0x02; - public final static int OUR_ALT_ON = 0x04; - public final static int OUR_ALT_LOCK = 0x08; - public final static int OUR_SHIFT_ON = 0x10; - public final static int OUR_SHIFT_LOCK = 0x20; - private final static int OUR_SLASH = 0x40; - private final static int OUR_TAB = 0x80; - - // All the transient key codes - private final static int OUR_TRANSIENT = OUR_CTRL_ON | OUR_ALT_ON - | OUR_SHIFT_ON | OUR_SLASH | OUR_TAB; - - // The bit mask of momentary and lock states for each - private final static int OUR_CTRL_MASK = OUR_CTRL_ON | OUR_CTRL_LOCK; - private final static int OUR_ALT_MASK = OUR_ALT_ON | OUR_ALT_LOCK; - private final static int OUR_SHIFT_MASK = OUR_SHIFT_ON | OUR_SHIFT_LOCK; - - // backport constants from api level 11 - private final static int KEYCODE_ESCAPE = 111; - private final static int HC_META_CTRL_ON = 0x1000; - private final static int HC_META_CTRL_LEFT_ON = 0x2000; - private final static int HC_META_CTRL_RIGHT_ON = 0x4000; - private final static int HC_META_CTRL_MASK = HC_META_CTRL_ON | HC_META_CTRL_RIGHT_ON - | HC_META_CTRL_LEFT_ON; - private final static int HC_META_ALT_MASK = KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON - | KeyEvent.META_ALT_RIGHT_ON; - - private final TerminalManager manager; - private final TerminalBridge bridge; - private final VDUBuffer buffer; - - private String keymode = null; - private final boolean deviceHasHardKeyboard; - private boolean shiftedNumbersAreFKeysOnHardKeyboard; - private boolean controlNumbersAreFKeysOnSoftKeyboard; - private boolean volumeKeysChangeFontSize; - - private int ourMetaState = 0; - - private int mDeadKey = 0; - - // TODO add support for the new API. - private ClipboardManager clipboard = null; - - private boolean selectingForCopy = false; - private final SelectionArea selectionArea; - - private String encoding; - - private final SharedPreferences prefs; - - public TerminalKeyListener(TerminalManager manager, - TerminalBridge bridge, - VDUBuffer buffer, - String encoding) { - this.manager = manager; - this.bridge = bridge; - this.buffer = buffer; - this.encoding = encoding; - - selectionArea = new SelectionArea(); - - prefs = PreferenceManager.getDefaultSharedPreferences(manager); - prefs.registerOnSharedPreferenceChangeListener(this); - - deviceHasHardKeyboard = (manager.res.getConfiguration().keyboard - == Configuration.KEYBOARD_QWERTY); - - updatePrefs(); - } - - /** - * Handle onKey() events coming down from a {@link TerminalView} above us. - * Modify the keys to make more sense to a host then pass it to the transport. - */ - public boolean onKey(View v, int keyCode, KeyEvent event) { - try { - // skip keys if we aren't connected yet or have been disconnected - if (bridge.isDisconnected() || bridge.transport == null) - return false; - - final boolean interpretAsHardKeyboard = deviceHasHardKeyboard && - !manager.hardKeyboardHidden; - final boolean rightModifiersAreSlashAndTab = interpretAsHardKeyboard && - PreferenceConstants.KEYMODE_RIGHT.equals(keymode); - final boolean leftModifiersAreSlashAndTab = interpretAsHardKeyboard && - PreferenceConstants.KEYMODE_LEFT.equals(keymode); - final boolean shiftedNumbersAreFKeys = shiftedNumbersAreFKeysOnHardKeyboard && - interpretAsHardKeyboard; - final boolean controlNumbersAreFKeys = controlNumbersAreFKeysOnSoftKeyboard && - !interpretAsHardKeyboard; - - // Ignore all key-up events except for the special keys - if (event.getAction() == KeyEvent.ACTION_UP) { - if (rightModifiersAreSlashAndTab) { - if (keyCode == KeyEvent.KEYCODE_ALT_RIGHT - && (ourMetaState & OUR_SLASH) != 0) { - ourMetaState &= ~OUR_TRANSIENT; - bridge.transport.write('/'); - return true; - } else if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT - && (ourMetaState & OUR_TAB) != 0) { - ourMetaState &= ~OUR_TRANSIENT; - bridge.transport.write(0x09); - return true; - } - } else if (leftModifiersAreSlashAndTab) { - if (keyCode == KeyEvent.KEYCODE_ALT_LEFT - && (ourMetaState & OUR_SLASH) != 0) { - ourMetaState &= ~OUR_TRANSIENT; - bridge.transport.write('/'); - return true; - } else if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT - && (ourMetaState & OUR_TAB) != 0) { - ourMetaState &= ~OUR_TRANSIENT; - bridge.transport.write(0x09); - return true; - } - } - - return false; - } - - //Log.i("CBKeyDebug", KeyEventUtil.describeKeyEvent(keyCode, event)); - - if (volumeKeysChangeFontSize) { - if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { - bridge.increaseFontSize(); - return true; - } else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { - bridge.decreaseFontSize(); - return true; - } - } - - bridge.resetScrollPosition(); - - // Handle potentially multi-character IME input. - if (keyCode == KeyEvent.KEYCODE_UNKNOWN && - event.getAction() == KeyEvent.ACTION_MULTIPLE) { - byte[] input = event.getCharacters().getBytes(encoding); - bridge.transport.write(input); - return true; - } - - /// Handle alt and shift keys if they aren't repeating - if (event.getRepeatCount() == 0) { - if (rightModifiersAreSlashAndTab) { - switch (keyCode) { - case KeyEvent.KEYCODE_ALT_RIGHT: - ourMetaState |= OUR_SLASH; - return true; - case KeyEvent.KEYCODE_SHIFT_RIGHT: - ourMetaState |= OUR_TAB; - return true; - case KeyEvent.KEYCODE_SHIFT_LEFT: - metaPress(OUR_SHIFT_ON); - return true; - case KeyEvent.KEYCODE_ALT_LEFT: - metaPress(OUR_ALT_ON); - return true; - } - } else if (leftModifiersAreSlashAndTab) { - switch (keyCode) { - case KeyEvent.KEYCODE_ALT_LEFT: - ourMetaState |= OUR_SLASH; - return true; - case KeyEvent.KEYCODE_SHIFT_LEFT: - ourMetaState |= OUR_TAB; - return true; - case KeyEvent.KEYCODE_SHIFT_RIGHT: - metaPress(OUR_SHIFT_ON); - return true; - case KeyEvent.KEYCODE_ALT_RIGHT: - metaPress(OUR_ALT_ON); - return true; - } - } else { - switch (keyCode) { - case KeyEvent.KEYCODE_ALT_LEFT: - case KeyEvent.KEYCODE_ALT_RIGHT: - metaPress(OUR_ALT_ON); - return true; - case KeyEvent.KEYCODE_SHIFT_LEFT: - case KeyEvent.KEYCODE_SHIFT_RIGHT: - metaPress(OUR_SHIFT_ON); - return true; - } - } - } - - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { - if (selectingForCopy) { - if (selectionArea.isSelectingOrigin()) - selectionArea.finishSelectingOrigin(); - else { - if (clipboard != null) { - // copy selected area to clipboard - String copiedText = selectionArea.copyFrom(buffer); - clipboard.setText(copiedText); - // XXX STOPSHIP -// manager.notifyUser(manager.getString( -// R.string.console_copy_done, -// copiedText.length())); - selectingForCopy = false; - selectionArea.reset(); - } - } - } else { - if ((ourMetaState & OUR_CTRL_ON) != 0) { - sendEscape(); - ourMetaState &= ~OUR_CTRL_ON; - } else - metaPress(OUR_CTRL_ON); - } - bridge.redraw(); - return true; - } - - int derivedMetaState = event.getMetaState(); - if ((ourMetaState & OUR_SHIFT_MASK) != 0) - derivedMetaState |= KeyEvent.META_SHIFT_ON; - if ((ourMetaState & OUR_ALT_MASK) != 0) - derivedMetaState |= KeyEvent.META_ALT_ON; - if ((ourMetaState & OUR_CTRL_MASK) != 0) - derivedMetaState |= HC_META_CTRL_ON; - - if ((ourMetaState & OUR_TRANSIENT) != 0) { - ourMetaState &= ~OUR_TRANSIENT; - bridge.redraw(); - } - - // Test for modified numbers becoming function keys - if (shiftedNumbersAreFKeys && (derivedMetaState & KeyEvent.META_SHIFT_ON) != 0) { - if (sendFunctionKey(keyCode)) - return true; - } - if (controlNumbersAreFKeys && (derivedMetaState & HC_META_CTRL_ON) != 0) { - if (sendFunctionKey(keyCode)) - return true; - } - - // Ask the system to use the keymap to give us the unicode character for this key, - // with our derived modifier state applied. - int uchar = event.getUnicodeChar(derivedMetaState & ~HC_META_CTRL_MASK); - int ucharWithoutAlt = event.getUnicodeChar( - derivedMetaState & ~(HC_META_ALT_MASK | HC_META_CTRL_MASK)); - if (uchar != ucharWithoutAlt) { - // The alt key was used to modify the character returned; therefore, drop the alt - // modifier from the state so we don't end up sending alt+key. - derivedMetaState &= ~HC_META_ALT_MASK; - } - - // Remove shift from the modifier state as it has already been used by getUnicodeChar. - derivedMetaState &= ~KeyEvent.META_SHIFT_ON; - - if ((uchar & KeyCharacterMap.COMBINING_ACCENT) != 0) { - mDeadKey = uchar & KeyCharacterMap.COMBINING_ACCENT_MASK; - return true; - } - - if (mDeadKey != 0) { - uchar = KeyCharacterMap.getDeadChar(mDeadKey, keyCode); - mDeadKey = 0; - } - - // If we have a defined non-control character - if (uchar >= 0x20) { - if ((derivedMetaState & HC_META_CTRL_ON) != 0) - uchar = keyAsControl(uchar); - if ((derivedMetaState & KeyEvent.META_ALT_ON) != 0) - sendEscape(); - if (uchar < 0x80) - bridge.transport.write(uchar); - else - // TODO write encoding routine that doesn't allocate each time - bridge.transport.write(new String(Character.toChars(uchar)) - .getBytes(encoding)); - return true; - } - - // look for special chars - switch(keyCode) { - case KEYCODE_ESCAPE: - sendEscape(); - return true; - case KeyEvent.KEYCODE_TAB: - bridge.transport.write(0x09); - return true; - case KeyEvent.KEYCODE_CAMERA: - - // check to see which shortcut the camera button triggers - String camera = manager.prefs.getString( - PreferenceConstants.CAMERA, - PreferenceConstants.CAMERA_CTRLA_SPACE); - if(PreferenceConstants.CAMERA_CTRLA_SPACE.equals(camera)) { - bridge.transport.write(0x01); - bridge.transport.write(' '); - } else if(PreferenceConstants.CAMERA_CTRLA.equals(camera)) { - bridge.transport.write(0x01); - } else if(PreferenceConstants.CAMERA_ESC.equals(camera)) { - ((vt320)buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0); - } else if(PreferenceConstants.CAMERA_ESC_A.equals(camera)) { - ((vt320)buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0); - bridge.transport.write('a'); - } - - break; - - case KeyEvent.KEYCODE_DEL: - ((vt320) buffer).keyPressed(vt320.KEY_BACK_SPACE, ' ', - getStateForBuffer()); - return true; - case KeyEvent.KEYCODE_ENTER: - ((vt320)buffer).keyTyped(vt320.KEY_ENTER, ' ', 0); - return true; - - case KeyEvent.KEYCODE_DPAD_LEFT: - if (selectingForCopy) { - selectionArea.decrementColumn(); - bridge.redraw(); - } else { - ((vt320) buffer).keyPressed(vt320.KEY_LEFT, ' ', - getStateForBuffer()); - bridge.tryKeyVibrate(); - } - return true; - - case KeyEvent.KEYCODE_DPAD_UP: - if (selectingForCopy) { - selectionArea.decrementRow(); - bridge.redraw(); - } else { - ((vt320) buffer).keyPressed(vt320.KEY_UP, ' ', - getStateForBuffer()); - bridge.tryKeyVibrate(); - } - return true; - - case KeyEvent.KEYCODE_DPAD_DOWN: - if (selectingForCopy) { - selectionArea.incrementRow(); - bridge.redraw(); - } else { - ((vt320) buffer).keyPressed(vt320.KEY_DOWN, ' ', - getStateForBuffer()); - bridge.tryKeyVibrate(); - } - return true; - - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (selectingForCopy) { - selectionArea.incrementColumn(); - bridge.redraw(); - } else { - ((vt320) buffer).keyPressed(vt320.KEY_RIGHT, ' ', - getStateForBuffer()); - bridge.tryKeyVibrate(); - } - return true; - } - - } catch (IOException e) { - Log.e(TAG, "Problem while trying to handle an onKey() event", e); - try { - bridge.transport.flush(); - } catch (IOException ioe) { - Log.d(TAG, "Our transport was closed, dispatching disconnect event"); - bridge.dispatchDisconnect(false); - } - } catch (NullPointerException npe) { - Log.d(TAG, "Input before connection established ignored."); - return true; - } - - return false; - } - - public int keyAsControl(int key) { - // Support CTRL-a through CTRL-z - if (key >= 0x61 && key <= 0x7A) - key -= 0x60; - // Support CTRL-A through CTRL-_ - else if (key >= 0x41 && key <= 0x5F) - key -= 0x40; - // CTRL-space sends NULL - else if (key == 0x20) - key = 0x00; - // CTRL-? sends DEL - else if (key == 0x3F) - key = 0x7F; - return key; - } - - public void sendEscape() { - ((vt320)buffer).keyTyped(vt320.KEY_ESCAPE, ' ', 0); - } - - /** - * @param key - * @return successful - */ - private boolean sendFunctionKey(int keyCode) { - switch (keyCode) { - case KeyEvent.KEYCODE_1: - ((vt320) buffer).keyPressed(vt320.KEY_F1, ' ', 0); - return true; - case KeyEvent.KEYCODE_2: - ((vt320) buffer).keyPressed(vt320.KEY_F2, ' ', 0); - return true; - case KeyEvent.KEYCODE_3: - ((vt320) buffer).keyPressed(vt320.KEY_F3, ' ', 0); - return true; - case KeyEvent.KEYCODE_4: - ((vt320) buffer).keyPressed(vt320.KEY_F4, ' ', 0); - return true; - case KeyEvent.KEYCODE_5: - ((vt320) buffer).keyPressed(vt320.KEY_F5, ' ', 0); - return true; - case KeyEvent.KEYCODE_6: - ((vt320) buffer).keyPressed(vt320.KEY_F6, ' ', 0); - return true; - case KeyEvent.KEYCODE_7: - ((vt320) buffer).keyPressed(vt320.KEY_F7, ' ', 0); - return true; - case KeyEvent.KEYCODE_8: - ((vt320) buffer).keyPressed(vt320.KEY_F8, ' ', 0); - return true; - case KeyEvent.KEYCODE_9: - ((vt320) buffer).keyPressed(vt320.KEY_F9, ' ', 0); - return true; - case KeyEvent.KEYCODE_0: - ((vt320) buffer).keyPressed(vt320.KEY_F10, ' ', 0); - return true; - default: - return false; - } - } - - /** - * Handle meta key presses where the key can be locked on. - * <p> - * 1st press: next key to have meta state<br /> - * 2nd press: meta state is locked on<br /> - * 3rd press: disable meta state - * - * @param code - */ - public void metaPress(int code) { - if ((ourMetaState & (code << 1)) != 0) { - ourMetaState &= ~(code << 1); - } else if ((ourMetaState & code) != 0) { - ourMetaState &= ~code; - ourMetaState |= code << 1; - } else - ourMetaState |= code; - bridge.redraw(); - } - - public void setTerminalKeyMode(String keymode) { - this.keymode = keymode; - } - - private int getStateForBuffer() { - int bufferState = 0; - - if ((ourMetaState & OUR_CTRL_MASK) != 0) - bufferState |= vt320.KEY_CONTROL; - if ((ourMetaState & OUR_SHIFT_MASK) != 0) - bufferState |= vt320.KEY_SHIFT; - if ((ourMetaState & OUR_ALT_MASK) != 0) - bufferState |= vt320.KEY_ALT; - - return bufferState; - } - - public int getMetaState() { - return ourMetaState; - } - - public int getDeadKey() { - return mDeadKey; - } - - public void setClipboardManager(ClipboardManager clipboard) { - this.clipboard = clipboard; - } - - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) { - if (PreferenceConstants.KEYMODE.equals(key) || - PreferenceConstants.SHIFT_FKEYS.equals(key) || - PreferenceConstants.CTRL_FKEYS.equals(key) || - PreferenceConstants.VOLUME_FONT.equals(key)) { - updatePrefs(); - } - } - - private void updatePrefs() { - keymode = prefs.getString(PreferenceConstants.KEYMODE, PreferenceConstants.KEYMODE_RIGHT); - shiftedNumbersAreFKeysOnHardKeyboard = - prefs.getBoolean(PreferenceConstants.SHIFT_FKEYS, false); - controlNumbersAreFKeysOnSoftKeyboard = - prefs.getBoolean(PreferenceConstants.CTRL_FKEYS, false); - volumeKeysChangeFontSize = prefs.getBoolean(PreferenceConstants.VOLUME_FONT, true); - } - - public void setCharset(String encoding) { - this.encoding = encoding; - } -} diff --git a/src/org/connectbot/service/TerminalManager.java b/src/org/connectbot/service/TerminalManager.java deleted file mode 100644 index 369d79a..0000000 --- a/src/org/connectbot/service/TerminalManager.java +++ /dev/null @@ -1,714 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.service; - -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Timer; -import java.util.TimerTask; - -import org.connectbot.R; -import org.connectbot.bean.HostBean; -import org.connectbot.bean.PubkeyBean; -import org.connectbot.transport.TransportFactory; -import org.connectbot.util.HostDatabase; -import org.connectbot.util.PreferenceConstants; -import org.connectbot.util.PubkeyDatabase; -import org.connectbot.util.PubkeyUtils; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.content.res.AssetFileDescriptor; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.media.MediaPlayer.OnCompletionListener; -import android.net.Uri; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Vibrator; -import android.preference.PreferenceManager; -import android.util.Log; - -/** - * Manager for SSH connections that runs as a service. This service holds a list - * of currently connected SSH bridges that are ready for connection up to a GUI - * if needed. - * - * @author jsharkey - */ -public class TerminalManager extends Service implements BridgeDisconnectedListener, OnSharedPreferenceChangeListener { - public final static String TAG = "ConnectBot.TerminalManager"; - - public List<TerminalBridge> bridges = new LinkedList<TerminalBridge>(); - public Map<HostBean, WeakReference<TerminalBridge>> mHostBridgeMap = - new HashMap<HostBean, WeakReference<TerminalBridge>>(); - public Map<String, WeakReference<TerminalBridge>> mNicknameBridgeMap = - new HashMap<String, WeakReference<TerminalBridge>>(); - - public TerminalBridge defaultBridge = null; - - public List<HostBean> disconnected = new LinkedList<HostBean>(); - - public Handler disconnectHandler = null; - - public Map<String, KeyHolder> loadedKeypairs = new HashMap<String, KeyHolder>(); - - public Resources res; - - public HostDatabase hostdb; - public PubkeyDatabase pubkeydb; - - protected SharedPreferences prefs; - - final private IBinder binder = new TerminalBinder(); - - private ConnectivityReceiver connectivityManager; - - private MediaPlayer mediaPlayer; - - private Timer pubkeyTimer; - - private Timer idleTimer; - private final long IDLE_TIMEOUT = 300000; // 5 minutes - - private Vibrator vibrator; - private volatile boolean wantKeyVibration; - public static final long VIBRATE_DURATION = 30; - - private boolean wantBellVibration; - - private boolean resizeAllowed = true; - - private boolean savingKeys; - - protected List<WeakReference<TerminalBridge>> mPendingReconnect - = new LinkedList<WeakReference<TerminalBridge>>(); - - public boolean hardKeyboardHidden; - - @Override - public void onCreate() { - Log.i(TAG, "Starting service"); - - prefs = PreferenceManager.getDefaultSharedPreferences(this); - prefs.registerOnSharedPreferenceChangeListener(this); - - res = getResources(); - - pubkeyTimer = new Timer("pubkeyTimer", true); - - hostdb = new HostDatabase(this); - pubkeydb = new PubkeyDatabase(this); - - // load all marked pubkeys into memory - updateSavingKeys(); - List<PubkeyBean> pubkeys = pubkeydb.getAllStartPubkeys(); - - for (PubkeyBean pubkey : pubkeys) { - try { - PrivateKey privKey = PubkeyUtils.decodePrivate(pubkey.getPrivateKey(), pubkey.getType()); - PublicKey pubKey = PubkeyUtils.decodePublic(pubkey.getPublicKey(), pubkey.getType()); - KeyPair pair = new KeyPair(pubKey, privKey); - - addKey(pubkey, pair); - } catch (Exception e) { - Log.d(TAG, String.format("Problem adding key '%s' to in-memory cache", pubkey.getNickname()), e); - } - } - - vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); - wantKeyVibration = prefs.getBoolean(PreferenceConstants.BUMPY_ARROWS, true); - - wantBellVibration = prefs.getBoolean(PreferenceConstants.BELL_VIBRATE, true); - enableMediaPlayer(); - - hardKeyboardHidden = (res.getConfiguration().hardKeyboardHidden == - Configuration.HARDKEYBOARDHIDDEN_YES); - - final boolean lockingWifi = prefs.getBoolean(PreferenceConstants.WIFI_LOCK, true); - - connectivityManager = new ConnectivityReceiver(this, lockingWifi); - - } - - private void updateSavingKeys() { - savingKeys = prefs.getBoolean(PreferenceConstants.MEMKEYS, true); - } - - @Override - public void onDestroy() { - Log.i(TAG, "Destroying service"); - - disconnectAll(true); - - if(hostdb != null) { - hostdb.close(); - hostdb = null; - } - - if(pubkeydb != null) { - pubkeydb.close(); - pubkeydb = null; - } - - synchronized (this) { - if (idleTimer != null) - idleTimer.cancel(); - if (pubkeyTimer != null) - pubkeyTimer.cancel(); - } - - connectivityManager.cleanup(); - - ConnectionNotifier.getInstance().hideRunningNotification(this); - - disableMediaPlayer(); - } - - /** - * Disconnect all currently connected bridges. - */ - private void disconnectAll(final boolean immediate) { - TerminalBridge[] tmpBridges = null; - - synchronized (bridges) { - if (bridges.size() > 0) { - tmpBridges = bridges.toArray(new TerminalBridge[bridges.size()]); - } - } - - if (tmpBridges != null) { - // disconnect and dispose of any existing bridges - for (int i = 0; i < tmpBridges.length; i++) - tmpBridges[i].dispatchDisconnect(immediate); - } - } - - /** - * Open a new SSH session using the given parameters. - */ - private TerminalBridge openConnection(HostBean host) throws IllegalArgumentException, IOException { - // throw exception if terminal already open - if (getConnectedBridge(host) != null) { - throw new IllegalArgumentException("Connection already open for that nickname"); - } - - TerminalBridge bridge = new TerminalBridge(this, host); - bridge.setOnDisconnectedListener(this); - bridge.startConnection(); - - synchronized (bridges) { - bridges.add(bridge); - WeakReference<TerminalBridge> wr = new WeakReference<TerminalBridge>(bridge); - mHostBridgeMap.put(bridge.host, wr); - mNicknameBridgeMap.put(bridge.host.getNickname(), wr); - } - - synchronized (disconnected) { - disconnected.remove(bridge.host); - } - - if (bridge.isUsingNetwork()) { - connectivityManager.incRef(); - } - - if (prefs.getBoolean(PreferenceConstants.CONNECTION_PERSIST, true)) { - ConnectionNotifier.getInstance().showRunningNotification(this); - } - - // also update database with new connected time - touchHost(host); - - return bridge; - } - - public String getEmulation() { - return prefs.getString(PreferenceConstants.EMULATION, "screen"); - } - - public int getScrollback() { - int scrollback = 140; - try { - scrollback = Integer.parseInt(prefs.getString(PreferenceConstants.SCROLLBACK, "140")); - } catch(Exception e) { - } - return scrollback; - } - - /** - * Open a new connection by reading parameters from the given URI. Follows - * format specified by an individual transport. - */ - public TerminalBridge openConnection(Uri uri) throws Exception { - HostBean host = TransportFactory.findHost(hostdb, uri); - - if (host == null) - host = TransportFactory.getTransport(uri.getScheme()).createHost(uri); - - return openConnection(host); - } - - /** - * Update the last-connected value for the given nickname by passing through - * to {@link HostDatabase}. - */ - private void touchHost(HostBean host) { - hostdb.touchHost(host); - } - - /** - * Find a connected {@link TerminalBridge} with the given HostBean. - * - * @param host the HostBean to search for - * @return TerminalBridge that uses the HostBean - */ - public TerminalBridge getConnectedBridge(HostBean host) { - WeakReference<TerminalBridge> wr = mHostBridgeMap.get(host); - if (wr != null) { - return wr.get(); - } else { - return null; - } - } - - /** - * Find a connected {@link TerminalBridge} using its nickname. - * - * @param nickname - * @return TerminalBridge that matches nickname - */ - public TerminalBridge getConnectedBridge(final String nickname) { - if (nickname == null) { - return null; - } - WeakReference<TerminalBridge> wr = mNicknameBridgeMap.get(nickname); - if (wr != null) { - return wr.get(); - } else { - return null; - } - } - - /** - * Called by child bridge when somehow it's been disconnected. - */ - public void onDisconnected(TerminalBridge bridge) { - boolean shouldHideRunningNotification = false; - - synchronized (bridges) { - // remove this bridge from our list - bridges.remove(bridge); - - mHostBridgeMap.remove(bridge.host); - mNicknameBridgeMap.remove(bridge.host.getNickname()); - - if (bridge.isUsingNetwork()) { - connectivityManager.decRef(); - } - - if (bridges.size() == 0 && - mPendingReconnect.size() == 0) { - shouldHideRunningNotification = true; - } - } - - synchronized (disconnected) { - disconnected.add(bridge.host); - } - - if (shouldHideRunningNotification) { - ConnectionNotifier.getInstance().hideRunningNotification(this); - } - - // pass notification back up to gui - if (disconnectHandler != null) - Message.obtain(disconnectHandler, -1, bridge).sendToTarget(); - } - - public boolean isKeyLoaded(String nickname) { - return loadedKeypairs.containsKey(nickname); - } - - public void addKey(PubkeyBean pubkey, KeyPair pair) { - addKey(pubkey, pair, false); - } - - public void addKey(PubkeyBean pubkey, KeyPair pair, boolean force) { - if (!savingKeys && !force) - return; - - removeKey(pubkey.getNickname()); - - byte[] sshPubKey = PubkeyUtils.extractOpenSSHPublic(pair); - - KeyHolder keyHolder = new KeyHolder(); - keyHolder.bean = pubkey; - keyHolder.pair = pair; - keyHolder.openSSHPubkey = sshPubKey; - - loadedKeypairs.put(pubkey.getNickname(), keyHolder); - - if (pubkey.getLifetime() > 0) { - final String nickname = pubkey.getNickname(); - pubkeyTimer.schedule(new TimerTask() { - @Override - public void run() { - Log.d(TAG, "Unloading from memory key: " + nickname); - removeKey(nickname); - } - }, pubkey.getLifetime() * 1000); - } - - Log.d(TAG, String.format("Added key '%s' to in-memory cache", pubkey.getNickname())); - } - - public boolean removeKey(String nickname) { - Log.d(TAG, String.format("Removed key '%s' to in-memory cache", nickname)); - return loadedKeypairs.remove(nickname) != null; - } - - public boolean removeKey(byte[] publicKey) { - String nickname = null; - for (Entry<String,KeyHolder> entry : loadedKeypairs.entrySet()) { - if (Arrays.equals(entry.getValue().openSSHPubkey, publicKey)) { - nickname = entry.getKey(); - break; - } - } - - if (nickname != null) { - Log.d(TAG, String.format("Removed key '%s' to in-memory cache", nickname)); - return removeKey(nickname); - } else - return false; - } - - public KeyPair getKey(String nickname) { - if (loadedKeypairs.containsKey(nickname)) { - KeyHolder keyHolder = loadedKeypairs.get(nickname); - return keyHolder.pair; - } else - return null; - } - - public KeyPair getKey(byte[] publicKey) { - for (KeyHolder keyHolder : loadedKeypairs.values()) { - if (Arrays.equals(keyHolder.openSSHPubkey, publicKey)) - return keyHolder.pair; - } - return null; - } - - public String getKeyNickname(byte[] publicKey) { - for (Entry<String,KeyHolder> entry : loadedKeypairs.entrySet()) { - if (Arrays.equals(entry.getValue().openSSHPubkey, publicKey)) - return entry.getKey(); - } - return null; - } - - private void stopWithDelay() { - // TODO add in a way to check whether keys loaded are encrypted and only - // set timer when we have an encrypted key loaded - - if (loadedKeypairs.size() > 0) { - synchronized (this) { - if (idleTimer == null) - idleTimer = new Timer("idleTimer", true); - - idleTimer.schedule(new IdleTask(), IDLE_TIMEOUT); - } - } else { - Log.d(TAG, "Stopping service immediately"); - stopSelf(); - } - } - - protected void stopNow() { - if (bridges.size() == 0) { - stopSelf(); - } - } - - private synchronized void stopIdleTimer() { - if (idleTimer != null) { - idleTimer.cancel(); - idleTimer = null; - } - } - - public class TerminalBinder extends Binder { - public TerminalManager getService() { - return TerminalManager.this; - } - } - - @Override - public IBinder onBind(Intent intent) { - Log.i(TAG, "Someone bound to TerminalManager"); - - setResizeAllowed(true); - - stopIdleTimer(); - - // Make sure we stay running to maintain the bridges - startService(new Intent(this, TerminalManager.class)); - - return binder; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - /* - * We want this service to continue running until it is explicitly - * stopped, so return sticky. - */ - return START_STICKY; - } - - @Override - public void onRebind(Intent intent) { - super.onRebind(intent); - - setResizeAllowed(true); - - Log.i(TAG, "Someone rebound to TerminalManager"); - - stopIdleTimer(); - } - - @Override - public boolean onUnbind(Intent intent) { - Log.i(TAG, "Someone unbound from TerminalManager"); - - setResizeAllowed(true); - - if (bridges.size() == 0) { - stopWithDelay(); - } - - return true; - } - - private class IdleTask extends TimerTask { - /* (non-Javadoc) - * @see java.util.TimerTask#run() - */ - @Override - public void run() { - Log.d(TAG, String.format("Stopping service after timeout of ~%d seconds", IDLE_TIMEOUT / 1000)); - TerminalManager.this.stopNow(); - } - } - - public void tryKeyVibrate() { - if (wantKeyVibration) - vibrate(); - } - - private void vibrate() { - if (vibrator != null) - vibrator.vibrate(VIBRATE_DURATION); - } - - private void enableMediaPlayer() { - mediaPlayer = new MediaPlayer(); - - float volume = prefs.getFloat(PreferenceConstants.BELL_VOLUME, - PreferenceConstants.DEFAULT_BELL_VOLUME); - - mediaPlayer.setAudioStreamType(AudioManager.STREAM_NOTIFICATION); - mediaPlayer.setOnCompletionListener(new BeepListener()); - - AssetFileDescriptor file = res.openRawResourceFd(R.raw.bell); - try { - mediaPlayer.setDataSource(file.getFileDescriptor(), file - .getStartOffset(), file.getLength()); - file.close(); - mediaPlayer.setVolume(volume, volume); - mediaPlayer.prepare(); - } catch (IOException e) { - Log.e(TAG, "Error setting up bell media player", e); - } - } - - private void disableMediaPlayer() { - if (mediaPlayer != null) { - mediaPlayer.release(); - mediaPlayer = null; - } - } - - public void playBeep() { - if (mediaPlayer != null) - mediaPlayer.start(); - - if (wantBellVibration) - vibrate(); - } - - private static class BeepListener implements OnCompletionListener { - public void onCompletion(MediaPlayer mp) { - mp.seekTo(0); - } - } - - /** - * Send system notification to user for a certain host. When user selects - * the notification, it will bring them directly to the ConsoleActivity - * displaying the host. - * - * @param host - */ - public void sendActivityNotification(HostBean host) { - if (!prefs.getBoolean(PreferenceConstants.BELL_NOTIFICATION, false)) - return; - - ConnectionNotifier.getInstance().showActivityNotification(this, host); - } - - /* (non-Javadoc) - * @see android.content.SharedPreferences.OnSharedPreferenceChangeListener#onSharedPreferenceChanged(android.content.SharedPreferences, java.lang.String) - */ - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) { - if (PreferenceConstants.BELL.equals(key)) { - boolean wantAudible = sharedPreferences.getBoolean( - PreferenceConstants.BELL, true); - if (wantAudible && mediaPlayer == null) - enableMediaPlayer(); - else if (!wantAudible && mediaPlayer != null) - disableMediaPlayer(); - } else if (PreferenceConstants.BELL_VOLUME.equals(key)) { - if (mediaPlayer != null) { - float volume = sharedPreferences.getFloat( - PreferenceConstants.BELL_VOLUME, - PreferenceConstants.DEFAULT_BELL_VOLUME); - mediaPlayer.setVolume(volume, volume); - } - } else if (PreferenceConstants.BELL_VIBRATE.equals(key)) { - wantBellVibration = sharedPreferences.getBoolean( - PreferenceConstants.BELL_VIBRATE, true); - } else if (PreferenceConstants.BUMPY_ARROWS.equals(key)) { - wantKeyVibration = sharedPreferences.getBoolean( - PreferenceConstants.BUMPY_ARROWS, true); - } else if (PreferenceConstants.WIFI_LOCK.equals(key)) { - final boolean lockingWifi = prefs.getBoolean(PreferenceConstants.WIFI_LOCK, true); - connectivityManager.setWantWifiLock(lockingWifi); - } else if (PreferenceConstants.MEMKEYS.equals(key)) { - updateSavingKeys(); - } - } - - /** - * Allow {@link TerminalBridge} to resize when the parent has changed. - * @param resizeAllowed - */ - public void setResizeAllowed(boolean resizeAllowed) { - this.resizeAllowed = resizeAllowed; - } - - public boolean isResizeAllowed() { - return resizeAllowed; - } - - public static class KeyHolder { - public PubkeyBean bean; - public KeyPair pair; - public byte[] openSSHPubkey; - } - - /** - * Called when connectivity to the network is lost and it doesn't appear - * we'll be getting a different connection any time soon. - */ - public void onConnectivityLost() { - final Thread t = new Thread() { - @Override - public void run() { - disconnectAll(false); - } - }; - t.setName("Disconnector"); - t.start(); - } - - /** - * Called when connectivity to the network is restored. - */ - public void onConnectivityRestored() { - final Thread t = new Thread() { - @Override - public void run() { - reconnectPending(); - } - }; - t.setName("Reconnector"); - t.start(); - } - - /** - * Insert request into reconnect queue to be executed either immediately - * or later when connectivity is restored depending on whether we're - * currently connected. - * - * @param bridge the TerminalBridge to reconnect when possible - */ - public void requestReconnect(TerminalBridge bridge) { - synchronized (mPendingReconnect) { - mPendingReconnect.add(new WeakReference<TerminalBridge>(bridge)); - if (!bridge.isUsingNetwork() || - connectivityManager.isConnected()) { - reconnectPending(); - } - } - } - - /** - * Reconnect all bridges that were pending a reconnect when connectivity - * was lost. - */ - private void reconnectPending() { - synchronized (mPendingReconnect) { - for (WeakReference<TerminalBridge> ref : mPendingReconnect) { - TerminalBridge bridge = ref.get(); - if (bridge == null) { - continue; - } - bridge.startConnection(); - } - mPendingReconnect.clear(); - } - } -} diff --git a/src/org/connectbot/transport/AbsTransport.java b/src/org/connectbot/transport/AbsTransport.java deleted file mode 100644 index 18397ea..0000000 --- a/src/org/connectbot/transport/AbsTransport.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.transport; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import org.connectbot.bean.HostBean; -import org.connectbot.bean.PortForwardBean; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalManager; - -import android.content.Context; -import android.net.Uri; - -/** - * @author Kenny Root - * - */ -public abstract class AbsTransport { - HostBean host; - TerminalBridge bridge; - TerminalManager manager; - - String emulation; - - public AbsTransport() {} - - public AbsTransport(HostBean host, TerminalBridge bridge, TerminalManager manager) { - this.host = host; - this.bridge = bridge; - this.manager = manager; - } - - /** - * @return protocol part of the URI - */ - public static String getProtocolName() { - return "unknown"; - } - - /** - * Encode the current transport into a URI that can be passed via intent calls. - * @return URI to host - */ - public static Uri getUri(String input) { - return null; - } - - /** - * Causes transport to connect to the target host. After connecting but before a - * session is started, must call back to {@link TerminalBridge#onConnected()}. - * After that call a session may be opened. - */ - public abstract void connect(); - - /** - * Reads from the transport. Transport must support reading into a the byte array - * <code>buffer</code> at the start of <code>offset</code> and a maximum of - * <code>length</code> bytes. If the remote host disconnects, throw an - * {@link IOException}. - * @param buffer byte buffer to store read bytes into - * @param offset where to start writing in the buffer - * @param length maximum number of bytes to read - * @return number of bytes read - * @throws IOException when remote host disconnects - */ - public abstract int read(byte[] buffer, int offset, int length) throws IOException; - - /** - * Writes to the transport. If the host is not yet connected, simply return without - * doing anything. An {@link IOException} should be thrown if there is an error after - * connection. - * @param buffer bytes to write to transport - * @throws IOException when there is a problem writing after connection - */ - public abstract void write(byte[] buffer) throws IOException; - - /** - * Writes to the transport. See {@link #write(byte[])} for behavior details. - * @param c character to write to the transport - * @throws IOException when there is a problem writing after connection - */ - public abstract void write(int c) throws IOException; - - /** - * Flushes the write commands to the transport. - * @throws IOException when there is a problem writing after connection - */ - public abstract void flush() throws IOException; - - /** - * Closes the connection to the terminal. Note that the resulting failure to read - * should call {@link TerminalBridge#dispatchDisconnect(boolean)}. - */ - public abstract void close(); - - /** - * Tells the transport what dimensions the display is currently - * @param columns columns of text - * @param rows rows of text - * @param width width in pixels - * @param height height in pixels - */ - public abstract void setDimensions(int columns, int rows, int width, int height); - - public void setOptions(Map<String,String> options) { - // do nothing - } - - public Map<String,String> getOptions() { - return null; - } - - public void setCompression(boolean compression) { - // do nothing - } - - public void setUseAuthAgent(String useAuthAgent) { - // do nothing - } - - public void setEmulation(String emulation) { - this.emulation = emulation; - } - - public String getEmulation() { - return emulation; - } - - public void setHost(HostBean host) { - this.host = host; - } - - public void setBridge(TerminalBridge bridge) { - this.bridge = bridge; - } - - public void setManager(TerminalManager manager) { - this.manager = manager; - } - - /** - * Whether or not this transport type can forward ports. - * @return true on ability to forward ports - */ - public boolean canForwardPorts() { - return false; - } - - /** - * Adds the {@link PortForwardBean} to the list. - * @param portForward the port forward bean to add - * @return true on successful addition - */ - public boolean addPortForward(PortForwardBean portForward) { - return false; - } - - /** - * Enables a port forward member. After calling this method, the port forward should - * be operational iff it could be enabled by the transport. - * @param portForward member of our current port forwards list to enable - * @return true on successful port forward setup - */ - public boolean enablePortForward(PortForwardBean portForward) { - return false; - } - - /** - * Disables a port forward member. After calling this method, the port forward should - * be non-functioning iff it could be disabled by the transport. - * @param portForward member of our current port forwards list to enable - * @return true on successful port forward tear-down - */ - public boolean disablePortForward(PortForwardBean portForward) { - return false; - } - - /** - * Removes the {@link PortForwardBean} from the available port forwards. - * @param portForward the port forward bean to remove - * @return true on successful removal - */ - public boolean removePortForward(PortForwardBean portForward) { - return false; - } - - /** - * Gets a list of the {@link PortForwardBean} currently used by this transport. - * @return the list of port forwards - */ - public List<PortForwardBean> getPortForwards() { - return null; - } - - public abstract boolean isConnected(); - public abstract boolean isSessionOpen(); - - /** - * @return int default port for protocol - */ - public abstract int getDefaultPort(); - - /** - * @param username - * @param hostname - * @param port - * @return - */ - public abstract String getDefaultNickname(String username, String hostname, int port); - - /** - * @param uri - * @param selectionKeys - * @param selectionValues - */ - public abstract void getSelectionArgs(Uri uri, Map<String, String> selection); - - /** - * @param uri - * @return - */ - public abstract HostBean createHost(Uri uri); - - /** - * @param context context containing the correct resources - * @return string that hints at the format for connection - */ - public static String getFormatHint(Context context) { - return "???"; - } - - /** - * @return - */ - public abstract boolean usesNetwork(); -} diff --git a/src/org/connectbot/transport/Local.java b/src/org/connectbot/transport/Local.java deleted file mode 100644 index 5ace1b0..0000000 --- a/src/org/connectbot/transport/Local.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.transport; - -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Map; - -import org.connectbot.R; -import org.connectbot.bean.HostBean; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalManager; -import org.connectbot.util.HostDatabase; - -import android.content.Context; -import android.net.Uri; -import android.util.Log; - -import com.google.ase.Exec; - -/** - * @author Kenny Root - * - */ -public class Local extends AbsTransport { - private static final String TAG = "ConnectBot.Local"; - private static final String PROTOCOL = "local"; - - private static final String DEFAULT_URI = "local:#Local"; - - private FileDescriptor shellFd; - - private FileInputStream is; - private FileOutputStream os; - - /** - * - */ - public Local() { - } - - /** - * @param host - * @param bridge - * @param manager - */ - public Local(HostBean host, TerminalBridge bridge, TerminalManager manager) { - super(host, bridge, manager); - } - - public static String getProtocolName() { - return PROTOCOL; - } - - @Override - public void close() { - try { - if (os != null) { - os.close(); - os = null; - } - if (is != null) { - is.close(); - is = null; - } - } catch (IOException e) { - Log.e(TAG, "Couldn't close shell", e); - } - } - - @Override - public void connect() { - int[] pids = new int[1]; - - try { - shellFd = Exec.createSubprocess("/system/bin/sh", "-", null, pids); - } catch (Exception e) { - bridge.outputLine(manager.res.getString(R.string.local_shell_unavailable)); - Log.e(TAG, "Cannot start local shell", e); - return; - } - - final int shellPid = pids[0]; - Runnable exitWatcher = new Runnable() { - public void run() { - Exec.waitFor(shellPid); - - bridge.dispatchDisconnect(false); - } - }; - - Thread exitWatcherThread = new Thread(exitWatcher); - exitWatcherThread.setName("LocalExitWatcher"); - exitWatcherThread.setDaemon(true); - exitWatcherThread.start(); - - is = new FileInputStream(shellFd); - os = new FileOutputStream(shellFd); - - bridge.onConnected(); - } - - @Override - public void flush() throws IOException { - os.flush(); - } - - @Override - public String getDefaultNickname(String username, String hostname, int port) { - return DEFAULT_URI; - } - - @Override - public int getDefaultPort() { - return 0; - } - - @Override - public boolean isConnected() { - return is != null && os != null; - } - - @Override - public boolean isSessionOpen() { - return is != null && os != null; - } - - @Override - public int read(byte[] buffer, int start, int len) throws IOException { - if (is == null) { - bridge.dispatchDisconnect(false); - throw new IOException("session closed"); - } - return is.read(buffer, start, len); - } - - @Override - public void setDimensions(int columns, int rows, int width, int height) { - try { - Exec.setPtyWindowSize(shellFd, rows, columns, width, height); - } catch (Exception e) { - Log.e(TAG, "Couldn't resize pty", e); - } - } - - @Override - public void write(byte[] buffer) throws IOException { - if (os != null) - os.write(buffer); - } - - @Override - public void write(int c) throws IOException { - if (os != null) - os.write(c); - } - - public static Uri getUri(String input) { - Uri uri = Uri.parse(DEFAULT_URI); - - if (input != null && input.length() > 0) { - uri = uri.buildUpon().fragment(input).build(); - } - - return uri; - } - - @Override - public HostBean createHost(Uri uri) { - HostBean host = new HostBean(); - - host.setProtocol(PROTOCOL); - - String nickname = uri.getFragment(); - if (nickname == null || nickname.length() == 0) { - host.setNickname(getDefaultNickname(host.getUsername(), - host.getHostname(), host.getPort())); - } else { - host.setNickname(uri.getFragment()); - } - - return host; - } - - @Override - public void getSelectionArgs(Uri uri, Map<String, String> selection) { - selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); - selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); - } - - public static String getFormatHint(Context context) { - return context.getString(R.string.hostpref_nickname_title); - } - - /* (non-Javadoc) - * @see org.connectbot.transport.AbsTransport#usesNetwork() - */ - @Override - public boolean usesNetwork() { - return false; - } -} diff --git a/src/org/connectbot/transport/SSH.java b/src/org/connectbot/transport/SSH.java deleted file mode 100644 index 6ef9745..0000000 --- a/src/org/connectbot/transport/SSH.java +++ /dev/null @@ -1,958 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.transport; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.connectbot.R; -import org.connectbot.bean.HostBean; -import org.connectbot.bean.PortForwardBean; -import org.connectbot.bean.PubkeyBean; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalManager; -import org.connectbot.service.TerminalManager.KeyHolder; -import org.connectbot.util.HostDatabase; -import org.connectbot.util.PubkeyDatabase; -import org.connectbot.util.PubkeyUtils; - -import android.content.Context; -import android.net.Uri; -import android.util.Log; - -import com.trilead.ssh2.AuthAgentCallback; -import com.trilead.ssh2.ChannelCondition; -import com.trilead.ssh2.Connection; -import com.trilead.ssh2.ConnectionInfo; -import com.trilead.ssh2.ConnectionMonitor; -import com.trilead.ssh2.DynamicPortForwarder; -import com.trilead.ssh2.InteractiveCallback; -import com.trilead.ssh2.KnownHosts; -import com.trilead.ssh2.LocalPortForwarder; -import com.trilead.ssh2.ServerHostKeyVerifier; -import com.trilead.ssh2.Session; -import com.trilead.ssh2.crypto.PEMDecoder; -import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.RSASHA1Verify; - -/** - * @author Kenny Root - * - */ -public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveCallback, AuthAgentCallback { - public SSH() { - super(); - } - - /** - * @param bridge - * @param db - */ - public SSH(HostBean host, TerminalBridge bridge, TerminalManager manager) { - super(host, bridge, manager); - } - - private static final String PROTOCOL = "ssh"; - private static final String TAG = "ConnectBot.SSH"; - private static final int DEFAULT_PORT = 22; - - private static final String AUTH_PUBLICKEY = "publickey", - AUTH_PASSWORD = "password", - AUTH_KEYBOARDINTERACTIVE = "keyboard-interactive"; - - private final static int AUTH_TRIES = 20; - - static final Pattern hostmask; - static { - hostmask = Pattern.compile("^(.+)@([0-9a-z.-]+)(:(\\d+))?$", Pattern.CASE_INSENSITIVE); - } - - private boolean compression = false; - private volatile boolean authenticated = false; - private volatile boolean connected = false; - private volatile boolean sessionOpen = false; - - private boolean pubkeysExhausted = false; - private boolean interactiveCanContinue = true; - - private Connection connection; - private Session session; - private ConnectionInfo connectionInfo; - - private OutputStream stdin; - private InputStream stdout; - private InputStream stderr; - - private static final int conditions = ChannelCondition.STDOUT_DATA - | ChannelCondition.STDERR_DATA - | ChannelCondition.CLOSED - | ChannelCondition.EOF; - - private List<PortForwardBean> portForwards = new LinkedList<PortForwardBean>(); - - private int columns; - private int rows; - - private int width; - private int height; - - private String useAuthAgent = HostDatabase.AUTHAGENT_NO; - private String agentLockPassphrase; - - public class HostKeyVerifier implements ServerHostKeyVerifier { - public boolean verifyServerHostKey(String hostname, int port, - String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException { - - // read in all known hosts from hostdb - KnownHosts hosts = manager.hostdb.getKnownHosts(); - Boolean result; - - String matchName = String.format(Locale.US, "%s:%d", hostname, port); - - String fingerprint = KnownHosts.createHexFingerprint(serverHostKeyAlgorithm, serverHostKey); - - String algorithmName; - if ("ssh-rsa".equals(serverHostKeyAlgorithm)) - algorithmName = "RSA"; - else if ("ssh-dss".equals(serverHostKeyAlgorithm)) - algorithmName = "DSA"; - else if (serverHostKeyAlgorithm.startsWith("ecdsa-")) - algorithmName = "EC"; - else - algorithmName = serverHostKeyAlgorithm; - - switch(hosts.verifyHostkey(matchName, serverHostKeyAlgorithm, serverHostKey)) { - case KnownHosts.HOSTKEY_IS_OK: - bridge.outputLine(manager.res.getString(R.string.terminal_sucess, algorithmName, fingerprint)); - return true; - - case KnownHosts.HOSTKEY_IS_NEW: - // prompt user - bridge.outputLine(manager.res.getString(R.string.host_authenticity_warning, hostname)); - bridge.outputLine(manager.res.getString(R.string.host_fingerprint, algorithmName, fingerprint)); - - result = bridge.promptHelper.requestBooleanPrompt(null, manager.res.getString(R.string.prompt_continue_connecting)); - if(result == null) return false; - if(result.booleanValue()) { - // save this key in known database - manager.hostdb.saveKnownHost(hostname, port, serverHostKeyAlgorithm, serverHostKey); - } - return result.booleanValue(); - - case KnownHosts.HOSTKEY_HAS_CHANGED: - String header = String.format("@ %s @", - manager.res.getString(R.string.host_verification_failure_warning_header)); - - char[] atsigns = new char[header.length()]; - Arrays.fill(atsigns, '@'); - String border = new String(atsigns); - - bridge.outputLine(border); - bridge.outputLine(manager.res.getString(R.string.host_verification_failure_warning)); - bridge.outputLine(border); - - bridge.outputLine(String.format(manager.res.getString(R.string.host_fingerprint), - algorithmName, fingerprint)); - - // Users have no way to delete keys, so we'll prompt them for now. - result = bridge.promptHelper.requestBooleanPrompt(null, manager.res.getString(R.string.prompt_continue_connecting)); - if(result == null) return false; - if(result.booleanValue()) { - // save this key in known database - manager.hostdb.saveKnownHost(hostname, port, serverHostKeyAlgorithm, serverHostKey); - } - return result.booleanValue(); - - default: - return false; - } - } - - } - - private void authenticate() { - try { - if (connection.authenticateWithNone(host.getUsername())) { - finishConnection(); - return; - } - } catch(Exception e) { - Log.d(TAG, "Host does not support 'none' authentication."); - } - - bridge.outputLine(manager.res.getString(R.string.terminal_auth)); - - try { - long pubkeyId = host.getPubkeyId(); - - if (!pubkeysExhausted && - pubkeyId != HostDatabase.PUBKEYID_NEVER && - connection.isAuthMethodAvailable(host.getUsername(), AUTH_PUBLICKEY)) { - - // if explicit pubkey defined for this host, then prompt for password as needed - // otherwise just try all in-memory keys held in terminalmanager - - if (pubkeyId == HostDatabase.PUBKEYID_ANY) { - // try each of the in-memory keys - bridge.outputLine(manager.res - .getString(R.string.terminal_auth_pubkey_any)); - for (Entry<String, KeyHolder> entry : manager.loadedKeypairs.entrySet()) { - if (entry.getValue().bean.isConfirmUse() - && !promptForPubkeyUse(entry.getKey())) - continue; - - if (this.tryPublicKey(host.getUsername(), entry.getKey(), - entry.getValue().pair)) { - finishConnection(); - break; - } - } - } else { - bridge.outputLine(manager.res.getString(R.string.terminal_auth_pubkey_specific)); - // use a specific key for this host, as requested - PubkeyBean pubkey = manager.pubkeydb.findPubkeyById(pubkeyId); - - if (pubkey == null) - bridge.outputLine(manager.res.getString(R.string.terminal_auth_pubkey_invalid)); - else - if (tryPublicKey(pubkey)) - finishConnection(); - } - - pubkeysExhausted = true; - } else if (interactiveCanContinue && - connection.isAuthMethodAvailable(host.getUsername(), AUTH_KEYBOARDINTERACTIVE)) { - // this auth method will talk with us using InteractiveCallback interface - // it blocks until authentication finishes - bridge.outputLine(manager.res.getString(R.string.terminal_auth_ki)); - interactiveCanContinue = false; - if(connection.authenticateWithKeyboardInteractive(host.getUsername(), this)) { - finishConnection(); - } else { - bridge.outputLine(manager.res.getString(R.string.terminal_auth_ki_fail)); - } - } else if (connection.isAuthMethodAvailable(host.getUsername(), AUTH_PASSWORD)) { - bridge.outputLine(manager.res.getString(R.string.terminal_auth_pass)); - String password = bridge.getPromptHelper().requestStringPrompt(null, - manager.res.getString(R.string.prompt_password)); - if (password != null - && connection.authenticateWithPassword(host.getUsername(), password)) { - finishConnection(); - } else { - bridge.outputLine(manager.res.getString(R.string.terminal_auth_pass_fail)); - } - } else { - bridge.outputLine(manager.res.getString(R.string.terminal_auth_fail)); - } - } catch (IllegalStateException e) { - Log.e(TAG, "Connection went away while we were trying to authenticate", e); - return; - } catch(Exception e) { - Log.e(TAG, "Problem during handleAuthentication()", e); - } - } - - /** - * Attempt connection with database row pointed to by cursor. - * @param cursor - * @return true for successful authentication - * @throws NoSuchAlgorithmException - * @throws InvalidKeySpecException - * @throws IOException - */ - private boolean tryPublicKey(PubkeyBean pubkey) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { - KeyPair pair = null; - - if(manager.isKeyLoaded(pubkey.getNickname())) { - // load this key from memory if its already there - Log.d(TAG, String.format("Found unlocked key '%s' already in-memory", pubkey.getNickname())); - - if (pubkey.isConfirmUse()) { - if (!promptForPubkeyUse(pubkey.getNickname())) - return false; - } - - pair = manager.getKey(pubkey.getNickname()); - } else { - // otherwise load key from database and prompt for password as needed - String password = null; - if (pubkey.isEncrypted()) { - password = bridge.getPromptHelper().requestStringPrompt(null, - manager.res.getString(R.string.prompt_pubkey_password, pubkey.getNickname())); - - // Something must have interrupted the prompt. - if (password == null) - return false; - } - - if(PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType())) { - // load specific key using pem format - pair = PEMDecoder.decode(new String(pubkey.getPrivateKey()).toCharArray(), password); - } else { - // load using internal generated format - PrivateKey privKey; - try { - privKey = PubkeyUtils.decodePrivate(pubkey.getPrivateKey(), - pubkey.getType(), password); - } catch (Exception e) { - String message = String.format("Bad password for key '%s'. Authentication failed.", pubkey.getNickname()); - Log.e(TAG, message, e); - bridge.outputLine(message); - return false; - } - - PublicKey pubKey = PubkeyUtils.decodePublic(pubkey.getPublicKey(), pubkey.getType()); - - // convert key to trilead format - pair = new KeyPair(pubKey, privKey); - Log.d(TAG, "Unlocked key " + PubkeyUtils.formatKey(pubKey)); - } - - Log.d(TAG, String.format("Unlocked key '%s'", pubkey.getNickname())); - - // save this key in memory - manager.addKey(pubkey, pair); - } - - return tryPublicKey(host.getUsername(), pubkey.getNickname(), pair); - } - - private boolean tryPublicKey(String username, String keyNickname, KeyPair pair) throws IOException { - //bridge.outputLine(String.format("Attempting 'publickey' with key '%s' [%s]...", keyNickname, trileadKey.toString())); - boolean success = connection.authenticateWithPublicKey(username, pair); - if(!success) - bridge.outputLine(manager.res.getString(R.string.terminal_auth_pubkey_fail, keyNickname)); - return success; - } - - /** - * Internal method to request actual PTY terminal once we've finished - * authentication. If called before authenticated, it will just fail. - */ - private void finishConnection() { - authenticated = true; - - for (PortForwardBean portForward : portForwards) { - try { - enablePortForward(portForward); - bridge.outputLine(manager.res.getString(R.string.terminal_enable_portfoward, portForward.getDescription())); - } catch (Exception e) { - Log.e(TAG, "Error setting up port forward during connect", e); - } - } - - if (!host.getWantSession()) { - bridge.outputLine(manager.res.getString(R.string.terminal_no_session)); - bridge.onConnected(); - return; - } - - try { - session = connection.openSession(); - - if (!useAuthAgent.equals(HostDatabase.AUTHAGENT_NO)) - session.requestAuthAgentForwarding(this); - - session.requestPTY(getEmulation(), columns, rows, width, height, null); - session.startShell(); - - stdin = session.getStdin(); - stdout = session.getStdout(); - stderr = session.getStderr(); - - sessionOpen = true; - - bridge.onConnected(); - } catch (IOException e1) { - Log.e(TAG, "Problem while trying to create PTY in finishConnection()", e1); - } - - } - - @Override - public void connect() { - connection = new Connection(host.getHostname(), host.getPort()); - connection.addConnectionMonitor(this); - - try { - connection.setCompression(compression); - } catch (IOException e) { - Log.e(TAG, "Could not enable compression!", e); - } - - try { - /* Uncomment when debugging SSH protocol: - DebugLogger logger = new DebugLogger() { - - public void log(int level, String className, String message) { - Log.d("SSH", message); - } - - }; - Logger.enabled = true; - Logger.logger = logger; - */ - connectionInfo = connection.connect(new HostKeyVerifier()); - connected = true; - - if (connectionInfo.clientToServerCryptoAlgorithm - .equals(connectionInfo.serverToClientCryptoAlgorithm) - && connectionInfo.clientToServerMACAlgorithm - .equals(connectionInfo.serverToClientMACAlgorithm)) { - bridge.outputLine(manager.res.getString(R.string.terminal_using_algorithm, - connectionInfo.clientToServerCryptoAlgorithm, - connectionInfo.clientToServerMACAlgorithm)); - } else { - bridge.outputLine(manager.res.getString( - R.string.terminal_using_c2s_algorithm, - connectionInfo.clientToServerCryptoAlgorithm, - connectionInfo.clientToServerMACAlgorithm)); - - bridge.outputLine(manager.res.getString( - R.string.terminal_using_s2c_algorithm, - connectionInfo.serverToClientCryptoAlgorithm, - connectionInfo.serverToClientMACAlgorithm)); - } - } catch (IOException e) { - Log.e(TAG, "Problem in SSH connection thread during authentication", e); - - // Display the reason in the text. - bridge.outputLine(e.getCause().getMessage()); - - onDisconnect(); - return; - } - - try { - // enter a loop to keep trying until authentication - int tries = 0; - while (connected && !connection.isAuthenticationComplete() && tries++ < AUTH_TRIES) { - authenticate(); - - // sleep to make sure we dont kill system - Thread.sleep(1000); - } - } catch(Exception e) { - Log.e(TAG, "Problem in SSH connection thread during authentication", e); - } - } - - @Override - public void close() { - connected = false; - - if (session != null) { - session.close(); - session = null; - } - - if (connection != null) { - connection.close(); - connection = null; - } - } - - private void onDisconnect() { - close(); - - bridge.dispatchDisconnect(false); - } - - @Override - public void flush() throws IOException { - if (stdin != null) - stdin.flush(); - } - - @Override - public int read(byte[] buffer, int start, int len) throws IOException { - int bytesRead = 0; - - if (session == null) - return 0; - - int newConditions = session.waitForCondition(conditions, 0); - - if ((newConditions & ChannelCondition.STDOUT_DATA) != 0) { - bytesRead = stdout.read(buffer, start, len); - } - - if ((newConditions & ChannelCondition.STDERR_DATA) != 0) { - byte discard[] = new byte[256]; - while (stderr.available() > 0) { - stderr.read(discard); - } - } - - if ((newConditions & ChannelCondition.EOF) != 0) { - onDisconnect(); - throw new IOException("Remote end closed connection"); - } - - return bytesRead; - } - - @Override - public void write(byte[] buffer) throws IOException { - if (stdin != null) - stdin.write(buffer); - } - - @Override - public void write(int c) throws IOException { - if (stdin != null) - stdin.write(c); - } - - @Override - public Map<String, String> getOptions() { - Map<String, String> options = new HashMap<String, String>(); - - options.put("compression", Boolean.toString(compression)); - - return options; - } - - @Override - public void setOptions(Map<String, String> options) { - if (options.containsKey("compression")) - compression = Boolean.parseBoolean(options.get("compression")); - } - - public static String getProtocolName() { - return PROTOCOL; - } - - @Override - public boolean isSessionOpen() { - return sessionOpen; - } - - @Override - public boolean isConnected() { - return connected; - } - - public void connectionLost(Throwable reason) { - onDisconnect(); - } - - @Override - public boolean canForwardPorts() { - return true; - } - - @Override - public List<PortForwardBean> getPortForwards() { - return portForwards; - } - - @Override - public boolean addPortForward(PortForwardBean portForward) { - return portForwards.add(portForward); - } - - @Override - public boolean removePortForward(PortForwardBean portForward) { - // Make sure we don't have a phantom forwarder. - disablePortForward(portForward); - - return portForwards.remove(portForward); - } - - @Override - public boolean enablePortForward(PortForwardBean portForward) { - if (!portForwards.contains(portForward)) { - Log.e(TAG, "Attempt to enable port forward not in list"); - return false; - } - - if (!authenticated) - return false; - - if (HostDatabase.PORTFORWARD_LOCAL.equals(portForward.getType())) { - LocalPortForwarder lpf = null; - try { - lpf = connection.createLocalPortForwarder( - new InetSocketAddress(InetAddress.getLocalHost(), portForward.getSourcePort()), - portForward.getDestAddr(), portForward.getDestPort()); - } catch (Exception e) { - Log.e(TAG, "Could not create local port forward", e); - return false; - } - - if (lpf == null) { - Log.e(TAG, "returned LocalPortForwarder object is null"); - return false; - } - - portForward.setIdentifier(lpf); - portForward.setEnabled(true); - return true; - } else if (HostDatabase.PORTFORWARD_REMOTE.equals(portForward.getType())) { - try { - connection.requestRemotePortForwarding("", portForward.getSourcePort(), portForward.getDestAddr(), portForward.getDestPort()); - } catch (Exception e) { - Log.e(TAG, "Could not create remote port forward", e); - return false; - } - - portForward.setEnabled(true); - return true; - } else if (HostDatabase.PORTFORWARD_DYNAMIC5.equals(portForward.getType())) { - DynamicPortForwarder dpf = null; - - try { - dpf = connection.createDynamicPortForwarder( - new InetSocketAddress(InetAddress.getLocalHost(), portForward.getSourcePort())); - } catch (Exception e) { - Log.e(TAG, "Could not create dynamic port forward", e); - return false; - } - - portForward.setIdentifier(dpf); - portForward.setEnabled(true); - return true; - } else { - // Unsupported type - Log.e(TAG, String.format("attempt to forward unknown type %s", portForward.getType())); - return false; - } - } - - @Override - public boolean disablePortForward(PortForwardBean portForward) { - if (!portForwards.contains(portForward)) { - Log.e(TAG, "Attempt to disable port forward not in list"); - return false; - } - - if (!authenticated) - return false; - - if (HostDatabase.PORTFORWARD_LOCAL.equals(portForward.getType())) { - LocalPortForwarder lpf = null; - lpf = (LocalPortForwarder)portForward.getIdentifier(); - - if (!portForward.isEnabled() || lpf == null) { - Log.d(TAG, String.format("Could not disable %s; it appears to be not enabled or have no handler", portForward.getNickname())); - return false; - } - - portForward.setEnabled(false); - - try { - lpf.close(); - } catch (IOException e) { - Log.e(TAG, "Could not stop local port forwarder, setting enabled to false", e); - return false; - } - - return true; - } else if (HostDatabase.PORTFORWARD_REMOTE.equals(portForward.getType())) { - portForward.setEnabled(false); - - try { - connection.cancelRemotePortForwarding(portForward.getSourcePort()); - } catch (IOException e) { - Log.e(TAG, "Could not stop remote port forwarding, setting enabled to false", e); - return false; - } - - return true; - } else if (HostDatabase.PORTFORWARD_DYNAMIC5.equals(portForward.getType())) { - DynamicPortForwarder dpf = null; - dpf = (DynamicPortForwarder)portForward.getIdentifier(); - - if (!portForward.isEnabled() || dpf == null) { - Log.d(TAG, String.format("Could not disable %s; it appears to be not enabled or have no handler", portForward.getNickname())); - return false; - } - - portForward.setEnabled(false); - - try { - dpf.close(); - } catch (IOException e) { - Log.e(TAG, "Could not stop dynamic port forwarder, setting enabled to false", e); - return false; - } - - return true; - } else { - // Unsupported type - Log.e(TAG, String.format("attempt to forward unknown type %s", portForward.getType())); - return false; - } - } - - @Override - public void setDimensions(int columns, int rows, int width, int height) { - this.columns = columns; - this.rows = rows; - - if (sessionOpen) { - try { - session.resizePTY(columns, rows, width, height); - } catch (IOException e) { - Log.e(TAG, "Couldn't send resize PTY packet", e); - } - } - } - - @Override - public int getDefaultPort() { - return DEFAULT_PORT; - } - - @Override - public String getDefaultNickname(String username, String hostname, int port) { - if (port == DEFAULT_PORT) { - return String.format(Locale.US, "%s@%s", username, hostname); - } else { - return String.format(Locale.US, "%s@%s:%d", username, hostname, port); - } - } - - public static Uri getUri(String input) { - Matcher matcher = hostmask.matcher(input); - - if (!matcher.matches()) - return null; - - StringBuilder sb = new StringBuilder(); - - sb.append(PROTOCOL) - .append("://") - .append(Uri.encode(matcher.group(1))) - .append('@') - .append(matcher.group(2)); - - String portString = matcher.group(4); - int port = DEFAULT_PORT; - if (portString != null) { - try { - port = Integer.parseInt(portString); - if (port < 1 || port > 65535) { - port = DEFAULT_PORT; - } - } catch (NumberFormatException nfe) { - // Keep the default port - } - } - - if (port != DEFAULT_PORT) { - sb.append(':') - .append(port); - } - - sb.append("/#") - .append(Uri.encode(input)); - - Uri uri = Uri.parse(sb.toString()); - - return uri; - } - - /** - * Handle challenges from keyboard-interactive authentication mode. - */ - public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) { - interactiveCanContinue = true; - String[] responses = new String[numPrompts]; - for(int i = 0; i < numPrompts; i++) { - // request response from user for each prompt - responses[i] = bridge.promptHelper.requestStringPrompt(instruction, prompt[i]); - } - return responses; - } - - @Override - public HostBean createHost(Uri uri) { - HostBean host = new HostBean(); - - host.setProtocol(PROTOCOL); - - host.setHostname(uri.getHost()); - - int port = uri.getPort(); - if (port < 0) - port = DEFAULT_PORT; - host.setPort(port); - - host.setUsername(uri.getUserInfo()); - - String nickname = uri.getFragment(); - if (nickname == null || nickname.length() == 0) { - host.setNickname(getDefaultNickname(host.getUsername(), - host.getHostname(), host.getPort())); - } else { - host.setNickname(uri.getFragment()); - } - - return host; - } - - @Override - public void getSelectionArgs(Uri uri, Map<String, String> selection) { - selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); - selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); - selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); - - int port = uri.getPort(); - if (port < 0) - port = DEFAULT_PORT; - selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); - selection.put(HostDatabase.FIELD_HOST_USERNAME, uri.getUserInfo()); - } - - @Override - public void setCompression(boolean compression) { - this.compression = compression; - } - - public static String getFormatHint(Context context) { - return String.format("%s@%s:%s", - context.getString(R.string.format_username), - context.getString(R.string.format_hostname), - context.getString(R.string.format_port)); - } - - @Override - public void setUseAuthAgent(String useAuthAgent) { - this.useAuthAgent = useAuthAgent; - } - - public Map<String,byte[]> retrieveIdentities() { - Map<String,byte[]> pubKeys = new HashMap<String,byte[]>(manager.loadedKeypairs.size()); - - for (Entry<String,KeyHolder> entry : manager.loadedKeypairs.entrySet()) { - KeyPair pair = entry.getValue().pair; - - try { - PrivateKey privKey = pair.getPrivate(); - if (privKey instanceof RSAPrivateKey) { - RSAPublicKey pubkey = (RSAPublicKey) pair.getPublic(); - pubKeys.put(entry.getKey(), RSASHA1Verify.encodeSSHRSAPublicKey(pubkey)); - } else if (privKey instanceof DSAPrivateKey) { - DSAPublicKey pubkey = (DSAPublicKey) pair.getPublic(); - pubKeys.put(entry.getKey(), DSASHA1Verify.encodeSSHDSAPublicKey(pubkey)); - } else - continue; - } catch (IOException e) { - continue; - } - } - - return pubKeys; - } - - public KeyPair getKeyPair(byte[] publicKey) { - String nickname = manager.getKeyNickname(publicKey); - - if (nickname == null) - return null; - - if (useAuthAgent.equals(HostDatabase.AUTHAGENT_NO)) { - Log.e(TAG, ""); - return null; - } else if (useAuthAgent.equals(HostDatabase.AUTHAGENT_CONFIRM) || - manager.loadedKeypairs.get(nickname).bean.isConfirmUse()) { - if (!promptForPubkeyUse(nickname)) - return null; - } - return manager.getKey(nickname); - } - - private boolean promptForPubkeyUse(String nickname) { - Boolean result = bridge.promptHelper.requestBooleanPrompt(null, - manager.res.getString(R.string.prompt_allow_agent_to_use_key, - nickname)); - return result; - } - - public boolean addIdentity(KeyPair pair, String comment, boolean confirmUse, int lifetime) { - PubkeyBean pubkey = new PubkeyBean(); -// pubkey.setType(PubkeyDatabase.KEY_TYPE_IMPORTED); - pubkey.setNickname(comment); - pubkey.setConfirmUse(confirmUse); - pubkey.setLifetime(lifetime); - manager.addKey(pubkey, pair); - return true; - } - - public boolean removeAllIdentities() { - manager.loadedKeypairs.clear(); - return true; - } - - public boolean removeIdentity(byte[] publicKey) { - return manager.removeKey(publicKey); - } - - public boolean isAgentLocked() { - return agentLockPassphrase != null; - } - - public boolean requestAgentUnlock(String unlockPassphrase) { - if (agentLockPassphrase == null) - return false; - - if (agentLockPassphrase.equals(unlockPassphrase)) - agentLockPassphrase = null; - - return agentLockPassphrase == null; - } - - public boolean setAgentLock(String lockPassphrase) { - if (agentLockPassphrase != null) - return false; - - agentLockPassphrase = lockPassphrase; - return true; - } - - /* (non-Javadoc) - * @see org.connectbot.transport.AbsTransport#usesNetwork() - */ - @Override - public boolean usesNetwork() { - return true; - } -} diff --git a/src/org/connectbot/transport/Telnet.java b/src/org/connectbot/transport/Telnet.java deleted file mode 100644 index 5fde2f6..0000000 --- a/src/org/connectbot/transport/Telnet.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.transport; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.nio.charset.Charset; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.connectbot.R; -import org.connectbot.bean.HostBean; -import org.connectbot.service.TerminalBridge; -import org.connectbot.service.TerminalManager; -import org.connectbot.util.HostDatabase; - -import android.content.Context; -import android.net.Uri; -import android.util.Log; -import de.mud.telnet.TelnetProtocolHandler; - -/** - * Telnet transport implementation.<br/> - * Original idea from the JTA telnet package (de.mud.telnet) - * - * @author Kenny Root - * - */ -public class Telnet extends AbsTransport { - private static final String TAG = "ConnectBot.Telnet"; - private static final String PROTOCOL = "telnet"; - - private static final int DEFAULT_PORT = 23; - - private TelnetProtocolHandler handler; - private Socket socket; - - private InputStream is; - private OutputStream os; - private int width; - private int height; - - private boolean connected = false; - - static final Pattern hostmask; - static { - hostmask = Pattern.compile("^([0-9a-z.-]+)(:(\\d+))?$", Pattern.CASE_INSENSITIVE); - } - - public Telnet() { - handler = new TelnetProtocolHandler() { - /** get the current terminal type */ - @Override - public String getTerminalType() { - return getEmulation(); - } - - /** get the current window size */ - @Override - public int[] getWindowSize() { - return new int[] { width, height }; - } - - /** notify about local echo */ - @Override - public void setLocalEcho(boolean echo) { - /* EMPTY */ - } - - /** write data to our back end */ - @Override - public void write(byte[] b) throws IOException { - if (os != null) - os.write(b); - } - - /** sent on IAC EOR (prompt terminator for remote access systems). */ - @Override - public void notifyEndOfRecord() { - } - - @Override - protected String getCharsetName() { - Charset charset = bridge.getCharset(); - if (charset != null) - return charset.name(); - else - return ""; - } - }; - } - - /** - * @param host - * @param bridge - * @param manager - */ - public Telnet(HostBean host, TerminalBridge bridge, TerminalManager manager) { - super(host, bridge, manager); - } - - public static String getProtocolName() { - return PROTOCOL; - } - - @Override - public void connect() { - try { - socket = new Socket(host.getHostname(), host.getPort()); - - connected = true; - - is = socket.getInputStream(); - os = socket.getOutputStream(); - - bridge.onConnected(); - } catch (UnknownHostException e) { - Log.d(TAG, "IO Exception connecting to host", e); - } catch (IOException e) { - Log.d(TAG, "IO Exception connecting to host", e); - } - } - - @Override - public void close() { - connected = false; - if (socket != null) - try { - socket.close(); - socket = null; - } catch (IOException e) { - Log.d(TAG, "Error closing telnet socket.", e); - } - } - - @Override - public void flush() throws IOException { - os.flush(); - } - - @Override - public int getDefaultPort() { - return DEFAULT_PORT; - } - - @Override - public boolean isConnected() { - return connected; - } - - @Override - public boolean isSessionOpen() { - return connected; - } - - @Override - public int read(byte[] buffer, int start, int len) throws IOException { - /* process all already read bytes */ - int n = 0; - - do { - n = handler.negotiate(buffer, start); - if (n > 0) - return n; - } while (n == 0); - - while (n <= 0) { - do { - n = handler.negotiate(buffer, start); - if (n > 0) - return n; - } while (n == 0); - n = is.read(buffer, start, len); - if (n < 0) { - bridge.dispatchDisconnect(false); - throw new IOException("Remote end closed connection."); - } - - handler.inputfeed(buffer, start, n); - n = handler.negotiate(buffer, start); - } - return n; - } - - @Override - public void write(byte[] buffer) throws IOException { - try { - if (os != null) - os.write(buffer); - } catch (SocketException e) { - bridge.dispatchDisconnect(false); - } - } - - @Override - public void write(int c) throws IOException { - try { - if (os != null) - os.write(c); - } catch (SocketException e) { - bridge.dispatchDisconnect(false); - } - } - - @Override - public void setDimensions(int columns, int rows, int width, int height) { - try { - handler.setWindowSize(columns, rows); - } catch (IOException e) { - Log.e(TAG, "Couldn't resize remote terminal", e); - } - } - - @Override - public String getDefaultNickname(String username, String hostname, int port) { - if (port == DEFAULT_PORT) { - return String.format("%s", hostname); - } else { - return String.format("%s:%d", hostname, port); - } - } - - public static Uri getUri(String input) { - Matcher matcher = hostmask.matcher(input); - - if (!matcher.matches()) - return null; - - StringBuilder sb = new StringBuilder(); - - sb.append(PROTOCOL) - .append("://") - .append(matcher.group(1)); - - String portString = matcher.group(3); - int port = DEFAULT_PORT; - if (portString != null) { - try { - port = Integer.parseInt(portString); - if (port < 1 || port > 65535) { - port = DEFAULT_PORT; - } - } catch (NumberFormatException nfe) { - // Keep the default port - } - } - - if (port != DEFAULT_PORT) { - sb.append(':'); - sb.append(port); - } - - sb.append("/#") - .append(Uri.encode(input)); - - Uri uri = Uri.parse(sb.toString()); - - return uri; - } - - @Override - public HostBean createHost(Uri uri) { - HostBean host = new HostBean(); - - host.setProtocol(PROTOCOL); - - host.setHostname(uri.getHost()); - - int port = uri.getPort(); - if (port < 0) - port = DEFAULT_PORT; - host.setPort(port); - - String nickname = uri.getFragment(); - if (nickname == null || nickname.length() == 0) { - host.setNickname(getDefaultNickname(host.getUsername(), - host.getHostname(), host.getPort())); - } else { - host.setNickname(uri.getFragment()); - } - - return host; - } - - @Override - public void getSelectionArgs(Uri uri, Map<String, String> selection) { - selection.put(HostDatabase.FIELD_HOST_PROTOCOL, PROTOCOL); - selection.put(HostDatabase.FIELD_HOST_NICKNAME, uri.getFragment()); - selection.put(HostDatabase.FIELD_HOST_HOSTNAME, uri.getHost()); - - int port = uri.getPort(); - if (port < 0) - port = DEFAULT_PORT; - selection.put(HostDatabase.FIELD_HOST_PORT, Integer.toString(port)); - } - - public static String getFormatHint(Context context) { - return String.format("%s:%s", - context.getString(R.string.format_hostname), - context.getString(R.string.format_port)); - } - - /* (non-Javadoc) - * @see org.connectbot.transport.AbsTransport#usesNetwork() - */ - @Override - public boolean usesNetwork() { - return true; - } -} diff --git a/src/org/connectbot/transport/TransportFactory.java b/src/org/connectbot/transport/TransportFactory.java deleted file mode 100644 index 72e5e08..0000000 --- a/src/org/connectbot/transport/TransportFactory.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.transport; - -import java.util.HashMap; -import java.util.Map; - -import org.connectbot.bean.HostBean; -import org.connectbot.util.HostDatabase; - -import android.content.Context; -import android.net.Uri; -import android.util.Log; - - -/** - * @author Kenny Root - * - */ -public class TransportFactory { - private static final String TAG = "ConnectBot.TransportFactory"; - - private static String[] transportNames = { - SSH.getProtocolName(), - Telnet.getProtocolName(), - Local.getProtocolName(), - }; - - /** - * @param protocol - * @return - */ - public static AbsTransport getTransport(String protocol) { - if (SSH.getProtocolName().equals(protocol)) { - return new SSH(); - } else if (Telnet.getProtocolName().equals(protocol)) { - return new Telnet(); - } else if (Local.getProtocolName().equals(protocol)) { - return new Local(); - } else { - return null; - } - } - - public static Uri getUri(String scheme, String input) { - Log.d("TransportFactory", String.format( - "Attempting to discover URI for scheme=%s on input=%s", scheme, - input)); - if (SSH.getProtocolName().equals(scheme)) - return SSH.getUri(input); - else if (Telnet.getProtocolName().equals(scheme)) - return Telnet.getUri(input); - else if (Local.getProtocolName().equals(scheme)) { - Log.d("TransportFactory", "Got to the local parsing area"); - return Local.getUri(input); - } else - return null; - } - - public static String[] getTransportNames() { - return transportNames; - } - - public static boolean isSameTransportType(AbsTransport a, AbsTransport b) { - if (a == null || b == null) - return false; - - return a.getClass().equals(b.getClass()); - } - - public static boolean canForwardPorts(String protocol) { - // TODO uh, make this have less knowledge about its children - if (SSH.getProtocolName().equals(protocol)) { - return true; - } else { - return false; - } - } - - /** - * @param protocol text name of protocol - * @param context - * @return expanded format hint - */ - public static String getFormatHint(String protocol, Context context) { - if (SSH.getProtocolName().equals(protocol)) { - return SSH.getFormatHint(context); - } else if (Telnet.getProtocolName().equals(protocol)) { - return Telnet.getFormatHint(context); - } else if (Local.getProtocolName().equals(protocol)) { - return Local.getFormatHint(context); - } else { - return AbsTransport.getFormatHint(context); - } - } - - /** - * @param hostdb Handle to HostDatabase - * @param uri URI to target server - * @param host HostBean in which to put the results - * @return true when host was found - */ - public static HostBean findHost(HostDatabase hostdb, Uri uri) { - AbsTransport transport = getTransport(uri.getScheme()); - - Map<String, String> selection = new HashMap<String, String>(); - - transport.getSelectionArgs(uri, selection); - if (selection.size() == 0) { - Log.e(TAG, String.format("Transport %s failed to do something useful with URI=%s", - uri.getScheme(), uri.toString())); - throw new IllegalStateException("Failed to get needed selection arguments"); - } - - return hostdb.findHost(selection); - } -} diff --git a/src/org/connectbot/util/Colors.java b/src/org/connectbot/util/Colors.java deleted file mode 100644 index ff88d68..0000000 --- a/src/org/connectbot/util/Colors.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -/** - * @author Kenny Root - * - */ -public class Colors { - public final static Integer[] defaults = new Integer[] { - 0xff000000, // black - 0xffcc0000, // red - 0xff00cc00, // green - 0xffcccc00, // brown - 0xff0000cc, // blue - 0xffcc00cc, // purple - 0xff00cccc, // cyan - 0xffcccccc, // light grey - 0xff444444, // dark grey - 0xffff4444, // light red - 0xff44ff44, // light green - 0xffffff44, // yellow - 0xff4444ff, // light blue - 0xffff44ff, // light purple - 0xff44ffff, // light cyan - 0xffffffff, // white - 0xff000000, 0xff00005f, 0xff000087, 0xff0000af, 0xff0000d7, - 0xff0000ff, 0xff005f00, 0xff005f5f, 0xff005f87, 0xff005faf, - 0xff005fd7, 0xff005fff, 0xff008700, 0xff00875f, 0xff008787, - 0xff0087af, 0xff0087d7, 0xff0087ff, 0xff00af00, 0xff00af5f, - 0xff00af87, 0xff00afaf, 0xff00afd7, 0xff00afff, 0xff00d700, - 0xff00d75f, 0xff00d787, 0xff00d7af, 0xff00d7d7, 0xff00d7ff, - 0xff00ff00, 0xff00ff5f, 0xff00ff87, 0xff00ffaf, 0xff00ffd7, - 0xff00ffff, 0xff5f0000, 0xff5f005f, 0xff5f0087, 0xff5f00af, - 0xff5f00d7, 0xff5f00ff, 0xff5f5f00, 0xff5f5f5f, 0xff5f5f87, - 0xff5f5faf, 0xff5f5fd7, 0xff5f5fff, 0xff5f8700, 0xff5f875f, - 0xff5f8787, 0xff5f87af, 0xff5f87d7, 0xff5f87ff, 0xff5faf00, - 0xff5faf5f, 0xff5faf87, 0xff5fafaf, 0xff5fafd7, 0xff5fafff, - 0xff5fd700, 0xff5fd75f, 0xff5fd787, 0xff5fd7af, 0xff5fd7d7, - 0xff5fd7ff, 0xff5fff00, 0xff5fff5f, 0xff5fff87, 0xff5fffaf, - 0xff5fffd7, 0xff5fffff, 0xff870000, 0xff87005f, 0xff870087, - 0xff8700af, 0xff8700d7, 0xff8700ff, 0xff875f00, 0xff875f5f, - 0xff875f87, 0xff875faf, 0xff875fd7, 0xff875fff, 0xff878700, - 0xff87875f, 0xff878787, 0xff8787af, 0xff8787d7, 0xff8787ff, - 0xff87af00, 0xff87af5f, 0xff87af87, 0xff87afaf, 0xff87afd7, - 0xff87afff, 0xff87d700, 0xff87d75f, 0xff87d787, 0xff87d7af, - 0xff87d7d7, 0xff87d7ff, 0xff87ff00, 0xff87ff5f, 0xff87ff87, - 0xff87ffaf, 0xff87ffd7, 0xff87ffff, 0xffaf0000, 0xffaf005f, - 0xffaf0087, 0xffaf00af, 0xffaf00d7, 0xffaf00ff, 0xffaf5f00, - 0xffaf5f5f, 0xffaf5f87, 0xffaf5faf, 0xffaf5fd7, 0xffaf5fff, - 0xffaf8700, 0xffaf875f, 0xffaf8787, 0xffaf87af, 0xffaf87d7, - 0xffaf87ff, 0xffafaf00, 0xffafaf5f, 0xffafaf87, 0xffafafaf, - 0xffafafd7, 0xffafafff, 0xffafd700, 0xffafd75f, 0xffafd787, - 0xffafd7af, 0xffafd7d7, 0xffafd7ff, 0xffafff00, 0xffafff5f, - 0xffafff87, 0xffafffaf, 0xffafffd7, 0xffafffff, 0xffd70000, - 0xffd7005f, 0xffd70087, 0xffd700af, 0xffd700d7, 0xffd700ff, - 0xffd75f00, 0xffd75f5f, 0xffd75f87, 0xffd75faf, 0xffd75fd7, - 0xffd75fff, 0xffd78700, 0xffd7875f, 0xffd78787, 0xffd787af, - 0xffd787d7, 0xffd787ff, 0xffd7af00, 0xffd7af5f, 0xffd7af87, - 0xffd7afaf, 0xffd7afd7, 0xffd7afff, 0xffd7d700, 0xffd7d75f, - 0xffd7d787, 0xffd7d7af, 0xffd7d7d7, 0xffd7d7ff, 0xffd7ff00, - 0xffd7ff5f, 0xffd7ff87, 0xffd7ffaf, 0xffd7ffd7, 0xffd7ffff, - 0xffff0000, 0xffff005f, 0xffff0087, 0xffff00af, 0xffff00d7, - 0xffff00ff, 0xffff5f00, 0xffff5f5f, 0xffff5f87, 0xffff5faf, - 0xffff5fd7, 0xffff5fff, 0xffff8700, 0xffff875f, 0xffff8787, - 0xffff87af, 0xffff87d7, 0xffff87ff, 0xffffaf00, 0xffffaf5f, - 0xffffaf87, 0xffffafaf, 0xffffafd7, 0xffffafff, 0xffffd700, - 0xffffd75f, 0xffffd787, 0xffffd7af, 0xffffd7d7, 0xffffd7ff, - 0xffffff00, 0xffffff5f, 0xffffff87, 0xffffffaf, 0xffffffd7, - 0xffffffff, 0xff080808, 0xff121212, 0xff1c1c1c, 0xff262626, - 0xff303030, 0xff3a3a3a, 0xff444444, 0xff4e4e4e, 0xff585858, - 0xff626262, 0xff6c6c6c, 0xff767676, 0xff808080, 0xff8a8a8a, - 0xff949494, 0xff9e9e9e, 0xffa8a8a8, 0xffb2b2b2, 0xffbcbcbc, - 0xffc6c6c6, 0xffd0d0d0, 0xffdadada, 0xffe4e4e4, 0xffeeeeee, - }; -} diff --git a/src/org/connectbot/util/EastAsianWidth.java b/src/org/connectbot/util/EastAsianWidth.java deleted file mode 100644 index 0e274b5..0000000 --- a/src/org/connectbot/util/EastAsianWidth.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import android.graphics.Paint; -import android.text.AndroidCharacter; - -/** - * @author Kenny Root - * - */ -public abstract class EastAsianWidth { - public static EastAsianWidth getInstance() { - if (PreferenceConstants.PRE_FROYO) - return PreFroyo.Holder.sInstance; - else - return FroyoAndBeyond.Holder.sInstance; - } - - /** - * @param charArray - * @param i - * @param position - * @param wideAttribute - */ - public abstract void measure(char[] charArray, int start, int end, - byte[] wideAttribute, Paint paint, int charWidth); - - private static class PreFroyo extends EastAsianWidth { - private static final int BUFFER_SIZE = 4096; - private float[] mWidths = new float[BUFFER_SIZE]; - - private static class Holder { - private static final PreFroyo sInstance = new PreFroyo(); - } - - @Override - public void measure(char[] charArray, int start, int end, - byte[] wideAttribute, Paint paint, int charWidth) { - paint.getTextWidths(charArray, start, end, mWidths); - final int N = end - start; - for (int i = 0; i < N; i++) - wideAttribute[i] = (byte) (((int)mWidths[i] != charWidth) ? - AndroidCharacter.EAST_ASIAN_WIDTH_WIDE : - AndroidCharacter.EAST_ASIAN_WIDTH_NARROW); - } - } - - private static class FroyoAndBeyond extends EastAsianWidth { - private static class Holder { - private static final FroyoAndBeyond sInstance = new FroyoAndBeyond(); - } - - @Override - public void measure(char[] charArray, int start, int end, - byte[] wideAttribute, Paint paint, int charWidth) { - AndroidCharacter.getEastAsianWidths(charArray, start, end - start, wideAttribute); - } - } -} diff --git a/src/org/connectbot/util/Encryptor.java b/src/org/connectbot/util/Encryptor.java deleted file mode 100644 index 9d21454..0000000 --- a/src/org/connectbot/util/Encryptor.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -/** - * This class is from: - * - * Encryptor.java - * Copyright 2008 Zach Scrivena - * zachscrivena@gmail.com - * http://zs.freeshell.org/ - */ - -import java.security.MessageDigest; -import java.security.SecureRandom; -import java.util.Arrays; - -import javax.crypto.Cipher; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - - -/** - * Perform AES-128 encryption. - */ -public final class Encryptor -{ - /** name of the character set to use for converting between characters and bytes */ - private static final String CHARSET_NAME = "UTF-8"; - - /** random number generator algorithm */ - private static final String RNG_ALGORITHM = "SHA1PRNG"; - - /** message digest algorithm (must be sufficiently long to provide the key and initialization vector) */ - private static final String DIGEST_ALGORITHM = "SHA-256"; - - /** key algorithm (must be compatible with CIPHER_ALGORITHM) */ - private static final String KEY_ALGORITHM = "AES"; - - /** cipher algorithm (must be compatible with KEY_ALGORITHM) */ - private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding"; - - - /** - * Private constructor that should never be called. - */ - private Encryptor() - {} - - - /** - * Encrypt the specified cleartext using the given password. - * With the correct salt, number of iterations, and password, the decrypt() method reverses - * the effect of this method. - * This method generates and uses a random salt, and the user-specified number of iterations - * and password to create a 16-byte secret key and 16-byte initialization vector. - * The secret key and initialization vector are then used in the AES-128 cipher to encrypt - * the given cleartext. - * - * @param salt - * salt that was used in the encryption (to be populated) - * @param iterations - * number of iterations to use in salting - * @param password - * password to be used for encryption - * @param cleartext - * cleartext to be encrypted - * @return - * ciphertext - * @throws Exception - * on any error encountered in encryption - */ - public static byte[] encrypt( - final byte[] salt, - final int iterations, - final String password, - final byte[] cleartext) - throws Exception - { - /* generate salt randomly */ - SecureRandom.getInstance(RNG_ALGORITHM).nextBytes(salt); - - /* compute key and initialization vector */ - final MessageDigest shaDigest = MessageDigest.getInstance(DIGEST_ALGORITHM); - byte[] pw = password.getBytes(CHARSET_NAME); - - for (int i = 0; i < iterations; i++) - { - /* add salt */ - final byte[] salted = new byte[pw.length + salt.length]; - System.arraycopy(pw, 0, salted, 0, pw.length); - System.arraycopy(salt, 0, salted, pw.length, salt.length); - Arrays.fill(pw, (byte) 0x00); - - /* compute SHA-256 digest */ - shaDigest.reset(); - pw = shaDigest.digest(salted); - Arrays.fill(salted, (byte) 0x00); - } - - /* extract the 16-byte key and initialization vector from the SHA-256 digest */ - final byte[] key = new byte[16]; - final byte[] iv = new byte[16]; - System.arraycopy(pw, 0, key, 0, 16); - System.arraycopy(pw, 16, iv, 0, 16); - Arrays.fill(pw, (byte) 0x00); - - /* perform AES-128 encryption */ - final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); - - cipher.init( - Cipher.ENCRYPT_MODE, - new SecretKeySpec(key, KEY_ALGORITHM), - new IvParameterSpec(iv)); - - Arrays.fill(key, (byte) 0x00); - Arrays.fill(iv, (byte) 0x00); - - return cipher.doFinal(cleartext); - } - - - /** - * Decrypt the specified ciphertext using the given password. - * With the correct salt, number of iterations, and password, this method reverses the effect - * of the encrypt() method. - * This method uses the user-specified salt, number of iterations, and password - * to recreate the 16-byte secret key and 16-byte initialization vector. - * The secret key and initialization vector are then used in the AES-128 cipher to decrypt - * the given ciphertext. - * - * @param salt - * salt to be used in decryption - * @param iterations - * number of iterations to use in salting - * @param password - * password to be used for decryption - * @param ciphertext - * ciphertext to be decrypted - * @return - * cleartext - * @throws Exception - * on any error encountered in decryption - */ - public static byte[] decrypt( - final byte[] salt, - final int iterations, - final String password, - final byte[] ciphertext) - throws Exception - { - /* compute key and initialization vector */ - final MessageDigest shaDigest = MessageDigest.getInstance(DIGEST_ALGORITHM); - byte[] pw = password.getBytes(CHARSET_NAME); - - for (int i = 0; i < iterations; i++) - { - /* add salt */ - final byte[] salted = new byte[pw.length + salt.length]; - System.arraycopy(pw, 0, salted, 0, pw.length); - System.arraycopy(salt, 0, salted, pw.length, salt.length); - Arrays.fill(pw, (byte) 0x00); - - /* compute SHA-256 digest */ - shaDigest.reset(); - pw = shaDigest.digest(salted); - Arrays.fill(salted, (byte) 0x00); - } - - /* extract the 16-byte key and initialization vector from the SHA-256 digest */ - final byte[] key = new byte[16]; - final byte[] iv = new byte[16]; - System.arraycopy(pw, 0, key, 0, 16); - System.arraycopy(pw, 16, iv, 0, 16); - Arrays.fill(pw, (byte) 0x00); - - /* perform AES-128 decryption */ - final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); - - cipher.init( - Cipher.DECRYPT_MODE, - new SecretKeySpec(key, KEY_ALGORITHM), - new IvParameterSpec(iv)); - - Arrays.fill(key, (byte) 0x00); - Arrays.fill(iv, (byte) 0x00); - - return cipher.doFinal(ciphertext); - } -} diff --git a/src/org/connectbot/util/EntropyDialog.java b/src/org/connectbot/util/EntropyDialog.java deleted file mode 100644 index 4498ce2..0000000 --- a/src/org/connectbot/util/EntropyDialog.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import org.connectbot.R; - -import android.app.Dialog; -import android.content.Context; -import android.view.View; - -public class EntropyDialog extends Dialog implements OnEntropyGatheredListener { - - public EntropyDialog(Context context) { - super(context); - - this.setContentView(R.layout.dia_gatherentropy); - this.setTitle(R.string.pubkey_gather_entropy); - - ((EntropyView) findViewById(R.id.entropy)).addOnEntropyGatheredListener(this); - } - - public EntropyDialog(Context context, View view) { - super(context); - - this.setContentView(view); - this.setTitle(R.string.pubkey_gather_entropy); - - ((EntropyView) findViewById(R.id.entropy)).addOnEntropyGatheredListener(this); - } - - public void onEntropyGathered(byte[] entropy) { - this.dismiss(); - } - -} diff --git a/src/org/connectbot/util/EntropyView.java b/src/org/connectbot/util/EntropyView.java deleted file mode 100644 index c988673..0000000 --- a/src/org/connectbot/util/EntropyView.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import java.util.Vector; - -import org.connectbot.R; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Typeface; -import android.graphics.Paint.FontMetrics; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -public class EntropyView extends View { - private static final int SHA1_MAX_BYTES = 20; - private static final int MILLIS_BETWEEN_INPUTS = 50; - - private Paint mPaint; - private FontMetrics mFontMetrics; - private boolean mFlipFlop; - private long mLastTime; - private Vector<OnEntropyGatheredListener> listeners; - - private byte[] mEntropy; - private int mEntropyByteIndex; - private int mEntropyBitIndex; - - private int splitText = 0; - - private float lastX = 0.0f, lastY = 0.0f; - - public EntropyView(Context context) { - super(context); - - setUpEntropy(); - } - - public EntropyView(Context context, AttributeSet attrs) { - super(context, attrs); - - setUpEntropy(); - } - - private void setUpEntropy() { - mPaint = new Paint(); - mPaint.setAntiAlias(true); - mPaint.setTypeface(Typeface.DEFAULT); - mPaint.setTextAlign(Paint.Align.CENTER); - mPaint.setTextSize(16); - mPaint.setColor(Color.WHITE); - mFontMetrics = mPaint.getFontMetrics(); - - mEntropy = new byte[SHA1_MAX_BYTES]; - mEntropyByteIndex = 0; - mEntropyBitIndex = 0; - - listeners = new Vector<OnEntropyGatheredListener>(); - } - - public void addOnEntropyGatheredListener(OnEntropyGatheredListener listener) { - listeners.add(listener); - } - - public void removeOnEntropyGatheredListener(OnEntropyGatheredListener listener) { - listeners.remove(listener); - } - - @Override - public void onDraw(Canvas c) { - String prompt = String.format(getResources().getString(R.string.pubkey_touch_prompt), - (int)(100.0 * (mEntropyByteIndex / 20.0)) + (int)(5.0 * (mEntropyBitIndex / 8.0))); - if (splitText > 0 || - mPaint.measureText(prompt) > (getWidth() * 0.8)) { - if (splitText == 0) - splitText = prompt.indexOf(" ", prompt.length() / 2); - - c.drawText(prompt.substring(0, splitText), - getWidth() / 2.0f, - getHeight() / 2.0f + (mPaint.ascent() + mPaint.descent()), - mPaint); - c.drawText(prompt.substring(splitText), - getWidth() / 2.0f, - getHeight() / 2.0f - (mPaint.ascent() + mPaint.descent()), - mPaint); - } else { - c.drawText(prompt, - getWidth() / 2.0f, - getHeight() / 2.0f - (mFontMetrics.ascent + mFontMetrics.descent) / 2, - mPaint); - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (mEntropyByteIndex >= SHA1_MAX_BYTES - || lastX == event.getX() - || lastY == event.getY()) - return true; - - // Only get entropy every 200 milliseconds to ensure the user has moved around. - long now = System.currentTimeMillis(); - if ((now - mLastTime) < MILLIS_BETWEEN_INPUTS) - return true; - else - mLastTime = now; - - byte input; - - lastX = event.getX(); - lastY = event.getY(); - - // Get the lowest 4 bits of each X, Y input and concat to the entropy-gathering - // string. - if (mFlipFlop) - input = (byte)((((int)lastX & 0x0F) << 4) | ((int)lastY & 0x0F)); - else - input = (byte)((((int)lastY & 0x0F) << 4) | ((int)lastX & 0x0F)); - mFlipFlop = !mFlipFlop; - - for (int i = 0; i < 4 && mEntropyByteIndex < SHA1_MAX_BYTES; i++) { - if ((input & 0x3) == 0x1) { - mEntropy[mEntropyByteIndex] <<= 1; - mEntropy[mEntropyByteIndex] |= 1; - mEntropyBitIndex++; - input >>= 2; - } else if ((input & 0x3) == 0x2) { - mEntropy[mEntropyByteIndex] <<= 1; - mEntropyBitIndex++; - input >>= 2; - } - - if (mEntropyBitIndex >= 8) { - mEntropyBitIndex = 0; - mEntropyByteIndex++; - } - } - - // SHA1PRNG only keeps 160 bits of entropy. - if (mEntropyByteIndex >= SHA1_MAX_BYTES) { - for (OnEntropyGatheredListener listener: listeners) { - listener.onEntropyGathered(mEntropy); - } - } - - invalidate(); - - return true; - } -} diff --git a/src/org/connectbot/util/HelpTopicView.java b/src/org/connectbot/util/HelpTopicView.java deleted file mode 100644 index 0cbc267..0000000 --- a/src/org/connectbot/util/HelpTopicView.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import org.connectbot.HelpActivity; - -import android.content.Context; -import android.util.AttributeSet; -import android.webkit.WebSettings; -import android.webkit.WebView; - -/** - * @author Kenny Root - * - */ -public class HelpTopicView extends WebView { - public HelpTopicView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initialize(); - } - - public HelpTopicView(Context context, AttributeSet attrs) { - super(context, attrs); - initialize(); - } - - public HelpTopicView(Context context) { - super(context); - initialize(); - } - - private void initialize() { - WebSettings wSet = getSettings(); - wSet.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS); - wSet.setUseWideViewPort(false); - } - - public HelpTopicView setTopic(String topic) { - String path = String.format("file:///android_asset/%s/%s%s", - HelpActivity.HELPDIR, topic, HelpActivity.SUFFIX); - loadUrl(path); - - computeScroll(); - - return this; - } -} diff --git a/src/org/connectbot/util/HostDatabase.java b/src/org/connectbot/util/HostDatabase.java deleted file mode 100644 index 2a92bab..0000000 --- a/src/org/connectbot/util/HostDatabase.java +++ /dev/null @@ -1,766 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import java.nio.charset.Charset; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.connectbot.bean.HostBean; -import org.connectbot.bean.PortForwardBean; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.util.Log; - -import com.trilead.ssh2.KnownHosts; - -/** - * Contains information about various SSH hosts, include public hostkey if known - * from previous sessions. - * - * @author jsharkey - */ -public class HostDatabase extends RobustSQLiteOpenHelper { - - public final static String TAG = "ConnectBot.HostDatabase"; - - public final static String DB_NAME = "hosts"; - public final static int DB_VERSION = 22; - - public final static String TABLE_HOSTS = "hosts"; - public final static String FIELD_HOST_NICKNAME = "nickname"; - public final static String FIELD_HOST_PROTOCOL = "protocol"; - public final static String FIELD_HOST_USERNAME = "username"; - public final static String FIELD_HOST_HOSTNAME = "hostname"; - public final static String FIELD_HOST_PORT = "port"; - public final static String FIELD_HOST_HOSTKEYALGO = "hostkeyalgo"; - public final static String FIELD_HOST_HOSTKEY = "hostkey"; - public final static String FIELD_HOST_LASTCONNECT = "lastconnect"; - public final static String FIELD_HOST_COLOR = "color"; - public final static String FIELD_HOST_USEKEYS = "usekeys"; - public final static String FIELD_HOST_USEAUTHAGENT = "useauthagent"; - public final static String FIELD_HOST_POSTLOGIN = "postlogin"; - public final static String FIELD_HOST_PUBKEYID = "pubkeyid"; - public final static String FIELD_HOST_WANTSESSION = "wantsession"; - public final static String FIELD_HOST_DELKEY = "delkey"; - public final static String FIELD_HOST_FONTSIZE = "fontsize"; - public final static String FIELD_HOST_COMPRESSION = "compression"; - public final static String FIELD_HOST_ENCODING = "encoding"; - public final static String FIELD_HOST_STAYCONNECTED = "stayconnected"; - - public final static String TABLE_PORTFORWARDS = "portforwards"; - public final static String FIELD_PORTFORWARD_HOSTID = "hostid"; - public final static String FIELD_PORTFORWARD_NICKNAME = "nickname"; - public final static String FIELD_PORTFORWARD_TYPE = "type"; - public final static String FIELD_PORTFORWARD_SOURCEPORT = "sourceport"; - public final static String FIELD_PORTFORWARD_DESTADDR = "destaddr"; - public final static String FIELD_PORTFORWARD_DESTPORT = "destport"; - - public final static String TABLE_COLORS = "colors"; - public final static String FIELD_COLOR_SCHEME = "scheme"; - public final static String FIELD_COLOR_NUMBER = "number"; - public final static String FIELD_COLOR_VALUE = "value"; - - public final static String TABLE_COLOR_DEFAULTS = "colorDefaults"; - public final static String FIELD_COLOR_FG = "fg"; - public final static String FIELD_COLOR_BG = "bg"; - - public final static int DEFAULT_FG_COLOR = 7; - public final static int DEFAULT_BG_COLOR = 0; - - public final static String COLOR_RED = "red"; - public final static String COLOR_GREEN = "green"; - public final static String COLOR_BLUE = "blue"; - public final static String COLOR_GRAY = "gray"; - - public final static String PORTFORWARD_LOCAL = "local"; - public final static String PORTFORWARD_REMOTE = "remote"; - public final static String PORTFORWARD_DYNAMIC4 = "dynamic4"; - public final static String PORTFORWARD_DYNAMIC5 = "dynamic5"; - - public final static String DELKEY_DEL = "del"; - public final static String DELKEY_BACKSPACE = "backspace"; - - public final static String AUTHAGENT_NO = "no"; - public final static String AUTHAGENT_CONFIRM = "confirm"; - public final static String AUTHAGENT_YES = "yes"; - - public final static String ENCODING_DEFAULT = Charset.defaultCharset().name(); - - public final static long PUBKEYID_NEVER = -2; - public final static long PUBKEYID_ANY = -1; - - public static final int DEFAULT_COLOR_SCHEME = 0; - - // Table creation strings - public static final String CREATE_TABLE_COLOR_DEFAULTS = - "CREATE TABLE " + TABLE_COLOR_DEFAULTS - + " (" + FIELD_COLOR_SCHEME + " INTEGER NOT NULL, " - + FIELD_COLOR_FG + " INTEGER NOT NULL DEFAULT " + DEFAULT_FG_COLOR + ", " - + FIELD_COLOR_BG + " INTEGER NOT NULL DEFAULT " + DEFAULT_BG_COLOR + ")"; - public static final String CREATE_TABLE_COLOR_DEFAULTS_INDEX = - "CREATE INDEX " + TABLE_COLOR_DEFAULTS + FIELD_COLOR_SCHEME + "index ON " - + TABLE_COLOR_DEFAULTS + " (" + FIELD_COLOR_SCHEME + ");"; - - private static final String WHERE_SCHEME_AND_COLOR = FIELD_COLOR_SCHEME + " = ? AND " - + FIELD_COLOR_NUMBER + " = ?"; - - static { - addTableName(TABLE_HOSTS); - addTableName(TABLE_PORTFORWARDS); - addIndexName(TABLE_PORTFORWARDS + FIELD_PORTFORWARD_HOSTID + "index"); - addTableName(TABLE_COLORS); - addIndexName(TABLE_COLORS + FIELD_COLOR_SCHEME + "index"); - addTableName(TABLE_COLOR_DEFAULTS); - addIndexName(TABLE_COLOR_DEFAULTS + FIELD_COLOR_SCHEME + "index"); - } - - public static final Object[] dbLock = new Object[0]; - - public HostDatabase(Context context) { - super(context, DB_NAME, null, DB_VERSION); - - getWritableDatabase().close(); - } - - @Override - public void onCreate(SQLiteDatabase db) { - super.onCreate(db); - - db.execSQL("CREATE TABLE " + TABLE_HOSTS - + " (_id INTEGER PRIMARY KEY, " - + FIELD_HOST_NICKNAME + " TEXT, " - + FIELD_HOST_PROTOCOL + " TEXT DEFAULT 'ssh', " - + FIELD_HOST_USERNAME + " TEXT, " - + FIELD_HOST_HOSTNAME + " TEXT, " - + FIELD_HOST_PORT + " INTEGER, " - + FIELD_HOST_HOSTKEYALGO + " TEXT, " - + FIELD_HOST_HOSTKEY + " BLOB, " - + FIELD_HOST_LASTCONNECT + " INTEGER, " - + FIELD_HOST_COLOR + " TEXT, " - + FIELD_HOST_USEKEYS + " TEXT, " - + FIELD_HOST_USEAUTHAGENT + " TEXT, " - + FIELD_HOST_POSTLOGIN + " TEXT, " - + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY + ", " - + FIELD_HOST_DELKEY + " TEXT DEFAULT '" + DELKEY_DEL + "', " - + FIELD_HOST_FONTSIZE + " INTEGER, " - + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "', " - + FIELD_HOST_COMPRESSION + " TEXT DEFAULT '" + Boolean.toString(false) + "', " - + FIELD_HOST_ENCODING + " TEXT DEFAULT '" + ENCODING_DEFAULT + "', " - + FIELD_HOST_STAYCONNECTED + " TEXT)"); - - db.execSQL("CREATE TABLE " + TABLE_PORTFORWARDS - + " (_id INTEGER PRIMARY KEY, " - + FIELD_PORTFORWARD_HOSTID + " INTEGER, " - + FIELD_PORTFORWARD_NICKNAME + " TEXT, " - + FIELD_PORTFORWARD_TYPE + " TEXT NOT NULL DEFAULT " + PORTFORWARD_LOCAL + ", " - + FIELD_PORTFORWARD_SOURCEPORT + " INTEGER NOT NULL DEFAULT 8080, " - + FIELD_PORTFORWARD_DESTADDR + " TEXT, " - + FIELD_PORTFORWARD_DESTPORT + " TEXT)"); - - db.execSQL("CREATE INDEX " + TABLE_PORTFORWARDS + FIELD_PORTFORWARD_HOSTID + "index ON " - + TABLE_PORTFORWARDS + " (" + FIELD_PORTFORWARD_HOSTID + ");"); - - db.execSQL("CREATE TABLE " + TABLE_COLORS - + " (_id INTEGER PRIMARY KEY, " - + FIELD_COLOR_NUMBER + " INTEGER, " - + FIELD_COLOR_VALUE + " INTEGER, " - + FIELD_COLOR_SCHEME + " INTEGER)"); - - db.execSQL("CREATE INDEX " + TABLE_COLORS + FIELD_COLOR_SCHEME + "index ON " - + TABLE_COLORS + " (" + FIELD_COLOR_SCHEME + ");"); - - db.execSQL(CREATE_TABLE_COLOR_DEFAULTS); - db.execSQL(CREATE_TABLE_COLOR_DEFAULTS_INDEX); - } - - @Override - public void onRobustUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) throws SQLiteException { - // Versions of the database before the Android Market release will be - // shot without warning. - if (oldVersion <= 9) { - db.execSQL("DROP TABLE IF EXISTS " + TABLE_HOSTS); - onCreate(db); - return; - } - - switch (oldVersion) { - case 10: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY); - case 11: - db.execSQL("CREATE TABLE " + TABLE_PORTFORWARDS - + " (_id INTEGER PRIMARY KEY, " - + FIELD_PORTFORWARD_HOSTID + " INTEGER, " - + FIELD_PORTFORWARD_NICKNAME + " TEXT, " - + FIELD_PORTFORWARD_TYPE + " TEXT NOT NULL DEFAULT " + PORTFORWARD_LOCAL + ", " - + FIELD_PORTFORWARD_SOURCEPORT + " INTEGER NOT NULL DEFAULT 8080, " - + FIELD_PORTFORWARD_DESTADDR + " TEXT, " - + FIELD_PORTFORWARD_DESTPORT + " INTEGER)"); - case 12: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "'"); - case 13: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_COMPRESSION + " TEXT DEFAULT '" + Boolean.toString(false) + "'"); - case 14: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_ENCODING + " TEXT DEFAULT '" + ENCODING_DEFAULT + "'"); - case 15: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_PROTOCOL + " TEXT DEFAULT 'ssh'"); - case 16: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_DELKEY + " TEXT DEFAULT '" + DELKEY_DEL + "'"); - case 17: - db.execSQL("CREATE INDEX " + TABLE_PORTFORWARDS + FIELD_PORTFORWARD_HOSTID + "index ON " - + TABLE_PORTFORWARDS + " (" + FIELD_PORTFORWARD_HOSTID + ");"); - - // Add colors - db.execSQL("CREATE TABLE " + TABLE_COLORS - + " (_id INTEGER PRIMARY KEY, " - + FIELD_COLOR_NUMBER + " INTEGER, " - + FIELD_COLOR_VALUE + " INTEGER, " - + FIELD_COLOR_SCHEME + " INTEGER)"); - db.execSQL("CREATE INDEX " + TABLE_COLORS + FIELD_COLOR_SCHEME + "index ON " - + TABLE_COLORS + " (" + FIELD_COLOR_SCHEME + ");"); - case 18: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_USEAUTHAGENT + " TEXT DEFAULT '" + AUTHAGENT_NO + "'"); - case 19: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_STAYCONNECTED + " TEXT"); - case 20: - db.execSQL("ALTER TABLE " + TABLE_HOSTS - + " ADD COLUMN " + FIELD_HOST_FONTSIZE + " INTEGER"); - case 21: - db.execSQL("DROP TABLE " + TABLE_COLOR_DEFAULTS); - db.execSQL(CREATE_TABLE_COLOR_DEFAULTS); - db.execSQL(CREATE_TABLE_COLOR_DEFAULTS_INDEX); - } - } - - /** - * Touch a specific host to update its "last connected" field. - * @param nickname Nickname field of host to update - */ - public void touchHost(HostBean host) { - long now = System.currentTimeMillis() / 1000; - - ContentValues values = new ContentValues(); - values.put(FIELD_HOST_LASTCONNECT, now); - - synchronized (dbLock) { - SQLiteDatabase db = this.getWritableDatabase(); - - db.update(TABLE_HOSTS, values, "_id = ?", new String[] { String.valueOf(host.getId()) }); - } - } - - /** - * Create a new host using the given parameters. - */ - public HostBean saveHost(HostBean host) { - long id; - - synchronized (dbLock) { - SQLiteDatabase db = this.getWritableDatabase(); - - id = db.insert(TABLE_HOSTS, null, host.getValues()); - } - - host.setId(id); - - return host; - } - - /** - * Update a field in a host record. - */ - public boolean updateFontSize(HostBean host) { - long id = host.getId(); - if (id < 0) - return false; - - ContentValues updates = new ContentValues(); - updates.put(FIELD_HOST_FONTSIZE, host.getFontSize()); - - synchronized (dbLock) { - SQLiteDatabase db = getWritableDatabase(); - - db.update(TABLE_HOSTS, updates, "_id = ?", - new String[] { String.valueOf(id) }); - - } - - return true; - } - - /** - * Delete a specific host by its <code>_id</code> value. - */ - public void deleteHost(HostBean host) { - if (host.getId() < 0) - return; - - synchronized (dbLock) { - SQLiteDatabase db = this.getWritableDatabase(); - db.delete(TABLE_HOSTS, "_id = ?", new String[] { String.valueOf(host.getId()) }); - } - } - - /** - * Return a cursor that contains information about all known hosts. - * @param sortColors If true, sort by color, otherwise sort by nickname. - */ - public List<HostBean> getHosts(boolean sortColors) { - String sortField = sortColors ? FIELD_HOST_COLOR : FIELD_HOST_NICKNAME; - List<HostBean> hosts; - - synchronized (dbLock) { - SQLiteDatabase db = this.getReadableDatabase(); - - Cursor c = db.query(TABLE_HOSTS, null, null, null, null, null, sortField + " ASC"); - - hosts = createHostBeans(c); - - c.close(); - } - - return hosts; - } - - /** - * @param hosts - * @param c - */ - private List<HostBean> createHostBeans(Cursor c) { - List<HostBean> hosts = new LinkedList<HostBean>(); - - final int COL_ID = c.getColumnIndexOrThrow("_id"), - COL_NICKNAME = c.getColumnIndexOrThrow(FIELD_HOST_NICKNAME), - COL_PROTOCOL = c.getColumnIndexOrThrow(FIELD_HOST_PROTOCOL), - COL_USERNAME = c.getColumnIndexOrThrow(FIELD_HOST_USERNAME), - COL_HOSTNAME = c.getColumnIndexOrThrow(FIELD_HOST_HOSTNAME), - COL_PORT = c.getColumnIndexOrThrow(FIELD_HOST_PORT), - COL_LASTCONNECT = c.getColumnIndexOrThrow(FIELD_HOST_LASTCONNECT), - COL_COLOR = c.getColumnIndexOrThrow(FIELD_HOST_COLOR), - COL_USEKEYS = c.getColumnIndexOrThrow(FIELD_HOST_USEKEYS), - COL_USEAUTHAGENT = c.getColumnIndexOrThrow(FIELD_HOST_USEAUTHAGENT), - COL_POSTLOGIN = c.getColumnIndexOrThrow(FIELD_HOST_POSTLOGIN), - COL_PUBKEYID = c.getColumnIndexOrThrow(FIELD_HOST_PUBKEYID), - COL_WANTSESSION = c.getColumnIndexOrThrow(FIELD_HOST_WANTSESSION), - COL_DELKEY = c.getColumnIndexOrThrow(FIELD_HOST_DELKEY), - COL_FONTSIZE = c.getColumnIndexOrThrow(FIELD_HOST_FONTSIZE), - COL_COMPRESSION = c.getColumnIndexOrThrow(FIELD_HOST_COMPRESSION), - COL_ENCODING = c.getColumnIndexOrThrow(FIELD_HOST_ENCODING), - COL_STAYCONNECTED = c.getColumnIndexOrThrow(FIELD_HOST_STAYCONNECTED); - - - while (c.moveToNext()) { - HostBean host = new HostBean(); - - host.setId(c.getLong(COL_ID)); - host.setNickname(c.getString(COL_NICKNAME)); - host.setProtocol(c.getString(COL_PROTOCOL)); - host.setUsername(c.getString(COL_USERNAME)); - host.setHostname(c.getString(COL_HOSTNAME)); - host.setPort(c.getInt(COL_PORT)); - host.setLastConnect(c.getLong(COL_LASTCONNECT)); - host.setColor(c.getString(COL_COLOR)); - host.setUseKeys(Boolean.valueOf(c.getString(COL_USEKEYS))); - host.setUseAuthAgent(c.getString(COL_USEAUTHAGENT)); - host.setPostLogin(c.getString(COL_POSTLOGIN)); - host.setPubkeyId(c.getLong(COL_PUBKEYID)); - host.setWantSession(Boolean.valueOf(c.getString(COL_WANTSESSION))); - host.setDelKey(c.getString(COL_DELKEY)); - host.setFontSize(c.getInt(COL_FONTSIZE)); - host.setCompression(Boolean.valueOf(c.getString(COL_COMPRESSION))); - host.setEncoding(c.getString(COL_ENCODING)); - host.setStayConnected(Boolean.valueOf(c.getString(COL_STAYCONNECTED))); - - hosts.add(host); - } - - return hosts; - } - - /** - * @param c - * @return - */ - private HostBean getFirstHostBean(Cursor c) { - HostBean host = null; - - List<HostBean> hosts = createHostBeans(c); - if (hosts.size() > 0) - host = hosts.get(0); - - c.close(); - - return host; - } - - /** - * @param nickname - * @param protocol - * @param username - * @param hostname - * @param hostname2 - * @param port - * @return - */ - public HostBean findHost(Map<String, String> selection) { - StringBuilder selectionBuilder = new StringBuilder(); - - Iterator<Entry<String, String>> i = selection.entrySet().iterator(); - - List<String> selectionValuesList = new LinkedList<String>(); - int n = 0; - while (i.hasNext()) { - Entry<String, String> entry = i.next(); - - if (entry.getValue() == null) - continue; - - if (n++ > 0) - selectionBuilder.append(" AND "); - - selectionBuilder.append(entry.getKey()) - .append(" = ?"); - - selectionValuesList.add(entry.getValue()); - } - - String selectionValues[] = new String[selectionValuesList.size()]; - selectionValuesList.toArray(selectionValues); - selectionValuesList = null; - - HostBean host; - - synchronized (dbLock) { - SQLiteDatabase db = getReadableDatabase(); - - Cursor c = db.query(TABLE_HOSTS, null, - selectionBuilder.toString(), - selectionValues, - null, null, null); - - host = getFirstHostBean(c); - } - - return host; - } - - /** - * @param hostId - * @return - */ - public HostBean findHostById(long hostId) { - HostBean host; - - synchronized (dbLock) { - SQLiteDatabase db = getReadableDatabase(); - - Cursor c = db.query(TABLE_HOSTS, null, - "_id = ?", new String[] { String.valueOf(hostId) }, - null, null, null); - - host = getFirstHostBean(c); - } - - return host; - } - - /** - * Record the given hostkey into database under this nickname. - * @param hostname - * @param port - * @param hostkeyalgo - * @param hostkey - */ - public void saveKnownHost(String hostname, int port, String hostkeyalgo, byte[] hostkey) { - ContentValues values = new ContentValues(); - values.put(FIELD_HOST_HOSTKEYALGO, hostkeyalgo); - values.put(FIELD_HOST_HOSTKEY, hostkey); - - synchronized (dbLock) { - SQLiteDatabase db = getReadableDatabase(); - - db.update(TABLE_HOSTS, values, - FIELD_HOST_HOSTNAME + " = ? AND " + FIELD_HOST_PORT + " = ?", - new String[] { hostname, String.valueOf(port) }); - Log.d(TAG, String.format("Finished saving hostkey information for '%s'", hostname)); - } - } - - /** - * Build list of known hosts for Trilead library. - * @return - */ - public KnownHosts getKnownHosts() { - KnownHosts known = new KnownHosts(); - - synchronized (dbLock) { - SQLiteDatabase db = this.getReadableDatabase(); - Cursor c = db.query(TABLE_HOSTS, new String[] { FIELD_HOST_HOSTNAME, - FIELD_HOST_PORT, FIELD_HOST_HOSTKEYALGO, FIELD_HOST_HOSTKEY }, - null, null, null, null, null); - - if (c != null) { - int COL_HOSTNAME = c.getColumnIndexOrThrow(FIELD_HOST_HOSTNAME), - COL_PORT = c.getColumnIndexOrThrow(FIELD_HOST_PORT), - COL_HOSTKEYALGO = c.getColumnIndexOrThrow(FIELD_HOST_HOSTKEYALGO), - COL_HOSTKEY = c.getColumnIndexOrThrow(FIELD_HOST_HOSTKEY); - - while (c.moveToNext()) { - String hostname = c.getString(COL_HOSTNAME), - hostkeyalgo = c.getString(COL_HOSTKEYALGO); - int port = c.getInt(COL_PORT); - byte[] hostkey = c.getBlob(COL_HOSTKEY); - - if (hostkeyalgo == null || hostkeyalgo.length() == 0) continue; - if (hostkey == null || hostkey.length == 0) continue; - - try { - known.addHostkey(new String[] { String.format("%s:%d", hostname, port) }, hostkeyalgo, hostkey); - } catch(Exception e) { - Log.e(TAG, "Problem while adding a known host from database", e); - } - } - - c.close(); - } - } - - return known; - } - - /** - * Unset any hosts using a pubkey ID that has been deleted. - * @param pubkeyId - */ - public void stopUsingPubkey(long pubkeyId) { - if (pubkeyId < 0) return; - - ContentValues values = new ContentValues(); - values.put(FIELD_HOST_PUBKEYID, PUBKEYID_ANY); - - synchronized (dbLock) { - SQLiteDatabase db = this.getWritableDatabase(); - - db.update(TABLE_HOSTS, values, FIELD_HOST_PUBKEYID + " = ?", new String[] { String.valueOf(pubkeyId) }); - } - - Log.d(TAG, String.format("Set all hosts using pubkey id %d to -1", pubkeyId)); - } - - /* - * Methods for dealing with port forwards attached to hosts - */ - - /** - * Returns a list of all the port forwards associated with a particular host ID. - * @param host the host for which we want the port forward list - * @return port forwards associated with host ID - */ - public List<PortForwardBean> getPortForwardsForHost(HostBean host) { - List<PortForwardBean> portForwards = new LinkedList<PortForwardBean>(); - - synchronized (dbLock) { - SQLiteDatabase db = this.getReadableDatabase(); - - Cursor c = db.query(TABLE_PORTFORWARDS, new String[] { - "_id", FIELD_PORTFORWARD_NICKNAME, FIELD_PORTFORWARD_TYPE, FIELD_PORTFORWARD_SOURCEPORT, - FIELD_PORTFORWARD_DESTADDR, FIELD_PORTFORWARD_DESTPORT }, - FIELD_PORTFORWARD_HOSTID + " = ?", new String[] { String.valueOf(host.getId()) }, - null, null, null); - - while (c.moveToNext()) { - PortForwardBean pfb = new PortForwardBean( - c.getInt(0), - host.getId(), - c.getString(1), - c.getString(2), - c.getInt(3), - c.getString(4), - c.getInt(5)); - portForwards.add(pfb); - } - - c.close(); - } - - return portForwards; - } - - /** - * Update the parameters of a port forward in the database. - * @param pfb {@link PortForwardBean} to save - * @return true on success - */ - public boolean savePortForward(PortForwardBean pfb) { - boolean success = false; - - synchronized (dbLock) { - SQLiteDatabase db = getWritableDatabase(); - - if (pfb.getId() < 0) { - long id = db.insert(TABLE_PORTFORWARDS, null, pfb.getValues()); - pfb.setId(id); - success = true; - } else { - if (db.update(TABLE_PORTFORWARDS, pfb.getValues(), "_id = ?", new String[] { String.valueOf(pfb.getId()) }) > 0) - success = true; - } - } - - return success; - } - - /** - * Deletes a port forward from the database. - * @param pfb {@link PortForwardBean} to delete - */ - public void deletePortForward(PortForwardBean pfb) { - if (pfb.getId() < 0) - return; - - synchronized (dbLock) { - SQLiteDatabase db = this.getWritableDatabase(); - db.delete(TABLE_PORTFORWARDS, "_id = ?", new String[] { String.valueOf(pfb.getId()) }); - } - } - - public Integer[] getColorsForScheme(int scheme) { - Integer[] colors = Colors.defaults.clone(); - - synchronized (dbLock) { - SQLiteDatabase db = getReadableDatabase(); - - Cursor c = db.query(TABLE_COLORS, new String[] { - FIELD_COLOR_NUMBER, FIELD_COLOR_VALUE }, - FIELD_COLOR_SCHEME + " = ?", - new String[] { String.valueOf(scheme) }, - null, null, null); - - while (c.moveToNext()) { - colors[c.getInt(0)] = new Integer(c.getInt(1)); - } - - c.close(); - } - - return colors; - } - - public void setColorForScheme(int scheme, int number, int value) { - final SQLiteDatabase db; - - final String[] whereArgs = new String[] { String.valueOf(scheme), String.valueOf(number) }; - - if (value == Colors.defaults[number]) { - synchronized (dbLock) { - db = getWritableDatabase(); - - db.delete(TABLE_COLORS, - WHERE_SCHEME_AND_COLOR, whereArgs); - } - } else { - final ContentValues values = new ContentValues(); - values.put(FIELD_COLOR_VALUE, value); - - synchronized (dbLock) { - db = getWritableDatabase(); - - final int rowsAffected = db.update(TABLE_COLORS, values, - WHERE_SCHEME_AND_COLOR, whereArgs); - - if (rowsAffected == 0) { - values.put(FIELD_COLOR_SCHEME, scheme); - values.put(FIELD_COLOR_NUMBER, number); - db.insert(TABLE_COLORS, null, values); - } - } - } - } - - public void setGlobalColor(int number, int value) { - setColorForScheme(DEFAULT_COLOR_SCHEME, number, value); - } - - public int[] getDefaultColorsForScheme(int scheme) { - int[] colors = new int[] { DEFAULT_FG_COLOR, DEFAULT_BG_COLOR }; - - synchronized (dbLock) { - SQLiteDatabase db = getReadableDatabase(); - - Cursor c = db.query(TABLE_COLOR_DEFAULTS, - new String[] { FIELD_COLOR_FG, FIELD_COLOR_BG }, - FIELD_COLOR_SCHEME + " = ?", - new String[] { String.valueOf(scheme) }, - null, null, null); - - if (c.moveToFirst()) { - colors[0] = c.getInt(0); - colors[1] = c.getInt(1); - } - - c.close(); - } - - return colors; - } - - public int[] getGlobalDefaultColors() { - return getDefaultColorsForScheme(DEFAULT_COLOR_SCHEME); - } - - public void setDefaultColorsForScheme(int scheme, int fg, int bg) { - SQLiteDatabase db; - - String schemeWhere = null; - String[] whereArgs; - - schemeWhere = FIELD_COLOR_SCHEME + " = ?"; - whereArgs = new String[] { String.valueOf(scheme) }; - - ContentValues values = new ContentValues(); - values.put(FIELD_COLOR_FG, fg); - values.put(FIELD_COLOR_BG, bg); - - synchronized (dbLock) { - db = getWritableDatabase(); - - int rowsAffected = db.update(TABLE_COLOR_DEFAULTS, values, - schemeWhere, whereArgs); - - if (rowsAffected == 0) { - values.put(FIELD_COLOR_SCHEME, scheme); - db.insert(TABLE_COLOR_DEFAULTS, null, values); - } - } - } -} diff --git a/src/org/connectbot/util/OnDbWrittenListener.java b/src/org/connectbot/util/OnDbWrittenListener.java deleted file mode 100644 index ef33797..0000000 --- a/src/org/connectbot/util/OnDbWrittenListener.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2010 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -/** - * @author kroot - * - */ -public interface OnDbWrittenListener { - public void onDbWritten(); -} diff --git a/src/org/connectbot/util/OnEntropyGatheredListener.java b/src/org/connectbot/util/OnEntropyGatheredListener.java deleted file mode 100644 index 5debd65..0000000 --- a/src/org/connectbot/util/OnEntropyGatheredListener.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -public interface OnEntropyGatheredListener { - void onEntropyGathered(byte[] entropy); -} diff --git a/src/org/connectbot/util/PreferenceConstants.java b/src/org/connectbot/util/PreferenceConstants.java deleted file mode 100644 index e9fb06c..0000000 --- a/src/org/connectbot/util/PreferenceConstants.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import android.os.Build; - -/** - * @author Kenny Root - * - */ -public class PreferenceConstants { - public static final int SDK_INT = Integer.parseInt(Build.VERSION.SDK); - public static final boolean PRE_ECLAIR = SDK_INT < 5; - public static final boolean PRE_FROYO = SDK_INT < 8; - public static final boolean PRE_HONEYCOMB = SDK_INT < 11; - - public static final String MEMKEYS = "memkeys"; - public static final String UPDATE = "update"; - - public static final String UPDATE_DAILY = "Daily"; - public static final String UPDATE_WEEKLY = "Weekly"; - public static final String UPDATE_NEVER = "Never"; - - public static final String LAST_CHECKED = "lastchecked"; - - public static final String SCROLLBACK = "scrollback"; - - public static final String EMULATION = "emulation"; - - public static final String ROTATION = "rotation"; - - public static final String ROTATION_DEFAULT = "Default"; - public static final String ROTATION_LANDSCAPE = "Force landscape"; - public static final String ROTATION_PORTRAIT = "Force portrait"; - public static final String ROTATION_AUTOMATIC = "Automatic"; - - public static final String FULLSCREEN = "fullscreen"; - - public static final String KEYMODE = "keymode"; - - public static final String KEYMODE_RIGHT = "Use right-side keys"; - public static final String KEYMODE_LEFT = "Use left-side keys"; - - public static final String CAMERA = "camera"; - - public static final String CAMERA_CTRLA_SPACE = "Ctrl+A then Space"; - public static final String CAMERA_CTRLA = "Ctrl+A"; - public static final String CAMERA_ESC = "Esc"; - public static final String CAMERA_ESC_A = "Esc+A"; - - public static final String KEEP_ALIVE = "keepalive"; - - public static final String WIFI_LOCK = "wifilock"; - - public static final String BUMPY_ARROWS = "bumpyarrows"; - - public static final String EULA = "eula"; - - public static final String SORT_BY_COLOR = "sortByColor"; - - public static final String BELL = "bell"; - public static final String BELL_VOLUME = "bellVolume"; - public static final String BELL_VIBRATE = "bellVibrate"; - public static final String BELL_NOTIFICATION = "bellNotification"; - public static final float DEFAULT_BELL_VOLUME = 0.25f; - - public static final String CONNECTION_PERSIST = "connPersist"; - - public static final String SHIFT_FKEYS = "shiftfkeys"; - public static final String CTRL_FKEYS = "ctrlfkeys"; - public static final String VOLUME_FONT = "volumefont"; - - /* Backup identifiers */ - public static final String BACKUP_PREF_KEY = "prefs"; -} diff --git a/src/org/connectbot/util/PubkeyDatabase.java b/src/org/connectbot/util/PubkeyDatabase.java deleted file mode 100644 index a8993cb..0000000 --- a/src/org/connectbot/util/PubkeyDatabase.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import java.util.LinkedList; -import java.util.List; - -import org.connectbot.bean.PubkeyBean; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; - -/** - * Public Key Encryption database. Contains private and public key pairs - * for public key authentication. - * - * @author Kenny Root - */ -public class PubkeyDatabase extends RobustSQLiteOpenHelper { - public final static String TAG = "ConnectBot.PubkeyDatabase"; - - public final static String DB_NAME = "pubkeys"; - public final static int DB_VERSION = 2; - - public final static String TABLE_PUBKEYS = "pubkeys"; - public final static String FIELD_PUBKEY_NICKNAME = "nickname"; - public final static String FIELD_PUBKEY_TYPE = "type"; - public final static String FIELD_PUBKEY_PRIVATE = "private"; - public final static String FIELD_PUBKEY_PUBLIC = "public"; - public final static String FIELD_PUBKEY_ENCRYPTED = "encrypted"; - public final static String FIELD_PUBKEY_STARTUP = "startup"; - public final static String FIELD_PUBKEY_CONFIRMUSE = "confirmuse"; - public final static String FIELD_PUBKEY_LIFETIME = "lifetime"; - - public final static String KEY_TYPE_RSA = "RSA", - KEY_TYPE_DSA = "DSA", - KEY_TYPE_IMPORTED = "IMPORTED", - KEY_TYPE_EC = "EC"; - - private Context context; - - static { - addTableName(TABLE_PUBKEYS); - } - - public PubkeyDatabase(Context context) { - super(context, DB_NAME, null, DB_VERSION); - - this.context = context; - } - - @Override - public void onCreate(SQLiteDatabase db) { - super.onCreate(db); - - db.execSQL("CREATE TABLE " + TABLE_PUBKEYS - + " (_id INTEGER PRIMARY KEY, " - + FIELD_PUBKEY_NICKNAME + " TEXT, " - + FIELD_PUBKEY_TYPE + " TEXT, " - + FIELD_PUBKEY_PRIVATE + " BLOB, " - + FIELD_PUBKEY_PUBLIC + " BLOB, " - + FIELD_PUBKEY_ENCRYPTED + " INTEGER, " - + FIELD_PUBKEY_STARTUP + " INTEGER, " - + FIELD_PUBKEY_CONFIRMUSE + " INTEGER DEFAULT 0, " - + FIELD_PUBKEY_LIFETIME + " INTEGER DEFAULT 0)"); - } - - @Override - public void onRobustUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) throws SQLiteException { - switch (oldVersion) { - case 1: - db.execSQL("ALTER TABLE " + TABLE_PUBKEYS - + " ADD COLUMN " + FIELD_PUBKEY_CONFIRMUSE + " INTEGER DEFAULT 0"); - db.execSQL("ALTER TABLE " + TABLE_PUBKEYS - + " ADD COLUMN " + FIELD_PUBKEY_LIFETIME + " INTEGER DEFAULT 0"); - } - } - - /** - * Delete a specific host by its <code>_id</code> value. - */ - public void deletePubkey(PubkeyBean pubkey) { - HostDatabase hostdb = new HostDatabase(context); - hostdb.stopUsingPubkey(pubkey.getId()); - hostdb.close(); - - SQLiteDatabase db = getWritableDatabase(); - db.delete(TABLE_PUBKEYS, "_id = ?", new String[] { Long.toString(pubkey.getId()) }); - db.close(); - } - - /** - * Return a cursor that contains information about all known hosts. - */ - /* - public Cursor allPubkeys() { - SQLiteDatabase db = this.getReadableDatabase(); - return db.query(TABLE_PUBKEYS, new String[] { "_id", - FIELD_PUBKEY_NICKNAME, FIELD_PUBKEY_TYPE, FIELD_PUBKEY_PRIVATE, - FIELD_PUBKEY_PUBLIC, FIELD_PUBKEY_ENCRYPTED, FIELD_PUBKEY_STARTUP }, - null, null, null, null, null); - }*/ - - public List<PubkeyBean> allPubkeys() { - return getPubkeys(null, null); - } - - public List<PubkeyBean> getAllStartPubkeys() { - return getPubkeys(FIELD_PUBKEY_STARTUP + " = 1 AND " + FIELD_PUBKEY_ENCRYPTED + " = 0", null); - } - - private List<PubkeyBean> getPubkeys(String selection, String[] selectionArgs) { - SQLiteDatabase db = getReadableDatabase(); - - List<PubkeyBean> pubkeys = new LinkedList<PubkeyBean>(); - - Cursor c = db.query(TABLE_PUBKEYS, null, selection, selectionArgs, null, null, null); - - if (c != null) { - final int COL_ID = c.getColumnIndexOrThrow("_id"), - COL_NICKNAME = c.getColumnIndexOrThrow(FIELD_PUBKEY_NICKNAME), - COL_TYPE = c.getColumnIndexOrThrow(FIELD_PUBKEY_TYPE), - COL_PRIVATE = c.getColumnIndexOrThrow(FIELD_PUBKEY_PRIVATE), - COL_PUBLIC = c.getColumnIndexOrThrow(FIELD_PUBKEY_PUBLIC), - COL_ENCRYPTED = c.getColumnIndexOrThrow(FIELD_PUBKEY_ENCRYPTED), - COL_STARTUP = c.getColumnIndexOrThrow(FIELD_PUBKEY_STARTUP), - COL_CONFIRMUSE = c.getColumnIndexOrThrow(FIELD_PUBKEY_CONFIRMUSE), - COL_LIFETIME = c.getColumnIndexOrThrow(FIELD_PUBKEY_LIFETIME); - - while (c.moveToNext()) { - PubkeyBean pubkey = new PubkeyBean(); - - pubkey.setId(c.getLong(COL_ID)); - pubkey.setNickname(c.getString(COL_NICKNAME)); - pubkey.setType(c.getString(COL_TYPE)); - pubkey.setPrivateKey(c.getBlob(COL_PRIVATE)); - pubkey.setPublicKey(c.getBlob(COL_PUBLIC)); - pubkey.setEncrypted(c.getInt(COL_ENCRYPTED) > 0); - pubkey.setStartup(c.getInt(COL_STARTUP) > 0); - pubkey.setConfirmUse(c.getInt(COL_CONFIRMUSE) > 0); - pubkey.setLifetime(c.getInt(COL_LIFETIME)); - - pubkeys.add(pubkey); - } - - c.close(); - } - - db.close(); - - return pubkeys; - } - - /** - * @param hostId - * @return - */ - public PubkeyBean findPubkeyById(long pubkeyId) { - SQLiteDatabase db = getReadableDatabase(); - - Cursor c = db.query(TABLE_PUBKEYS, null, - "_id = ?", new String[] { String.valueOf(pubkeyId) }, - null, null, null); - - PubkeyBean pubkey = null; - - if (c != null) { - if (c.moveToFirst()) - pubkey = createPubkeyBean(c); - - c.close(); - } - - db.close(); - - return pubkey; - } - - private PubkeyBean createPubkeyBean(Cursor c) { - PubkeyBean pubkey = new PubkeyBean(); - - pubkey.setId(c.getLong(c.getColumnIndexOrThrow("_id"))); - pubkey.setNickname(c.getString(c.getColumnIndexOrThrow(FIELD_PUBKEY_NICKNAME))); - pubkey.setType(c.getString(c.getColumnIndexOrThrow(FIELD_PUBKEY_TYPE))); - pubkey.setPrivateKey(c.getBlob(c.getColumnIndexOrThrow(FIELD_PUBKEY_PRIVATE))); - pubkey.setPublicKey(c.getBlob(c.getColumnIndexOrThrow(FIELD_PUBKEY_PUBLIC))); - pubkey.setEncrypted(c.getInt(c.getColumnIndexOrThrow(FIELD_PUBKEY_ENCRYPTED)) > 0); - pubkey.setStartup(c.getInt(c.getColumnIndexOrThrow(FIELD_PUBKEY_STARTUP)) > 0); - pubkey.setConfirmUse(c.getInt(c.getColumnIndexOrThrow(FIELD_PUBKEY_CONFIRMUSE)) > 0); - pubkey.setLifetime(c.getInt(c.getColumnIndexOrThrow(FIELD_PUBKEY_LIFETIME))); - - return pubkey; - } - - /** - * Pull all values for a given column as a list of Strings, probably for use - * in a ListPreference. Sorted by <code>_id</code> ascending. - */ - public List<CharSequence> allValues(String column) { - List<CharSequence> list = new LinkedList<CharSequence>(); - - SQLiteDatabase db = this.getReadableDatabase(); - Cursor c = db.query(TABLE_PUBKEYS, new String[] { "_id", column }, - null, null, null, null, "_id ASC"); - - if (c != null) { - int COL = c.getColumnIndexOrThrow(column); - - while (c.moveToNext()) - list.add(c.getString(COL)); - - c.close(); - } - - db.close(); - - return list; - } - - public String getNickname(long id) { - String nickname = null; - - SQLiteDatabase db = this.getReadableDatabase(); - Cursor c = db.query(TABLE_PUBKEYS, new String[] { "_id", - FIELD_PUBKEY_NICKNAME }, "_id = ?", - new String[] { Long.toString(id) }, null, null, null); - - if (c != null) { - if (c.moveToFirst()) - nickname = c.getString(c.getColumnIndexOrThrow(FIELD_PUBKEY_NICKNAME)); - - c.close(); - } - - db.close(); - - return nickname; - } - -/* - public void setOnStart(long id, boolean onStart) { - - SQLiteDatabase db = this.getWritableDatabase(); - - ContentValues values = new ContentValues(); - values.put(FIELD_PUBKEY_STARTUP, onStart ? 1 : 0); - - db.update(TABLE_PUBKEYS, values, "_id = ?", new String[] { Long.toString(id) }); - - } - - public boolean changePassword(long id, String oldPassword, String newPassword) throws NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException { - SQLiteDatabase db = this.getWritableDatabase(); - - Cursor c = db.query(TABLE_PUBKEYS, new String[] { FIELD_PUBKEY_TYPE, - FIELD_PUBKEY_PRIVATE, FIELD_PUBKEY_ENCRYPTED }, - "_id = ?", new String[] { String.valueOf(id) }, - null, null, null); - - if (!c.moveToFirst()) - return false; - - String keyType = c.getString(0); - byte[] encPriv = c.getBlob(1); - c.close(); - - PrivateKey priv; - try { - priv = PubkeyUtils.decodePrivate(encPriv, keyType, oldPassword); - } catch (InvalidKeyException e) { - return false; - } catch (BadPaddingException e) { - return false; - } catch (InvalidKeySpecException e) { - return false; - } - - ContentValues values = new ContentValues(); - values.put(FIELD_PUBKEY_PRIVATE, PubkeyUtils.getEncodedPrivate(priv, newPassword)); - values.put(FIELD_PUBKEY_ENCRYPTED, newPassword.length() > 0 ? 1 : 0); - db.update(TABLE_PUBKEYS, values, "_id = ?", new String[] { String.valueOf(id) }); - - return true; - } - */ - - /** - * @param pubkey - */ - public PubkeyBean savePubkey(PubkeyBean pubkey) { - SQLiteDatabase db = this.getWritableDatabase(); - boolean success = false; - - ContentValues values = pubkey.getValues(); - - if (pubkey.getId() > 0) { - values.remove("_id"); - if (db.update(TABLE_PUBKEYS, values, "_id = ?", new String[] { String.valueOf(pubkey.getId()) }) > 0) - success = true; - } - - if (!success) { - long id = db.insert(TABLE_PUBKEYS, null, pubkey.getValues()); - pubkey.setId(id); - } - - db.close(); - - return pubkey; - } -} diff --git a/src/org/connectbot/util/PubkeyUtils.java b/src/org/connectbot/util/PubkeyUtils.java deleted file mode 100644 index e7922bd..0000000 --- a/src/org/connectbot/util/PubkeyUtils.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.interfaces.DSAParams; -import java.security.interfaces.DSAPrivateKey; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPrivateCrtKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.InvalidParameterSpecException; -import java.security.spec.KeySpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPublicKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.Arrays; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.EncryptedPrivateKeyInfo; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import org.keyczar.jce.EcCore; - -import android.util.Log; - -import com.trilead.ssh2.crypto.Base64; -import com.trilead.ssh2.crypto.SimpleDERReader; -import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.ECDSASHA2Verify; -import com.trilead.ssh2.signature.RSASHA1Verify; - -public class PubkeyUtils { - private static final String TAG = "PubkeyUtils"; - - public static final String PKCS8_START = "-----BEGIN PRIVATE KEY-----"; - public static final String PKCS8_END = "-----END PRIVATE KEY-----"; - - // Size in bytes of salt to use. - private static final int SALT_SIZE = 8; - - // Number of iterations for password hashing. PKCS#5 recommends 1000 - private static final int ITERATIONS = 1000; - - // Cannot be instantiated - private PubkeyUtils() { - } - - public static String formatKey(Key key){ - String algo = key.getAlgorithm(); - String fmt = key.getFormat(); - byte[] encoded = key.getEncoded(); - return "Key[algorithm=" + algo + ", format=" + fmt + - ", bytes=" + encoded.length + "]"; - } - - public static byte[] sha256(byte[] data) throws NoSuchAlgorithmException { - return MessageDigest.getInstance("SHA-256").digest(data); - } - - public static byte[] cipher(int mode, byte[] data, byte[] secret) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - SecretKeySpec secretKeySpec = new SecretKeySpec(sha256(secret), "AES"); - Cipher c = Cipher.getInstance("AES"); - c.init(mode, secretKeySpec); - return c.doFinal(data); - } - - public static byte[] encrypt(byte[] cleartext, String secret) throws Exception { - byte[] salt = new byte[SALT_SIZE]; - - byte[] ciphertext = Encryptor.encrypt(salt, ITERATIONS, secret, cleartext); - - byte[] complete = new byte[salt.length + ciphertext.length]; - - System.arraycopy(salt, 0, complete, 0, salt.length); - System.arraycopy(ciphertext, 0, complete, salt.length, ciphertext.length); - - Arrays.fill(salt, (byte) 0x00); - Arrays.fill(ciphertext, (byte) 0x00); - - return complete; - } - - public static byte[] decrypt(byte[] saltAndCiphertext, String secret) throws Exception { - try { - byte[] salt = new byte[SALT_SIZE]; - byte[] ciphertext = new byte[saltAndCiphertext.length - salt.length]; - - System.arraycopy(saltAndCiphertext, 0, salt, 0, salt.length); - System.arraycopy(saltAndCiphertext, salt.length, ciphertext, 0, ciphertext.length); - - return Encryptor.decrypt(salt, ITERATIONS, secret, ciphertext); - } catch (Exception e) { - Log.d("decrypt", "Could not decrypt with new method", e); - // We might be using the old encryption method. - return cipher(Cipher.DECRYPT_MODE, saltAndCiphertext, secret.getBytes()); - } - } - - public static byte[] getEncodedPrivate(PrivateKey pk, String secret) throws Exception { - final byte[] encoded = pk.getEncoded(); - if (secret == null || secret.length() == 0) { - return encoded; - } - return encrypt(pk.getEncoded(), secret); - } - - public static PrivateKey decodePrivate(byte[] encoded, String keyType) throws NoSuchAlgorithmException, InvalidKeySpecException { - PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encoded); - KeyFactory kf = KeyFactory.getInstance(keyType); - return kf.generatePrivate(privKeySpec); - } - - public static PrivateKey decodePrivate(byte[] encoded, String keyType, String secret) throws Exception { - if (secret != null && secret.length() > 0) - return decodePrivate(decrypt(encoded, secret), keyType); - else - return decodePrivate(encoded, keyType); - } - - public static PublicKey decodePublic(byte[] encoded, String keyType) throws NoSuchAlgorithmException, InvalidKeySpecException { - X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encoded); - KeyFactory kf = KeyFactory.getInstance(keyType); - return kf.generatePublic(pubKeySpec); - } - - static String getAlgorithmForOid(String oid) throws NoSuchAlgorithmException { - if ("1.2.840.10045.2.1".equals(oid)) { - return "EC"; - } else if ("1.2.840.113549.1.1.1".equals(oid)) { - return "RSA"; - } else if ("1.2.840.10040.4.1".equals(oid)) { - return "DSA"; - } else { - throw new NoSuchAlgorithmException("Unknown algorithm OID " + oid); - } - } - - static String getOidFromPkcs8Encoded(byte[] encoded) throws NoSuchAlgorithmException { - if (encoded == null) { - throw new NoSuchAlgorithmException("encoding is null"); - } - - try { - SimpleDERReader reader = new SimpleDERReader(encoded); - reader.resetInput(reader.readSequenceAsByteArray()); - reader.readInt(); - reader.resetInput(reader.readSequenceAsByteArray()); - return reader.readOid(); - } catch (IOException e) { - Log.w(TAG, "Could not read OID", e); - throw new NoSuchAlgorithmException("Could not read key", e); - } - } - - public static KeyPair recoverKeyPair(byte[] encoded) throws NoSuchAlgorithmException, - InvalidKeySpecException { - final String algo = getAlgorithmForOid(getOidFromPkcs8Encoded(encoded)); - - final KeySpec privKeySpec = new PKCS8EncodedKeySpec(encoded); - - final KeyFactory kf = KeyFactory.getInstance(algo); - final PrivateKey priv = kf.generatePrivate(privKeySpec); - - return new KeyPair(recoverPublicKey(kf, priv), priv); - } - - static PublicKey recoverPublicKey(KeyFactory kf, PrivateKey priv) - throws NoSuchAlgorithmException, InvalidKeySpecException { - if (priv instanceof RSAPrivateCrtKey) { - RSAPrivateCrtKey rsaPriv = (RSAPrivateCrtKey) priv; - return kf.generatePublic(new RSAPublicKeySpec(rsaPriv.getModulus(), rsaPriv - .getPublicExponent())); - } else if (priv instanceof DSAPrivateKey) { - DSAPrivateKey dsaPriv = (DSAPrivateKey) priv; - DSAParams params = dsaPriv.getParams(); - - // Calculate public key Y - BigInteger y = params.getG().modPow(dsaPriv.getX(), params.getP()); - - return kf.generatePublic(new DSAPublicKeySpec(y, params.getP(), params.getQ(), params - .getG())); - } else if (priv instanceof ECPrivateKey) { - ECPrivateKey ecPriv = (ECPrivateKey) priv; - ECParameterSpec params = ecPriv.getParams(); - - // Calculate public key Y - ECPoint generator = params.getGenerator(); - BigInteger[] wCoords = EcCore.multiplyPointA(new BigInteger[] { generator.getAffineX(), - generator.getAffineY() }, ecPriv.getS(), params); - ECPoint w = new ECPoint(wCoords[0], wCoords[1]); - - return kf.generatePublic(new ECPublicKeySpec(w, params)); - } else { - throw new NoSuchAlgorithmException("Key type must be RSA, DSA, or EC"); - } - } - - /* - * OpenSSH compatibility methods - */ - - public static String convertToOpenSSHFormat(PublicKey pk, String origNickname) throws IOException, InvalidKeyException { - String nickname = origNickname; - if (nickname == null) - nickname = "connectbot@android"; - - if (pk instanceof RSAPublicKey) { - String data = "ssh-rsa "; - data += String.valueOf(Base64.encode(RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pk))); - return data + " " + nickname; - } else if (pk instanceof DSAPublicKey) { - String data = "ssh-dss "; - data += String.valueOf(Base64.encode(DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pk))); - return data + " " + nickname; - } else if (pk instanceof ECPublicKey) { - ECPublicKey ecPub = (ECPublicKey) pk; - String keyType = ECDSASHA2Verify.getCurveName(ecPub.getParams().getCurve().getField().getFieldSize()); - String keyData = String.valueOf(Base64.encode(ECDSASHA2Verify.encodeSSHECDSAPublicKey(ecPub))); - return ECDSASHA2Verify.ECDSA_SHA2_PREFIX + keyType + " " + keyData + " " + nickname; - } - - throw new InvalidKeyException("Unknown key type"); - } - - /* - * OpenSSH compatibility methods - */ - - /** - * @param trileadKey - * @return OpenSSH-encoded pubkey - */ - public static byte[] extractOpenSSHPublic(KeyPair pair) { - try { - PublicKey pubKey = pair.getPublic(); - if (pubKey instanceof RSAPublicKey) { - return RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pair.getPublic()); - } else if (pubKey instanceof DSAPublicKey) { - return DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pair.getPublic()); - } else if (pubKey instanceof ECPublicKey) { - return ECDSASHA2Verify.encodeSSHECDSAPublicKey((ECPublicKey) pair.getPublic()); - } else { - return null; - } - } catch (IOException e) { - return null; - } - } - - public static String exportPEM(PrivateKey key, String secret) throws NoSuchAlgorithmException, InvalidParameterSpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, InvalidKeySpecException, IllegalBlockSizeException, IOException { - StringBuilder sb = new StringBuilder(); - - byte[] data = key.getEncoded(); - - sb.append(PKCS8_START); - sb.append('\n'); - - if (secret != null) { - byte[] salt = new byte[8]; - SecureRandom random = new SecureRandom(); - random.nextBytes(salt); - - PBEParameterSpec defParams = new PBEParameterSpec(salt, 1); - AlgorithmParameters params = AlgorithmParameters.getInstance(key.getAlgorithm()); - - params.init(defParams); - - PBEKeySpec pbeSpec = new PBEKeySpec(secret.toCharArray()); - - SecretKeyFactory keyFact = SecretKeyFactory.getInstance(key.getAlgorithm()); - Cipher cipher = Cipher.getInstance(key.getAlgorithm()); - cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), params); - - byte[] wrappedKey = cipher.wrap(key); - - EncryptedPrivateKeyInfo pinfo = new EncryptedPrivateKeyInfo(params, wrappedKey); - - data = pinfo.getEncoded(); - - sb.append("Proc-Type: 4,ENCRYPTED\n"); - sb.append("DEK-Info: DES-EDE3-CBC,"); - sb.append(encodeHex(salt)); - sb.append("\n\n"); - } - - int i = sb.length(); - sb.append(Base64.encode(data)); - for (i += 63; i < sb.length(); i += 64) { - sb.insert(i, "\n"); - } - - sb.append('\n'); - sb.append(PKCS8_END); - sb.append('\n'); - - return sb.toString(); - } - - private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', - '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - protected static String encodeHex(byte[] bytes) { - final char[] hex = new char[bytes.length * 2]; - - int i = 0; - for (byte b : bytes) { - hex[i++] = HEX_DIGITS[(b >> 4) & 0x0f]; - hex[i++] = HEX_DIGITS[b & 0x0f]; - } - - return String.valueOf(hex); - } -} diff --git a/src/org/connectbot/util/RobustSQLiteOpenHelper.java b/src/org/connectbot/util/RobustSQLiteOpenHelper.java deleted file mode 100644 index abdd991..0000000 --- a/src/org/connectbot/util/RobustSQLiteOpenHelper.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import java.util.LinkedList; -import java.util.List; - -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteException; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteDatabase.CursorFactory; - -/** - * @author Kenny Root - * - */ -public abstract class RobustSQLiteOpenHelper extends SQLiteOpenHelper { - private static List<String> mTableNames = new LinkedList<String>(); - private static List<String> mIndexNames = new LinkedList<String>(); - - public RobustSQLiteOpenHelper(Context context, String name, - CursorFactory factory, int version) { - super(context, name, factory, version); - } - - protected static void addTableName(String tableName) { - mTableNames.add(tableName); - } - - protected static void addIndexName(String indexName) { - mIndexNames.add(indexName); - } - - @Override - public void onCreate(SQLiteDatabase db) { - dropAllTables(db); - } - - @Override - public final void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - try { - onRobustUpgrade(db, oldVersion, newVersion); - } catch (SQLiteException e) { - // The database has entered an unknown state. Try to recover. - try { - regenerateTables(db); - } catch (SQLiteException e2) { - dropAndCreateTables(db); - } - } - } - - public abstract void onRobustUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) throws SQLiteException; - - private void regenerateTables(SQLiteDatabase db) { - dropAllTablesWithPrefix(db, "OLD_"); - - for (String tableName : mTableNames) - db.execSQL("ALTER TABLE " + tableName + " RENAME TO OLD_" - + tableName); - - onCreate(db); - - for (String tableName : mTableNames) - repopulateTable(db, tableName); - - dropAllTablesWithPrefix(db, "OLD_"); - } - - private void repopulateTable(SQLiteDatabase db, String tableName) { - String columns = getTableColumnNames(db, tableName); - - StringBuilder sb = new StringBuilder(); - sb.append("INSERT INTO ") - .append(tableName) - .append(" (") - .append(columns) - .append(") SELECT ") - .append(columns) - .append(" FROM OLD_") - .append(tableName); - - String sql = sb.toString(); - db.execSQL(sql); - } - - private String getTableColumnNames(SQLiteDatabase db, String tableName) { - StringBuilder sb = new StringBuilder(); - - Cursor fields = db.rawQuery("PRAGMA table_info(" + tableName + ")", null); - while (fields.moveToNext()) { - if (!fields.isFirst()) - sb.append(", "); - sb.append(fields.getString(1)); - } - fields.close(); - - return sb.toString(); - } - - private void dropAndCreateTables(SQLiteDatabase db) { - dropAllTables(db); - onCreate(db); - } - - private void dropAllTablesWithPrefix(SQLiteDatabase db, String prefix) { - for (String indexName : mIndexNames) - db.execSQL("DROP INDEX IF EXISTS " + prefix + indexName); - for (String tableName : mTableNames) - db.execSQL("DROP TABLE IF EXISTS " + prefix + tableName); - } - - private void dropAllTables(SQLiteDatabase db) { - dropAllTablesWithPrefix(db, ""); - } -} diff --git a/src/org/connectbot/util/UberColorPickerDialog.java b/src/org/connectbot/util/UberColorPickerDialog.java deleted file mode 100644 index 2c01b30..0000000 --- a/src/org/connectbot/util/UberColorPickerDialog.java +++ /dev/null @@ -1,982 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 090408 - * Keith Wiley - * kwiley@keithwiley.com - * http://keithwiley.com - * - * UberColorPickerDialog v1.1 - * - * This color picker was implemented as a (significant) extension of the - * ColorPickerDialog class provided in the Android API Demos. You are free - * to drop it unchanged into your own projects or to modify it as you see - * fit. I would appreciate it if this comment block were let intact, - * merely for credit's sake. - * - * Enjoy! - */ - -package org.connectbot.util; - -import android.app.Dialog; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorMatrix; -import android.graphics.ComposeShader; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.RadialGradient; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Shader; -import android.graphics.SweepGradient; -import android.graphics.drawable.GradientDrawable; -import android.graphics.drawable.GradientDrawable.Orientation; -import android.os.Bundle; -import android.util.DisplayMetrics; -import android.view.MotionEvent; -import android.view.View; - -/** - * UberColorPickerDialog is a seriously enhanced version of the UberColorPickerDialog - * class provided in the Android API Demos.<p> - * - * NOTE (from Kenny Root): This is a VERY slimmed down version custom for ConnectBot. - * Visit Keith's site for the full version at the URL listed in the author line.<p> - * - * @author Keith Wiley, kwiley@keithwiley.com, http://keithwiley.com - */ -public class UberColorPickerDialog extends Dialog { - private final OnColorChangedListener mListener; - private final int mInitialColor; - - /** - * Callback to the creator of the dialog, informing the creator of a new color and notifying that the dialog is about to dismiss. - */ - public interface OnColorChangedListener { - void colorChanged(int color); - } - - /** - * Ctor - * @param context - * @param listener - * @param initialColor - * @param showTitle If true, a title is shown across the top of the dialog. If false a toast is shown instead. - */ - public UberColorPickerDialog(Context context, - OnColorChangedListener listener, - int initialColor) { - super(context); - - mListener = listener; - mInitialColor = initialColor; - } - - /** - * Activity entry point - */ - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - OnColorChangedListener l = new OnColorChangedListener() { - public void colorChanged(int color) { - mListener.colorChanged(color); - dismiss(); - } - }; - - DisplayMetrics dm = new DisplayMetrics(); - getWindow().getWindowManager().getDefaultDisplay().getMetrics(dm); - int screenWidth = dm.widthPixels; - int screenHeight = dm.heightPixels; - - setTitle("Pick a color (try the trackball)"); - - try { - setContentView(new ColorPickerView(getContext(), l, screenWidth, screenHeight, mInitialColor)); - } - catch (Exception e) { - //There is currently only one kind of ctor exception, that where no methods are enabled. - dismiss(); //This doesn't work! The dialog is still shown (its title at least, the layout is empty from the exception being thrown). <sigh> - } - } - - /** - * ColorPickerView is the meat of this color picker (as opposed to the enclosing class). - * All the heavy lifting is done directly by this View subclass. - * <P> - * You can enable/disable whichever color chooser methods you want by modifying the ENABLED_METHODS switches. They *should* - * do all the work required to properly enable/disable methods without losing track of what goes with what and what maps to what. - * <P> - * If you add a new color chooser method, do a text search for "NEW_METHOD_WORK_NEEDED_HERE". That tag indicates all - * the locations in the code that will have to be amended in order to properly add a new color chooser method. - * I highly recommend adding new methods to the end of the list. If you want to try to reorder the list, you're on your own. - */ - private static class ColorPickerView extends View { - private static int SWATCH_WIDTH = 95; - private static final int SWATCH_HEIGHT = 60; - - private static int PALETTE_POS_X = 0; - private static int PALETTE_POS_Y = SWATCH_HEIGHT; - private static final int PALETTE_DIM = SWATCH_WIDTH * 2; - private static final int PALETTE_RADIUS = PALETTE_DIM / 2; - private static final int PALETTE_CENTER_X = PALETTE_RADIUS; - private static final int PALETTE_CENTER_Y = PALETTE_RADIUS; - - private static final int SLIDER_THICKNESS = 40; - - private static int VIEW_DIM_X = PALETTE_DIM; - private static int VIEW_DIM_Y = SWATCH_HEIGHT; - - //NEW_METHOD_WORK_NEEDED_HERE - private static final int METHOD_HS_V_PALETTE = 0; - - //NEW_METHOD_WORK_NEEDED_HERE - //Add a new entry to the list for each controller in the new method - private static final int TRACKED_NONE = -1; //No object on screen is currently being tracked - private static final int TRACK_SWATCH_OLD = 10; - private static final int TRACK_SWATCH_NEW = 11; - private static final int TRACK_HS_PALETTE = 30; - private static final int TRACK_VER_VALUE_SLIDER = 31; - - private static final int TEXT_SIZE = 12; - private static int[] TEXT_HSV_POS = new int[2]; - private static int[] TEXT_RGB_POS = new int[2]; - private static int[] TEXT_YUV_POS = new int[2]; - private static int[] TEXT_HEX_POS = new int[2]; - - private static final float PI = 3.141592653589793f; - - private int mMethod = METHOD_HS_V_PALETTE; - private int mTracking = TRACKED_NONE; //What object on screen is currently being tracked for movement - - //Zillions of persistant Paint objecs for drawing the View - - private Paint mSwatchOld, mSwatchNew; - - //NEW_METHOD_WORK_NEEDED_HERE - //Add Paints to represent the palettes of the new method's UI controllers - private Paint mOvalHueSat; - - private Bitmap mVerSliderBM; - private Canvas mVerSliderCv; - - private Bitmap[] mHorSlidersBM = new Bitmap[3]; - private Canvas[] mHorSlidersCv = new Canvas[3]; - - private Paint mValDimmer; - - //NEW_METHOD_WORK_NEEDED_HERE - //Add Paints to represent the icon for the new method - private Paint mOvalHueSatSmall; - - private Paint mPosMarker; - private Paint mText; - - private Rect mOldSwatchRect = new Rect(); - private Rect mNewSwatchRect = new Rect(); - private Rect mPaletteRect = new Rect(); - private Rect mVerSliderRect = new Rect(); - - private int[] mSpectrumColorsRev; - private int mOriginalColor = 0; //The color passed in at the beginning, which can be reverted to at any time by tapping the old swatch. - private float[] mHSV = new float[3]; - private int[] mRGB = new int[3]; - private float[] mYUV = new float[3]; - private String mHexStr = ""; - private boolean mHSVenabled = true; //Only true if an HSV method is enabled - private boolean mRGBenabled = true; //Only true if an RGB method is enabled - private boolean mYUVenabled = true; //Only true if a YUV method is enabled - private boolean mHexenabled = true; //Only true if an RGB method is enabled - private int[] mCoord = new int[3]; //For drawing slider/palette markers - private int mFocusedControl = -1; //Which control receives trackball events. - private OnColorChangedListener mListener; - - /** - * Ctor. - * @param c - * @param l - * @param width Used to determine orientation and adjust layout accordingly - * @param height Used to determine orientation and adjust layout accordingly - * @param color The initial color - * @throws Exception - */ - ColorPickerView(Context c, OnColorChangedListener l, int width, int height, int color) - throws Exception { - super(c); - - //We need to make the dialog focusable to retrieve trackball events. - setFocusable(true); - - mListener = l; - - mOriginalColor = color; - - Color.colorToHSV(color, mHSV); - - updateAllFromHSV(); - - //Setup the layout based on whether this is a portrait or landscape orientation. - if (width <= height) { //Portrait layout - SWATCH_WIDTH = (PALETTE_DIM + SLIDER_THICKNESS) / 2; - - PALETTE_POS_X = 0; - PALETTE_POS_Y = TEXT_SIZE * 4 + SWATCH_HEIGHT; - - //Set more rects, lots of rects - mOldSwatchRect.set(0, TEXT_SIZE * 4, SWATCH_WIDTH, TEXT_SIZE * 4 + SWATCH_HEIGHT); - mNewSwatchRect.set(SWATCH_WIDTH, TEXT_SIZE * 4, SWATCH_WIDTH * 2, TEXT_SIZE * 4 + SWATCH_HEIGHT); - mPaletteRect.set(0, PALETTE_POS_Y, PALETTE_DIM, PALETTE_POS_Y + PALETTE_DIM); - mVerSliderRect.set(PALETTE_DIM, PALETTE_POS_Y, PALETTE_DIM + SLIDER_THICKNESS, PALETTE_POS_Y + PALETTE_DIM); - - TEXT_HSV_POS[0] = 3; - TEXT_HSV_POS[1] = 0; - TEXT_RGB_POS[0] = TEXT_HSV_POS[0] + 50; - TEXT_RGB_POS[1] = TEXT_HSV_POS[1]; - TEXT_YUV_POS[0] = TEXT_HSV_POS[0] + 100; - TEXT_YUV_POS[1] = TEXT_HSV_POS[1]; - TEXT_HEX_POS[0] = TEXT_HSV_POS[0] + 150; - TEXT_HEX_POS[1] = TEXT_HSV_POS[1]; - - VIEW_DIM_X = PALETTE_DIM + SLIDER_THICKNESS; - VIEW_DIM_Y = SWATCH_HEIGHT + PALETTE_DIM + TEXT_SIZE * 4; - } - else { //Landscape layout - SWATCH_WIDTH = 110; - - PALETTE_POS_X = SWATCH_WIDTH; - PALETTE_POS_Y = 0; - - //Set more rects, lots of rects - mOldSwatchRect.set(0, TEXT_SIZE * 7, SWATCH_WIDTH, TEXT_SIZE * 7 + SWATCH_HEIGHT); - mNewSwatchRect.set(0, TEXT_SIZE * 7 + SWATCH_HEIGHT, SWATCH_WIDTH, TEXT_SIZE * 7 + SWATCH_HEIGHT * 2); - mPaletteRect.set(SWATCH_WIDTH, PALETTE_POS_Y, SWATCH_WIDTH + PALETTE_DIM, PALETTE_POS_Y + PALETTE_DIM); - mVerSliderRect.set(SWATCH_WIDTH + PALETTE_DIM, PALETTE_POS_Y, SWATCH_WIDTH + PALETTE_DIM + SLIDER_THICKNESS, PALETTE_POS_Y + PALETTE_DIM); - - TEXT_HSV_POS[0] = 3; - TEXT_HSV_POS[1] = 0; - TEXT_RGB_POS[0] = TEXT_HSV_POS[0]; - TEXT_RGB_POS[1] = (int)(TEXT_HSV_POS[1] + TEXT_SIZE * 3.5); - TEXT_YUV_POS[0] = TEXT_HSV_POS[0] + 50; - TEXT_YUV_POS[1] = (int)(TEXT_HSV_POS[1] + TEXT_SIZE * 3.5); - TEXT_HEX_POS[0] = TEXT_HSV_POS[0] + 50; - TEXT_HEX_POS[1] = TEXT_HSV_POS[1]; - - VIEW_DIM_X = PALETTE_POS_X + PALETTE_DIM + SLIDER_THICKNESS; - VIEW_DIM_Y = Math.max(mNewSwatchRect.bottom, PALETTE_DIM); - } - - //Rainbows make everybody happy! - mSpectrumColorsRev = new int[] { - 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, - 0xFF00FF00, 0xFFFFFF00, 0xFFFF0000, - }; - - //Setup all the Paint and Shader objects. There are lots of them! - - //NEW_METHOD_WORK_NEEDED_HERE - //Add Paints to represent the palettes of the new method's UI controllers - - mSwatchOld = new Paint(Paint.ANTI_ALIAS_FLAG); - mSwatchOld.setStyle(Paint.Style.FILL); - mSwatchOld.setColor(Color.HSVToColor(mHSV)); - - mSwatchNew = new Paint(Paint.ANTI_ALIAS_FLAG); - mSwatchNew.setStyle(Paint.Style.FILL); - mSwatchNew.setColor(Color.HSVToColor(mHSV)); - - Shader shaderA = new SweepGradient(0, 0, mSpectrumColorsRev, null); - Shader shaderB = new RadialGradient(0, 0, PALETTE_CENTER_X, 0xFFFFFFFF, 0xFF000000, Shader.TileMode.CLAMP); - Shader shader = new ComposeShader(shaderA, shaderB, PorterDuff.Mode.SCREEN); - mOvalHueSat = new Paint(Paint.ANTI_ALIAS_FLAG); - mOvalHueSat.setShader(shader); - mOvalHueSat.setStyle(Paint.Style.FILL); - mOvalHueSat.setDither(true); - - mVerSliderBM = Bitmap.createBitmap(SLIDER_THICKNESS, PALETTE_DIM, Bitmap.Config.RGB_565); - mVerSliderCv = new Canvas(mVerSliderBM); - - for (int i = 0; i < 3; i++) { - mHorSlidersBM[i] = Bitmap.createBitmap(PALETTE_DIM, SLIDER_THICKNESS, Bitmap.Config.RGB_565); - mHorSlidersCv[i] = new Canvas(mHorSlidersBM[i]); - } - - mValDimmer = new Paint(Paint.ANTI_ALIAS_FLAG); - mValDimmer.setStyle(Paint.Style.FILL); - mValDimmer.setDither(true); - mValDimmer.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); - - //Whew, we're done making the big Paints and Shaders for the swatches, palettes, and sliders. - //Now we need to make the Paints and Shaders that will draw the little method icons in the method selector list. - - //NEW_METHOD_WORK_NEEDED_HERE - //Add Paints to represent the icon for the new method - - shaderA = new SweepGradient(0, 0, mSpectrumColorsRev, null); - shaderB = new RadialGradient(0, 0, PALETTE_DIM / 2, 0xFFFFFFFF, 0xFF000000, Shader.TileMode.CLAMP); - shader = new ComposeShader(shaderA, shaderB, PorterDuff.Mode.SCREEN); - mOvalHueSatSmall = new Paint(Paint.ANTI_ALIAS_FLAG); - mOvalHueSatSmall.setShader(shader); - mOvalHueSatSmall.setStyle(Paint.Style.FILL); - - //Make a simple stroking Paint for drawing markers and borders and stuff like that. - mPosMarker = new Paint(Paint.ANTI_ALIAS_FLAG); - mPosMarker.setStyle(Paint.Style.STROKE); - mPosMarker.setStrokeWidth(2); - - //Make a basic text Paint. - mText = new Paint(Paint.ANTI_ALIAS_FLAG); - mText.setTextSize(TEXT_SIZE); - mText.setColor(Color.WHITE); - - //Kickstart - initUI(); - } - - /** - * Draw the entire view (the entire dialog). - */ - @Override - protected void onDraw(Canvas canvas) { - //Draw the old and new swatches - drawSwatches(canvas); - - //Write the text - writeColorParams(canvas); - - //Draw the palette and sliders (the UI) - if (mMethod == METHOD_HS_V_PALETTE) - drawHSV1Palette(canvas); - } - - /** - * Draw the old and new swatches. - * @param canvas - */ - private void drawSwatches(Canvas canvas) { - float[] hsv = new float[3]; - - mText.setTextSize(16); - - //Draw the original swatch - canvas.drawRect(mOldSwatchRect, mSwatchOld); - Color.colorToHSV(mOriginalColor, hsv); - //if (UberColorPickerDialog.isGray(mColor)) //Don't need this right here, but imp't to note - // hsv[1] = 0; - if (hsv[2] > .5) - mText.setColor(Color.BLACK); - canvas.drawText("Revert", mOldSwatchRect.left + SWATCH_WIDTH / 2 - mText.measureText("Revert") / 2, mOldSwatchRect.top + 16, mText); - mText.setColor(Color.WHITE); - - //Draw the new swatch - canvas.drawRect(mNewSwatchRect, mSwatchNew); - if (mHSV[2] > .5) - mText.setColor(Color.BLACK); - canvas.drawText("Accept", mNewSwatchRect.left + SWATCH_WIDTH / 2 - mText.measureText("Accept") / 2, mNewSwatchRect.top + 16, mText); - mText.setColor(Color.WHITE); - - mText.setTextSize(TEXT_SIZE); - } - - /** - * Write the color parametes (HSV, RGB, YUV, Hex, etc.). - * @param canvas - */ - private void writeColorParams(Canvas canvas) { - if (mHSVenabled) { - canvas.drawText("H: " + Integer.toString((int)(mHSV[0] / 360.0f * 255)), TEXT_HSV_POS[0], TEXT_HSV_POS[1] + TEXT_SIZE, mText); - canvas.drawText("S: " + Integer.toString((int)(mHSV[1] * 255)), TEXT_HSV_POS[0], TEXT_HSV_POS[1] + TEXT_SIZE * 2, mText); - canvas.drawText("V: " + Integer.toString((int)(mHSV[2] * 255)), TEXT_HSV_POS[0], TEXT_HSV_POS[1] + TEXT_SIZE * 3, mText); - } - - if (mRGBenabled) { - canvas.drawText("R: " + mRGB[0], TEXT_RGB_POS[0], TEXT_RGB_POS[1] + TEXT_SIZE, mText); - canvas.drawText("G: " + mRGB[1], TEXT_RGB_POS[0], TEXT_RGB_POS[1] + TEXT_SIZE * 2, mText); - canvas.drawText("B: " + mRGB[2], TEXT_RGB_POS[0], TEXT_RGB_POS[1] + TEXT_SIZE * 3, mText); - } - - if (mYUVenabled) { - canvas.drawText("Y: " + Integer.toString((int)(mYUV[0] * 255)), TEXT_YUV_POS[0], TEXT_YUV_POS[1] + TEXT_SIZE, mText); - canvas.drawText("U: " + Integer.toString((int)((mYUV[1] + .5f) * 255)), TEXT_YUV_POS[0], TEXT_YUV_POS[1] + TEXT_SIZE * 2, mText); - canvas.drawText("V: " + Integer.toString((int)((mYUV[2] + .5f) * 255)), TEXT_YUV_POS[0], TEXT_YUV_POS[1] + TEXT_SIZE * 3, mText); - } - - if (mHexenabled) - canvas.drawText("#" + mHexStr, TEXT_HEX_POS[0], TEXT_HEX_POS[1] + TEXT_SIZE, mText); - } - - /** - * Place a small circle on the 2D palette to indicate the current values. - * @param canvas - * @param markerPosX - * @param markerPosY - */ - private void mark2DPalette(Canvas canvas, int markerPosX, int markerPosY) { - mPosMarker.setColor(Color.BLACK); - canvas.drawOval(new RectF(markerPosX - 5, markerPosY - 5, markerPosX + 5, markerPosY + 5), mPosMarker); - mPosMarker.setColor(Color.WHITE); - canvas.drawOval(new RectF(markerPosX - 3, markerPosY - 3, markerPosX + 3, markerPosY + 3), mPosMarker); - } - - /** - * Draw a line across the slider to indicate its current value. - * @param canvas - * @param markerPos - */ - private void markVerSlider(Canvas canvas, int markerPos) { - mPosMarker.setColor(Color.BLACK); - canvas.drawRect(new Rect(0, markerPos - 2, SLIDER_THICKNESS, markerPos + 3), mPosMarker); - mPosMarker.setColor(Color.WHITE); - canvas.drawRect(new Rect(0, markerPos, SLIDER_THICKNESS, markerPos + 1), mPosMarker); - } - - /** - * Frame the slider to indicate that it has trackball focus. - * @param canvas - */ - private void hilightFocusedVerSlider(Canvas canvas) { - mPosMarker.setColor(Color.WHITE); - canvas.drawRect(new Rect(0, 0, SLIDER_THICKNESS, PALETTE_DIM), mPosMarker); - mPosMarker.setColor(Color.BLACK); - canvas.drawRect(new Rect(2, 2, SLIDER_THICKNESS - 2, PALETTE_DIM - 2), mPosMarker); - } - - /** - * Frame the 2D palette to indicate that it has trackball focus. - * @param canvas - */ - private void hilightFocusedOvalPalette(Canvas canvas) { - mPosMarker.setColor(Color.WHITE); - canvas.drawOval(new RectF(-PALETTE_RADIUS, -PALETTE_RADIUS, PALETTE_RADIUS, PALETTE_RADIUS), mPosMarker); - mPosMarker.setColor(Color.BLACK); - canvas.drawOval(new RectF(-PALETTE_RADIUS + 2, -PALETTE_RADIUS + 2, PALETTE_RADIUS - 2, PALETTE_RADIUS - 2), mPosMarker); - } - - //NEW_METHOD_WORK_NEEDED_HERE - //To add a new method, replicate the basic draw functions here. Use the 2D palette or 1D sliders as templates for the new method. - /** - * Draw the UI for HSV with angular H and radial S combined in 2D and a 1D V slider. - * @param canvas - */ - private void drawHSV1Palette(Canvas canvas) { - canvas.save(); - - canvas.translate(PALETTE_POS_X, PALETTE_POS_Y); - - //Draw the 2D palette - canvas.translate(PALETTE_CENTER_X, PALETTE_CENTER_Y); - canvas.drawOval(new RectF(-PALETTE_RADIUS, -PALETTE_RADIUS, PALETTE_RADIUS, PALETTE_RADIUS), mOvalHueSat); - canvas.drawOval(new RectF(-PALETTE_RADIUS, -PALETTE_RADIUS, PALETTE_RADIUS, PALETTE_RADIUS), mValDimmer); - if (mFocusedControl == 0) - hilightFocusedOvalPalette(canvas); - mark2DPalette(canvas, mCoord[0], mCoord[1]); - canvas.translate(-PALETTE_CENTER_X, -PALETTE_CENTER_Y); - - //Draw the 1D slider - canvas.translate(PALETTE_DIM, 0); - canvas.drawBitmap(mVerSliderBM, 0, 0, null); - if (mFocusedControl == 1) - hilightFocusedVerSlider(canvas); - markVerSlider(canvas, mCoord[2]); - - canvas.restore(); - } - - /** - * Initialize the current color chooser's UI (set its color parameters and set its palette and slider values accordingly). - */ - private void initUI() { - initHSV1Palette(); - - //Focus on the first controller (arbitrary). - mFocusedControl = 0; - } - - //NEW_METHOD_WORK_NEEDED_HERE - //To add a new method, replicate and extend the last init function shown below - /** - * Initialize a color chooser. - */ - private void initHSV1Palette() { - setOvalValDimmer(); - setVerValSlider(); - - float angle = 2*PI - mHSV[0] / (180 / 3.1415927f); - float radius = mHSV[1] * PALETTE_RADIUS; - mCoord[0] = (int)(Math.cos(angle) * radius); - mCoord[1] = (int)(Math.sin(angle) * radius); - - mCoord[2] = PALETTE_DIM - (int)(mHSV[2] * PALETTE_DIM); - } - - //NEW_METHOD_WORK_NEEDED_HERE - //To add a new method, replicate and extend the set functions below, one per UI controller in the new method - /** - * Adjust a Paint which, when painted, dims its underlying object to show the effects of varying value (brightness). - */ - private void setOvalValDimmer() { - float[] hsv = new float[3]; - hsv[0] = mHSV[0]; - hsv[1] = 0; - hsv[2] = mHSV[2]; - int gray = Color.HSVToColor(hsv); - mValDimmer.setColor(gray); - } - - /** - * Create a linear gradient shader to show variations in value. - */ - private void setVerValSlider() { - float[] hsv = new float[3]; - hsv[0] = mHSV[0]; - hsv[1] = mHSV[1]; - hsv[2] = 1; - int col = Color.HSVToColor(hsv); - - int colors[] = new int[2]; - colors[0] = col; - colors[1] = 0xFF000000; - GradientDrawable gradDraw = new GradientDrawable(Orientation.TOP_BOTTOM, colors); - gradDraw.setDither(true); - gradDraw.setLevel(10000); - gradDraw.setBounds(0, 0, SLIDER_THICKNESS, PALETTE_DIM); - gradDraw.draw(mVerSliderCv); - } - - /** - * Report the correct tightly bounded dimensions of the view. - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(VIEW_DIM_X, VIEW_DIM_Y); - } - - /** - * Wrap Math.round(). I'm not a Java expert. Is this the only way to avoid writing "(int)Math.round" everywhere? - * @param x - * @return - */ - private int round(double x) { - return (int)Math.round(x); - } - - /** - * Limit a value to the range [0,1]. - * @param n - * @return - */ - private float pinToUnit(float n) { - if (n < 0) { - n = 0; - } else if (n > 1) { - n = 1; - } - return n; - } - - /** - * Limit a value to the range [0,max]. - * @param n - * @param max - * @return - */ - private float pin(float n, float max) { - if (n < 0) { - n = 0; - } else if (n > max) { - n = max; - } - return n; - } - - /** - * Limit a value to the range [min,max]. - * @param n - * @param min - * @param max - * @return - */ - private float pin(float n, float min, float max) { - if (n < min) { - n = min; - } else if (n > max) { - n = max; - } - return n; - } - - /** - * No clue what this does (some sort of average/mean I presume). It came with the original UberColorPickerDialog - * in the API Demos and wasn't documented. I don't feel like spending any time figuring it out, I haven't looked at it at all. - * @param s - * @param d - * @param p - * @return - */ - private int ave(int s, int d, float p) { - return s + round(p * (d - s)); - } - - /** - * Came with the original UberColorPickerDialog in the API Demos, wasn't documented. I believe it takes an array of - * colors and a value in the range [0,1] and interpolates a resulting color in a seemingly predictable manner. - * I haven't looked at it at all. - * @param colors - * @param unit - * @return - */ - private int interpColor(int colors[], float unit) { - if (unit <= 0) { - return colors[0]; - } - if (unit >= 1) { - return colors[colors.length - 1]; - } - - float p = unit * (colors.length - 1); - int i = (int)p; - p -= i; - - // now p is just the fractional part [0...1) and i is the index - int c0 = colors[i]; - int c1 = colors[i+1]; - int a = ave(Color.alpha(c0), Color.alpha(c1), p); - int r = ave(Color.red(c0), Color.red(c1), p); - int g = ave(Color.green(c0), Color.green(c1), p); - int b = ave(Color.blue(c0), Color.blue(c1), p); - - return Color.argb(a, r, g, b); - } - - /** - * A standard point-in-rect routine. - * @param x - * @param y - * @param r - * @return true if point x,y is in rect r - */ - public boolean ptInRect(int x, int y, Rect r) { - return x > r.left && x < r.right && y > r.top && y < r.bottom; - } - - /** - * Process trackball events. Used mainly for fine-tuned color adjustment, or alternatively to switch between slider controls. - */ - @Override - public boolean dispatchTrackballEvent(MotionEvent event) { - float x = event.getX(); - float y = event.getY(); - - //A longer event history implies faster trackball movement. - //Use it to infer a larger jump and therefore faster palette/slider adjustment. - int jump = event.getHistorySize() + 1; - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: { - } - break; - case MotionEvent.ACTION_MOVE: { - //NEW_METHOD_WORK_NEEDED_HERE - //To add a new method, replicate and extend the appropriate entry in this list, - //depending on whether you use 1D or 2D controllers - switch (mMethod) { - case METHOD_HS_V_PALETTE: - if (mFocusedControl == 0) { - changeHSPalette(x, y, jump); - } - else if (mFocusedControl == 1) { - if (y < 0) - changeSlider(mFocusedControl, true, jump); - else if (y > 0) - changeSlider(mFocusedControl, false, jump); - } - break; - } - } - break; - case MotionEvent.ACTION_UP: { - } - break; - } - - return true; - } - - //NEW_METHOD_WORK_NEEDED_HERE - //To add a new method, replicate and extend the appropriate functions below, - //one per UI controller in the new method - /** - * Effect a trackball change to a 2D palette. - * @param x -1: negative x change, 0: no x change, +1: positive x change. - * @param y -1: negative y change, 0, no y change, +1: positive y change. - * @param jump the amount by which to change. - */ - private void changeHSPalette(float x, float y, int jump) { - int x2 = 0, y2 = 0; - if (x < 0) - x2 = -jump; - else if (x > 0) - x2 = jump; - if (y < 0) - y2 = -jump; - else if (y > 0) - y2 = jump; - - mCoord[0] += x2; - mCoord[1] += y2; - - if (mCoord[0] < -PALETTE_RADIUS) - mCoord[0] = -PALETTE_RADIUS; - else if (mCoord[0] > PALETTE_RADIUS) - mCoord[0] = PALETTE_RADIUS; - if (mCoord[1] < -PALETTE_RADIUS) - mCoord[1] = -PALETTE_RADIUS; - else if (mCoord[1] > PALETTE_RADIUS) - mCoord[1] = PALETTE_RADIUS; - - float radius = (float)java.lang.Math.sqrt(mCoord[0] * mCoord[0] + mCoord[1] * mCoord[1]); - if (radius > PALETTE_RADIUS) - radius = PALETTE_RADIUS; - - float angle = (float)java.lang.Math.atan2(mCoord[1], mCoord[0]); - // need to turn angle [-PI ... PI] into unit [0....1] - float unit = angle/(2*PI); - if (unit < 0) { - unit += 1; - } - - mCoord[0] = round(Math.cos(angle) * radius); - mCoord[1] = round(Math.sin(angle) * radius); - - int c = interpColor(mSpectrumColorsRev, unit); - float[] hsv = new float[3]; - Color.colorToHSV(c, hsv); - mHSV[0] = hsv[0]; - mHSV[1] = radius / PALETTE_RADIUS; - updateAllFromHSV(); - mSwatchNew.setColor(Color.HSVToColor(mHSV)); - - setVerValSlider(); - - invalidate(); - } - - /** - * Effect a trackball change to a 1D slider. - * @param slider id of the slider to be effected - * @param increase true if the change is an increase, false if a decrease - * @param jump the amount by which to change in units of the range [0,255] - */ - private void changeSlider(int slider, boolean increase, int jump) { - //NEW_METHOD_WORK_NEEDED_HERE - //It is only necessary to add an entry here for a new method if the new method uses a 1D slider. - //Note, some sliders are horizontal and others are vertical. - //They differ a bit, especially in a sign flip on the vertical axis. - if (mMethod == METHOD_HS_V_PALETTE) { - //slider *must* equal 1 - - mHSV[2] += (increase ? jump : -jump) / 256.0f; - mHSV[2] = pinToUnit(mHSV[2]); - updateAllFromHSV(); - mCoord[2] = PALETTE_DIM - (int)(mHSV[2] * PALETTE_DIM); - - mSwatchNew.setColor(Color.HSVToColor(mHSV)); - - setOvalValDimmer(); - - invalidate(); - } - } - - /** - * Keep all colorspace representations in sync. - */ - private void updateRGBfromHSV() { - int color = Color.HSVToColor(mHSV); - mRGB[0] = Color.red(color); - mRGB[1] = Color.green(color); - mRGB[2] = Color.blue(color); - } - - /** - * Keep all colorspace representations in sync. - */ - private void updateYUVfromRGB() { - float r = mRGB[0] / 255.0f; - float g = mRGB[1] / 255.0f; - float b = mRGB[2] / 255.0f; - - ColorMatrix cm = new ColorMatrix(); - cm.setRGB2YUV(); - final float[] a = cm.getArray(); - - mYUV[0] = a[0] * r + a[1] * g + a[2] * b; - mYUV[0] = pinToUnit(mYUV[0]); - mYUV[1] = a[5] * r + a[6] * g + a[7] * b; - mYUV[1] = pin(mYUV[1], -.5f, .5f); - mYUV[2] = a[10] * r + a[11] * g + a[12] * b; - mYUV[2] = pin(mYUV[2], -.5f, .5f); - } - - /** - * Keep all colorspace representations in sync. - */ - private void updateHexFromHSV() { - //For now, assume 100% opacity - mHexStr = Integer.toHexString(Color.HSVToColor(mHSV)).toUpperCase(); - mHexStr = mHexStr.substring(2, mHexStr.length()); - } - - /** - * Keep all colorspace representations in sync. - */ - private void updateAllFromHSV() { - //Update mRGB - if (mRGBenabled || mYUVenabled) - updateRGBfromHSV(); - - //Update mYUV - if (mYUVenabled) - updateYUVfromRGB(); - - //Update mHexStr - if (mRGBenabled) - updateHexFromHSV(); - } - - /** - * Process touch events: down, move, and up - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - float x = event.getX(); - float y = event.getY(); - - //Generate coordinates which are palette=local with the origin at the upper left of the main 2D palette - int y2 = (int)(pin(round(y - PALETTE_POS_Y), PALETTE_DIM)); - - //Generate coordinates which are palette-local with the origin at the center of the main 2D palette - float circlePinnedX = x - PALETTE_POS_X - PALETTE_CENTER_X; - float circlePinnedY = y - PALETTE_POS_Y - PALETTE_CENTER_Y; - - //Is the event in a swatch? - boolean inSwatchOld = ptInRect(round(x), round(y), mOldSwatchRect); - boolean inSwatchNew = ptInRect(round(x), round(y), mNewSwatchRect); - - //Get the event's distance from the center of the main 2D palette - float radius = (float)java.lang.Math.sqrt(circlePinnedX * circlePinnedX + circlePinnedY * circlePinnedY); - - //Is the event in a circle-pinned 2D palette? - boolean inOvalPalette = radius <= PALETTE_RADIUS; - - //Pin the radius - if (radius > PALETTE_RADIUS) - radius = PALETTE_RADIUS; - - //Is the event in a vertical slider to the right of the main 2D palette - boolean inVerSlider = ptInRect(round(x), round(y), mVerSliderRect); - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mTracking = TRACKED_NONE; - - if (inSwatchOld) - mTracking = TRACK_SWATCH_OLD; - else if (inSwatchNew) - mTracking = TRACK_SWATCH_NEW; - - //NEW_METHOD_WORK_NEEDED_HERE - //To add a new method, replicate and extend the last entry in this list - else if (mMethod == METHOD_HS_V_PALETTE) { - if (inOvalPalette) { - mTracking = TRACK_HS_PALETTE; - mFocusedControl = 0; - } - else if (inVerSlider) { - mTracking = TRACK_VER_VALUE_SLIDER; - mFocusedControl = 1; - } - } - case MotionEvent.ACTION_MOVE: - //NEW_METHOD_WORK_NEEDED_HERE - //To add a new method, replicate and extend the entries in this list, - //one per UI controller the new method requires. - if (mTracking == TRACK_HS_PALETTE) { - float angle = (float)java.lang.Math.atan2(circlePinnedY, circlePinnedX); - // need to turn angle [-PI ... PI] into unit [0....1] - float unit = angle/(2*PI); - if (unit < 0) { - unit += 1; - } - - mCoord[0] = round(Math.cos(angle) * radius); - mCoord[1] = round(Math.sin(angle) * radius); - - int c = interpColor(mSpectrumColorsRev, unit); - float[] hsv = new float[3]; - Color.colorToHSV(c, hsv); - mHSV[0] = hsv[0]; - mHSV[1] = radius / PALETTE_RADIUS; - updateAllFromHSV(); - mSwatchNew.setColor(Color.HSVToColor(mHSV)); - - setVerValSlider(); - - invalidate(); - } - else if (mTracking == TRACK_VER_VALUE_SLIDER) { - if (mCoord[2] != y2) { - mCoord[2] = y2; - float value = 1.0f - (float)y2 / (float)PALETTE_DIM; - - mHSV[2] = value; - updateAllFromHSV(); - mSwatchNew.setColor(Color.HSVToColor(mHSV)); - - setOvalValDimmer(); - - invalidate(); - } - } - break; - case MotionEvent.ACTION_UP: - //NEW_METHOD_WORK_NEEDED_HERE - //To add a new method, replicate and extend the last entry in this list. - if (mTracking == TRACK_SWATCH_OLD && inSwatchOld) { - Color.colorToHSV(mOriginalColor, mHSV); - mSwatchNew.setColor(mOriginalColor); - initUI(); - invalidate(); - } - else if (mTracking == TRACK_SWATCH_NEW && inSwatchNew) { - mListener.colorChanged(mSwatchNew.getColor()); - invalidate(); - } - - mTracking= TRACKED_NONE; - break; - } - - return true; - } - } -} diff --git a/src/org/connectbot/util/VolumePreference.java b/src/org/connectbot/util/VolumePreference.java deleted file mode 100644 index 2e7f61c..0000000 --- a/src/org/connectbot/util/VolumePreference.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import android.content.Context; -import android.preference.DialogPreference; -import android.util.AttributeSet; -import android.view.View; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; - -/** - * @author kenny - * - */ -public class VolumePreference extends DialogPreference implements OnSeekBarChangeListener { - /** - * @param context - * @param attrs - */ - public VolumePreference(Context context, AttributeSet attrs) { - super(context, attrs); - - setupLayout(context, attrs); - } - - public VolumePreference(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - setupLayout(context, attrs); - } - - private void setupLayout(Context context, AttributeSet attrs) { - setPersistent(true); - } - - @Override - protected View onCreateDialogView() { - SeekBar sb = new SeekBar(getContext()); - - sb.setMax(100); - sb.setProgress((int)(getPersistedFloat( - PreferenceConstants.DEFAULT_BELL_VOLUME) * 100)); - sb.setPadding(10, 10, 10, 10); - sb.setOnSeekBarChangeListener(this); - - return sb; - } - - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - persistFloat(progress / 100f); - } - - public void onStartTrackingTouch(SeekBar seekBar) { } - - public void onStopTrackingTouch(SeekBar seekBar) { } -} diff --git a/src/org/connectbot/util/XmlBuilder.java b/src/org/connectbot/util/XmlBuilder.java deleted file mode 100644 index 4a6f62d..0000000 --- a/src/org/connectbot/util/XmlBuilder.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ConnectBot: simple, powerful, open-source SSH client for Android - * Copyright 2007 Kenny Root, Jeffrey Sharkey - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.connectbot.util; - -import com.trilead.ssh2.crypto.Base64; - -/** - * @author Kenny Root - * - */ -public class XmlBuilder { - private StringBuilder sb; - - public XmlBuilder() { - sb = new StringBuilder(); - } - - public XmlBuilder append(String data) { - sb.append(data); - - return this; - } - - public XmlBuilder append(String field, Object data) { - if (data == null) { - sb.append(String.format("<%s/>", field)); - } else if (data instanceof String) { - String input = (String) data; - boolean binary = false; - - for (byte b : input.getBytes()) { - if (b < 0x20 || b > 0x7e) { - binary = true; - break; - } - } - - sb.append(String.format("<%s>%s</%s>", field, - binary ? new String(Base64.encode(input.getBytes())) : input, field)); - } else if (data instanceof Integer) { - sb.append(String.format("<%s>%d</%s>", field, (Integer) data, field)); - } else if (data instanceof Long) { - sb.append(String.format("<%s>%d</%s>", field, (Long) data, field)); - } else if (data instanceof byte[]) { - sb.append(String.format("<%s>%s</%s>", field, new String(Base64.encode((byte[]) data)), field)); - } else if (data instanceof Boolean) { - sb.append(String.format("<%s>%s</%s>", field, (Boolean) data, field)); - } - - return this; - } - - public String toString() { - return sb.toString(); - } -} diff --git a/src/org/keyczar/jce/EcCore.java b/src/org/keyczar/jce/EcCore.java deleted file mode 100644 index 681d5db..0000000 --- a/src/org/keyczar/jce/EcCore.java +++ /dev/null @@ -1,679 +0,0 @@ -/* - * Copyright 2008 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package org.keyczar.jce; - -import java.math.BigInteger; -import java.security.spec.ECFieldFp; -import java.security.spec.ECParameterSpec; - -/** - * This class implements the basic EC operations such as point addition and - * doubling and point multiplication. Only NSA Suite B / NIST curves are - * supported. - * - * Todo: - * - Add (more) comments - Performance optimizations - Cleanup ASN.1 code, - * possibly replace with own impl - ... - * - * References: - * - * [1] Software Implementation of the NIST Elliptic Curves Over Prime Fields, M. - * Brown et al. [2] Efficient elliptic curve exponentiation using mixed - * coordinates, H. Cohen et al. [3] SEC 1: Elliptic Curve Cryptography. [4] - * Guide to Elliptic Curve Cryptography, D. Hankerson et al., Springer. - * - * @author martclau@gmail.com - * - */ -// BEGIN connectbot-changed -public final class EcCore { -// END connectbot-changed -// BEGIN connectbot-removed -// private static final long serialVersionUID = -1376116429660095993L; -// -// private static final String INFO = "Google Keyczar (EC key/parameter generation; EC signing)"; -// -// public static final String NAME = "GooKey"; -// -// @SuppressWarnings("unchecked") -// public EcCore() { -// super(NAME, 0.1, INFO); -// AccessController.doPrivileged(new PrivilegedAction<Object>() { -// @Override -// public Object run() { -// put("Signature.SHA1withECDSA", "org.keyczar.jce.EcSignatureImpl$SHA1"); -// put("Alg.Alias.Signature.ECDSA", "SHA1withDSA"); -// put("Signature.SHA256withECDSA", -// "org.keyczar.jce.EcSignatureImpl$SHA256"); -// put("Signature.SHA384withECDSA", -// "org.keyczar.jce.EcSignatureImpl$SHA384"); -// put("Signature.SHA512withECDSA", -// "org.keyczar.jce.EcSignatureImpl$SHA512"); -// put("KeyPairGenerator.EC", "org.keyczar.jce.EcKeyPairGeneratorImpl"); -// put("KeyFactory.EC", "org.keyczar.jce.EcKeyFactoryImpl"); -// put("Signature.SHA1withECDSA KeySize", "521"); -// put("Signature.SHA1withECDSA ImplementedIn", "Software"); -// put("Signature.SHA256withECDSA KeySize", "521"); -// put("Signature.SHA256withECDSA ImplementedIn", "Software"); -// put("Signature.SHA384withECDSA KeySize", "521"); -// put("Signature.SHA384withECDSA ImplementedIn", "Software"); -// put("Signature.SHA512withECDSA KeySize", "521"); -// put("Signature.SHA512withECDSA ImplementedIn", "Software"); -// put("KeyPairGenerator.EC ImplementedIn", "Software"); -// put("KeyFactory.EC ImplementedIn", "Software"); -// return null; -// } -// }); -// } -// -// private static final ECParameterSpec P192 = new ECParameterSpec( -// new EllipticCurve( -// new ECFieldFp(new BigInteger( -// "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16)), -// new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", 16), -// new BigInteger("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", 16)), -// new ECPoint( -// new BigInteger("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", 16), -// new BigInteger("07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", 16)), -// new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", 16), 1); -// -// private static final ECParameterSpec P224 = new ECParameterSpec( -// new EllipticCurve(new ECFieldFp(new BigInteger( -// "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", 16)), -// new BigInteger( -// "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", 16), -// new BigInteger( -// "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", 16)), -// new ECPoint(new BigInteger( -// "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", 16), -// new BigInteger( -// "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", 16)), -// new BigInteger( -// "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", 16), 1); -// -// private static final ECParameterSpec P256 = new ECParameterSpec( -// new EllipticCurve(new ECFieldFp(new BigInteger( -// "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", -// 16)), new BigInteger( -// "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", -// 16), new BigInteger( -// "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", -// 16)), new ECPoint(new BigInteger( -// "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", -// 16), new BigInteger( -// "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", -// 16)), new BigInteger( -// "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", -// 16), 1); -// -// private static final ECParameterSpec P384 = new ECParameterSpec( -// new EllipticCurve( -// new ECFieldFp( -// new BigInteger( -// "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", -// 16)), -// new BigInteger( -// "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", -// 16), -// new BigInteger( -// "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", -// 16)), -// new ECPoint( -// new BigInteger( -// "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", -// 16), -// new BigInteger( -// "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", -// 16)), -// new BigInteger( -// "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", -// 16), 1); -// -// private static final ECParameterSpec P521 = new ECParameterSpec( -// new EllipticCurve( -// new ECFieldFp( -// new BigInteger( -// "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", -// 16)), -// new BigInteger( -// "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", -// 16), -// new BigInteger( -// "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", -// 16)), -// new ECPoint( -// new BigInteger( -// "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", -// 16), -// new BigInteger( -// "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", -// 16)), -// new BigInteger( -// "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", -// 16), 1); -// -// public static final String EC_PARAMS_P192_OID = "1.2.840.10045.3.1.1"; -// public static final String EC_PARAMS_P224_OID = "1.3.132.0.33"; -// public static final String EC_PARAMS_P256_OID = "1.2.840.10045.3.1.7"; -// public static final String EC_PARAMS_P384_OID = "1.3.132.0.34"; -// public static final String EC_PARAMS_P521_OID = "1.3.132.0.35"; -// -// private static Map<String, ECParameterSpec> oidMap = new HashMap<String, ECParameterSpec>(); -// private static Map<ECParameterSpec, String> paramsMap = new HashMap<ECParameterSpec, String>(); -// private static Map<ECParameterSpec, String> friendlyNameMap = new HashMap<ECParameterSpec, String>(); -// -// static { -// oidMap.put(EC_PARAMS_P192_OID, P192); -// oidMap.put(EC_PARAMS_P224_OID, P224); -// oidMap.put(EC_PARAMS_P256_OID, P256); -// oidMap.put(EC_PARAMS_P384_OID, P384); -// oidMap.put(EC_PARAMS_P521_OID, P521); -// paramsMap.put(P192, EC_PARAMS_P192_OID); -// paramsMap.put(P224, EC_PARAMS_P224_OID); -// paramsMap.put(P256, EC_PARAMS_P256_OID); -// paramsMap.put(P384, EC_PARAMS_P384_OID); -// paramsMap.put(P521, EC_PARAMS_P521_OID); -// friendlyNameMap.put(P192, "P-192"); -// friendlyNameMap.put(P224, "P-224"); -// friendlyNameMap.put(P256, "P-256"); -// friendlyNameMap.put(P384, "P-384"); -// friendlyNameMap.put(P521, "P-521"); -// } -// -// public static ECParameterSpec getParams(String oid) { -// ECParameterSpec params; -// if ((params = oidMap.get(oid)) != null) return params; -// throw new IllegalArgumentException("Unsupported EC parameters: " + oid); -// } -// -// public static String getOID(ECParameterSpec params) { -// String oid; -// if ((oid = paramsMap.get(params)) != null) return oid; -// throw new IllegalArgumentException("Unsupport EC parameters"); -// } -// -// public static String getFriendlyName(ECParameterSpec params) { -// String name; -// if ((name = friendlyNameMap.get(params)) != null) return name; -// throw new IllegalArgumentException("Unsupport EC parameters"); -// } -// -// private static final BigInteger ZERO = BigInteger.ZERO; -// private static final BigInteger ONE = BigInteger.ONE; -// private static final BigInteger TWO = BigInteger.valueOf(2); -// END connectbot-removed - private static final BigInteger THREE = BigInteger.valueOf(3); -// BEGIN connectbot-removed -// private static final BigInteger FOUR = BigInteger.valueOf(4); -// private static final BigInteger EIGHT = BigInteger.valueOf(8); -// END connectbot-removed - - private static BigInteger[] doublePointA(BigInteger[] P, - ECParameterSpec params) { - final BigInteger p = ((ECFieldFp) params.getCurve().getField()).getP(); - final BigInteger a = params.getCurve().getA(); - - if (P[0] == null || P[1] == null) return P; - - BigInteger d = (P[0].pow(2).multiply(THREE).add(a)).multiply(P[1] - .shiftLeft(1).modInverse(p)); - BigInteger[] R = new BigInteger[2]; - R[0] = d.pow(2).subtract(P[0].shiftLeft(1)).mod(p); - R[1] = d.multiply(P[0].subtract(R[0])).subtract(P[1]).mod(p); - - return R; - } - - private static BigInteger[] addPointsA(BigInteger[] P1, BigInteger[] P2, - ECParameterSpec params) { - final BigInteger p = ((ECFieldFp) params.getCurve().getField()).getP(); - - if (P2[0] == null || P2[1] == null) return P1; - - if (P1[0] == null || P1[1] == null) return P2; - - BigInteger d = (P2[1].subtract(P1[1])).multiply((P2[0].subtract(P1[0])) - .modInverse(p)); - BigInteger[] R = new BigInteger[2]; - R[0] = d.pow(2).subtract(P1[0]).subtract(P2[0]).mod(p); - R[1] = d.multiply(P1[0].subtract(R[0])).subtract(P1[1]).mod(p); - - return R; - } - - public static BigInteger[] multiplyPointA(BigInteger[] P, BigInteger k, - ECParameterSpec params) { - BigInteger[] Q = new BigInteger[] {null, null}; - - for (int i = k.bitLength() - 1; i >= 0; i--) { - Q = doublePointA(Q, params); - if (k.testBit(i)) Q = addPointsA(Q, P, params); - } - - return Q; - } - -// BEGIN connectbot-removed -// private static BigInteger[] doublePointJ(BigInteger[] P, -// ECParameterSpec params) { -// final BigInteger p = ((ECFieldFp) params.getCurve().getField()).getP(); -// BigInteger A, B, C, D; -// -// if (P[2].signum() == 0) // point at inf -// return P; -// -// A = FOUR.multiply(P[0]).multiply(P[1].pow(2)).mod(p); -// B = EIGHT.multiply(P[1].pow(4)).mod(p); -// C = THREE.multiply(P[0].subtract(P[2].pow(2))).multiply( -// P[0].add(P[2].pow(2))).mod(p); -// D = C.pow(2).subtract(A.add(A)).mod(p); -// -// return new BigInteger[] { -// D, C.multiply(A.subtract(D)).subtract(B).mod(p), -// TWO.multiply(P[1]).multiply(P[2]).mod(p)}; -// } -// -// private static BigInteger[] addPointsJA(BigInteger[] P1, BigInteger[] P2, -// ECParameterSpec params) { -// final BigInteger p = ((ECFieldFp) params.getCurve().getField()).getP(); -// BigInteger A, B, C, D; -// BigInteger X3; -// -// if (P1[2].signum() == 0) // point at inf -// return new BigInteger[] {P2[0], P2[1], ONE}; -// -// A = P2[0].multiply(P1[2].pow(2)).mod(p); -// B = P2[1].multiply(P1[2].pow(3)).mod(p); -// C = A.subtract(P1[0]).mod(p); -// D = B.subtract(P1[1]).mod(p); -// -// X3 = D.pow(2) -// .subtract(C.pow(3).add(TWO.multiply(P1[0]).multiply(C.pow(2)))).mod(p); -// return new BigInteger[] { -// X3, -// D.multiply(P1[0].multiply(C.pow(2)).subtract(X3)).subtract( -// P1[1].multiply(C.pow(3))).mod(p), P1[2].multiply(C).mod(p)}; -// } -// -// // Binary NAF method for point multiplication -// public static BigInteger[] multiplyPoint(BigInteger[] P, BigInteger k, -// ECParameterSpec params) { -// BigInteger h = THREE.multiply(k); -// -// BigInteger[] Pneg = new BigInteger[] {P[0], P[1].negate()}; -// BigInteger[] R = new BigInteger[] {P[0], P[1], ONE}; -// -// int bitLen = h.bitLength(); -// for (int i = bitLen - 2; i > 0; --i) { -// R = doublePointJ(R, params); -// if (h.testBit(i)) R = addPointsJA(R, P, params); -// if (k.testBit(i)) R = addPointsJA(R, Pneg, params); -// } -// -// // // <DEBUG> -// // BigInteger[] SS = new BigInteger[] { R[0], R[1], R[2] }; -// // toAffine(SS, params); -// // BigInteger[] RR = multiplyPointA(P, k, params); -// // if (!SS[0].equals(RR[0]) || !SS[1].equals(RR[1])) -// // throw new RuntimeException("Internal mult error"); -// // // </DEBUG> -// -// return R; -// } - -// // Simultaneous multiple point multiplication, also known as Shamir's trick -// static BigInteger[] multiplyPoints(BigInteger[] P, BigInteger k, -// BigInteger[] Q, BigInteger l, ECParameterSpec params) { -// BigInteger[] PQ = addPointsA(P, Q, params); -// BigInteger[] R = new BigInteger[] {null, null, ZERO}; -// -// int max = Math.max(k.bitLength(), l.bitLength()); -// for (int i = max - 1; i >= 0; --i) { -// R = doublePointJ(R, params); -// if (k.testBit(i)) { -// if (l.testBit(i)) -// R = addPointsJA(R, PQ, params); -// else -// R = addPointsJA(R, P, params); -// } else if (l.testBit(i)) R = addPointsJA(R, Q, params); -// } -// -// // // <DEBUG> -// // BigInteger[] SS = new BigInteger[] { R[0], R[1], R[2] }; -// // toAffine(SS, params); -// // BigInteger[] AA = multiplyPointA(P, k, params); -// // BigInteger[] BB = multiplyPointA(Q, l, params); -// // BigInteger[] AB = addPointsA(AA, BB, params); -// // if (!SS[0].equals(AB[0]) || !SS[1].equals(AB[1])) -// // throw new RuntimeException("Internal mult error"); -// // // </DEBUG> -// -// return R; -// } -// -// // SEC 1, 2.3.5 -// static byte[] fieldElemToBytes(BigInteger a, ECParameterSpec params) { -// int len = (((ECFieldFp) params.getCurve().getField()).getP().bitLength() + 7) / 8; -// byte[] bytes = a.toByteArray(); -// if (len < bytes.length) { -// byte[] tmp = new byte[len]; -// System.arraycopy(bytes, bytes.length - tmp.length, tmp, 0, tmp.length); -// return tmp; -// } else if (len > bytes.length) { -// byte[] tmp = new byte[len]; -// System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length); -// return tmp; -// } -// return bytes; -// } -// -// static int fieldElemToBytes(BigInteger a, ECParameterSpec params, -// byte[] data, int off) { -// int len = (((ECFieldFp) params.getCurve().getField()).getP().bitLength() + 7) / 8; -// byte[] bytes = a.toByteArray(); -// if (len < bytes.length) { -// System.arraycopy(bytes, bytes.length - len, data, off, len); -// return len; -// } else if (len > bytes.length) { -// System.arraycopy(bytes, 0, data, len - bytes.length + off, bytes.length); -// return len; -// } -// System.arraycopy(bytes, 0, data, off, bytes.length); -// return bytes.length; -// } -// -// // SEC 1, 2.3.3 -// static byte[] ecPointToBytes(ECPoint a, ECParameterSpec params) { -// byte[] fe1 = fieldElemToBytes(a.getAffineX(), params); -// byte[] fe2 = fieldElemToBytes(a.getAffineY(), params); -// byte[] bytes = new byte[1 + fe1.length + fe2.length]; -// bytes[0] = 0x04; -// System.arraycopy(fe1, 0, bytes, 1, fe1.length); -// System.arraycopy(fe2, 0, bytes, 1 + fe1.length, fe2.length); -// return bytes; -// } -// -// // SEC 1, 2.3.4 -// static ECPoint bytesToECPoint(byte[] bytes, ECParameterSpec params) { -// switch (bytes[0]) { -// case 0x00: // point at inf -// throw new IllegalArgumentException( -// "Point at infinity is not a valid argument"); -// case 0x02: // point compression -// case 0x03: -// throw new UnsupportedOperationException( -// "Point compression is not supported"); -// case 0x04: -// final BigInteger p = ((ECFieldFp) params.getCurve().getField()).getP(); -// byte[] fe = new byte[(p.bitLength() + 7) / 8]; -// System.arraycopy(bytes, 1, fe, 0, fe.length); -// BigInteger x = new BigInteger(1, fe); -// System.arraycopy(bytes, 1 + fe.length, fe, 0, fe.length); -// return new ECPoint(x, new BigInteger(1, fe)); -// default: -// throw new IllegalArgumentException("Invalid point encoding"); -// } -// } -// -// // Convert Jacobian point to affine -// static void toAffine(BigInteger[] P, ECParameterSpec params) { -// final BigInteger p = ((ECFieldFp) params.getCurve().getField()).getP(); -// P[0] = P[0].multiply(P[2].pow(2).modInverse(p)).mod(p); -// P[1] = P[1].multiply(P[2].pow(3).modInverse(p)).mod(p); -// } -// -// static void toAffineX(BigInteger[] P, ECParameterSpec params) { -// final BigInteger p = ((ECFieldFp) params.getCurve().getField()).getP(); -// P[0] = P[0].multiply(P[2].pow(2).modInverse(p)).mod(p); -// } -// -// static BigInteger[] internalPoint(ECPoint P) { -// return new BigInteger[] {P.getAffineX(), P.getAffineY()}; -// } -// -// // private static void printPerf(String msg, long start, long stop) { -// // String unit = "ms"; -// // long diff = stop - start; -// // if (diff > 1000) { -// // diff /= 1000; -// // unit = "s"; -// // } -// // System.out.printf("%s: %d %s\n", msg, diff, unit); -// // } -// -// public static void main(String[] args) throws Exception { -// -// Security.insertProviderAt(new EcCore(), 0); -// -// // ---- -// // Test primitives -// // ---- -// -// // GooKey EC private key, 256 bit -// // Private value: -// // a9231e0d113abdacd3bb5edb24124fbef6f562c5f90b835670f5e48f775019f2 -// // Parameters: P-256 (1.2.840.10045.3.1.7) -// // GooKey EC public key, 256 bit -// // Public value (x coordinate): -// // 86645e0320c0f9dc1a9b8456396cc105754df67a9829c21e13ab6ecf944cf68c -// // Public value (y coordinate): -// // ea1721a578043d48f12738359b5eb5f0dac2242ec6128ee0ab6ff40c8fe0cae6 -// // Parameters: P-256 (1.2.840.10045.3.1.7) -// // GooKey EC private key, 256 bit -// // Private value: -// // b84d5cfab214fc3928864abb85f668a85b1006ca0147c78f22deb1dcc7e4a022 -// // Parameters: P-256 (1.2.840.10045.3.1.7) -// // GooKey EC public key, 256 bit -// // Public value (x coordinate): -// // 61f6f7264f0a19f0debcca3efd079667a0112cc0b8be07a815b4c375e96ad3d1 -// // Public value (y coordinate): -// // 3308c0016d776ed5aa9f021e43348b2e684b3b7a0f25dc9e4c8670b5d87cb705 -// // Parameters: P-256 (1.2.840.10045.3.1.7) -// -// // P = kG -// BigInteger k = new BigInteger( -// "a9231e0d113abdacd3bb5edb24124fbef6f562c5f90b835670f5e48f775019f2", 16); -// BigInteger[] P = new BigInteger[] { -// new BigInteger( -// "86645e0320c0f9dc1a9b8456396cc105754df67a9829c21e13ab6ecf944cf68c", -// 16), -// new BigInteger( -// "ea1721a578043d48f12738359b5eb5f0dac2242ec6128ee0ab6ff40c8fe0cae6", -// 16), ONE}; -// -// // Q = lG -// BigInteger l = new BigInteger( -// "b84d5cfab214fc3928864abb85f668a85b1006ca0147c78f22deb1dcc7e4a022", 16); -// BigInteger[] Q = new BigInteger[] { -// new BigInteger( -// "61f6f7264f0a19f0debcca3efd079667a0112cc0b8be07a815b4c375e96ad3d1", -// 16), -// new BigInteger( -// "3308c0016d776ed5aa9f021e43348b2e684b3b7a0f25dc9e4c8670b5d87cb705", -// 16), ONE}; -// -// // Known answer for P+Q -// BigInteger[] kat1 = new BigInteger[] { -// new BigInteger( -// "bc7adb05bca2460bbfeb4e0f88b61c384ea88ed3fd56017938ac2582513d4220", -// 16), -// new BigInteger( -// "a640a43df2e9df39eec11445b7e3f7835b743ef1ac4a83cecb570a060b3f1c6c", -// 16)}; -// -// BigInteger[] R = addPointsA(P, Q, P256); -// if (!R[0].equals(kat1[0]) || !R[1].equals(kat1[1])) -// throw new RuntimeException("kat1 failed"); -// -// R = addPointsJA(P, Q, P256); -// toAffine(R, P256); -// if (!R[0].equals(kat1[0]) || !R[1].equals(kat1[1])) -// throw new RuntimeException("kat1 failed"); -// -// -// // Known answer for Q+Q -// BigInteger[] kat2 = new BigInteger[] { -// new BigInteger( -// "c79d7f9100c14a70f0bb9bdce59654abf99e10d1ac5afc1a0f1b6bc650d6429b", -// 16), -// new BigInteger( -// "6856814e47adce42bc0d7c3bef308c6c737c418ed093effb31e21f53c7735c97", -// 16)}; -// -// R = doublePointA(P, P256); -// if (!R[0].equals(kat2[0]) || !R[1].equals(kat2[1])) -// throw new RuntimeException("kat2 failed"); -// -// R = doublePointJ(P, P256); -// toAffine(R, P256); -// if (!R[0].equals(kat2[0]) || !R[1].equals(kat2[1])) -// throw new RuntimeException("kat2 failed"); -// -// // Known answer for kP -// BigInteger[] kat3 = new BigInteger[] { -// new BigInteger( -// "97a82a834b9e6b50660ae30d43dac9b200276e8bcd2ed6a6593048de09276d1a", -// 16), -// new BigInteger( -// "30a9590a01066d8ef54a910afcc8648dbc7400c01750af423ce95547f2154d56", -// 16)}; -// -// R = multiplyPointA(P, k, P256); -// if (!R[0].equals(kat3[0]) || !R[1].equals(kat3[1])) -// throw new RuntimeException("kat3 failed"); -// -// R = multiplyPoint(P, k, P256); -// toAffine(R, P256); -// if (!R[0].equals(kat3[0]) || !R[1].equals(kat3[1])) -// throw new RuntimeException("kat3 failed"); -// -// // Known answer for kP+lQ -// BigInteger[] kat4 = new BigInteger[] { -// new BigInteger( -// "6fd51be5cf3d6a6bcb62594bbe41ccf549b37d8fefff6e293a5bea0836efcfc6", -// 16), -// new BigInteger( -// "9bc21a930137aa3814908974c431e4545a05dce61321253c337f3883129c42ca", -// 16)}; -// -// BigInteger[] RR = multiplyPointA(Q, l, P256); -// R = addPointsA(R, RR, P256); -// if (!R[0].equals(kat4[0]) || !R[1].equals(kat4[1])) -// throw new RuntimeException("kat4 failed"); -// -// R = multiplyPoints(P, k, Q, l, P256); -// toAffine(R, P256); -// if (!R[0].equals(kat4[0]) || !R[1].equals(kat4[1])) -// throw new RuntimeException("kat4 failed"); -// -// // ---- -// // Test ECDSA in various combinations -// // ---- -// -// Provider gooProv = Security.getProvider("GooKey"); -// Provider nssProv = Security.getProvider("SunPKCS11-NSS"); -// -// // Number of iterations: trust me, this is a (stress) good test -// // and does provoke bugs in a fuzzing way. -// int iter = 50; -// -// // Iterate over all key lengths and signature schemes. -// int[] keyLengths = {192, 224, 256, 384, 521}; -// String[] ecdsas = { -// "SHA1withECDSA", "SHA256withECDSA", "SHA384withECDSA", -// "SHA512withECDSA"}; -// for (int s = 0; s < ecdsas.length; s++) { -// System.out.println("Signature scheme " + ecdsas[s]); -// for (int i = 0; i < keyLengths.length; i++) { -// System.out.print("Testing P-" + keyLengths[i] + ": "); -// for (int n = 0; n < iter; n++) { -// System.out.print("."); -// -// KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", gooProv); -// kpGen.initialize(keyLengths[i]); -// KeyPair ecKeyPair = kpGen.generateKeyPair(); -// -// ECPrivateKey ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); -// byte[] tmp = ecPrivKey.getEncoded(); -// KeyFactory keyFab = KeyFactory.getInstance("EC", gooProv); -// keyFab.generatePrivate(new PKCS8EncodedKeySpec(tmp)); -// ECPrivateKeySpec ecPrivSpec = new ECPrivateKeySpec(ecPrivKey.getS(), -// ecPrivKey.getParams()); -// keyFab.generatePrivate(ecPrivSpec); -// -// ECPublicKey ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); -// tmp = ecPubKey.getEncoded(); // dont modify tmp now - is used below -// keyFab.generatePublic(new X509EncodedKeySpec(tmp)); -// ECPublicKeySpec ecPubSpec = new ECPublicKeySpec(ecPubKey.getW(), -// ecPubKey.getParams()); -// keyFab.generatePublic(ecPubSpec); -// -// Signature ecdsa = Signature.getInstance(ecdsas[s], gooProv); -// ecdsa.initSign(ecPrivKey); -// ecdsa.update(tmp); -// byte[] sig = ecdsa.sign(); -// ecdsa.initVerify(ecPubKey); -// ecdsa.update(tmp); -// if (!ecdsa.verify(sig)) -// throw new RuntimeException("Signature not verified: " -// + keyLengths[i]); -// -// // Cross verify using NSS if present -// if (nssProv != null) { -// keyFab = KeyFactory.getInstance("EC", nssProv); -// -// // For some reason NSS doesnt seem to work for P-192 and P-224?! -// if (keyLengths[i] == 192 || keyLengths[i] == 224) continue; -// -// ECPrivateKey nssPrivKey = (ECPrivateKey) keyFab -// .generatePrivate(new PKCS8EncodedKeySpec(ecPrivKey.getEncoded())); -// ECPublicKey nssPubKey = (ECPublicKey) keyFab -// .generatePublic(new X509EncodedKeySpec(ecPubKey.getEncoded())); -// -// ecdsa = Signature.getInstance(ecdsas[s], nssProv); -// ecdsa.initVerify(nssPubKey); -// ecdsa.update(tmp); -// if (!ecdsa.verify(sig)) -// throw new RuntimeException("Signature not verified 2: " -// + keyLengths[i]); -// -// ecdsa.initSign(nssPrivKey); -// ecdsa.update(tmp); -// sig = ecdsa.sign(); -// ecdsa = Signature.getInstance(ecdsas[s], gooProv); -// ecdsa.initVerify(ecPubKey); -// ecdsa.update(tmp); -// if (!ecdsa.verify(sig)) -// throw new RuntimeException("Signature not verified 3: " -// + keyLengths[i]); -// } -// } -// System.out.println(" done"); -// } -// } -// -// // Test Keyczar integration -// // Signer ecdsaSigner = new Signer("c:\\temp\\eckeyset"); -// // String tbs = "Sign this"; -// // String sig = ecdsaSigner.sign(tbs); -// // if (ecdsaSigner.verify(sig, tbs)) -// // System.out.println("Keyczar EC OK"); -// // else -// // System.out.println("Keyczar EC not OK"); -// } -//END connectbot-removed -} diff --git a/src/org/openintents/intents/FileManagerIntents.java b/src/org/openintents/intents/FileManagerIntents.java deleted file mode 100644 index fba2555..0000000 --- a/src/org/openintents/intents/FileManagerIntents.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2008 OpenIntents.org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.openintents.intents; - -// Version Dec 9, 2008 - - -/** - * Provides OpenIntents actions, extras, and categories used by providers. - * <p>These specifiers extend the standard Android specifiers.</p> - */ -public final class FileManagerIntents { - - /** - * Activity Action: Pick a file through the file manager, or let user - * specify a custom file name. - * Data is the current file name or file name suggestion. - * Returns a new file name as file URI in data. - * - * <p>Constant Value: "org.openintents.action.PICK_FILE"</p> - */ - public static final String ACTION_PICK_FILE = "org.openintents.action.PICK_FILE"; - - /** - * Activity Action: Pick a directory through the file manager, or let user - * specify a custom file name. - * Data is the current directory name or directory name suggestion. - * Returns a new directory name as file URI in data. - * - * <p>Constant Value: "org.openintents.action.PICK_DIRECTORY"</p> - */ - public static final String ACTION_PICK_DIRECTORY = "org.openintents.action.PICK_DIRECTORY"; - - /** - * The title to display. - * - * <p>This is shown in the title bar of the file manager.</p> - * - * <p>Constant Value: "org.openintents.extra.TITLE"</p> - */ - public static final String EXTRA_TITLE = "org.openintents.extra.TITLE"; - - /** - * The text on the button to display. - * - * <p>Depending on the use, it makes sense to set this to "Open" or "Save".</p> - * - * <p>Constant Value: "org.openintents.extra.BUTTON_TEXT"</p> - */ - public static final String EXTRA_BUTTON_TEXT = "org.openintents.extra.BUTTON_TEXT"; - -} |