type) {
97 | return themeDefinition.getRenderer(type);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Theme/MainTheme.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Theme;
2 | import com.googlecode.lanterna.graphics.*;
3 | import com.googlecode.lanterna.TextColor;
4 |
5 | public class MainTheme extends DelegatingThemeDefinition {
6 |
7 | public MainTheme(ThemeDefinition definition) {
8 | super(definition);
9 | }
10 |
11 |
12 |
13 | @Override
14 | public ThemeStyle getActive() {
15 | DefaultMutableThemeStyle mutableThemeStyle = new DefaultMutableThemeStyle(super.getActive());
16 | return mutableThemeStyle.setBackground(TextColor.Factory.fromString("MAGENTA"));
17 | }
18 |
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Utils/ByteBuilder.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Utils;
2 |
3 | public class ByteBuilder
4 | {
5 | public byte[] data = new byte[]{};
6 |
7 | public ByteBuilder(){
8 |
9 | }
10 |
11 | public void clean()
12 | {
13 | this.data = new byte[]{};
14 | }
15 |
16 | public void writebytesbylength(byte[] to_write)
17 | {
18 | this.writeint(to_write.length);
19 | this.writebytes(to_write);
20 | }
21 |
22 |
23 | public void writebytes(byte[] to_write){
24 | this.data = Util.byteMerger(this.data,to_write);
25 | }
26 |
27 | public void rewritebytes(byte[] to_write){
28 | this.data = Util.byteMerger(to_write,this.data);
29 | }
30 |
31 | public void writebyte(byte to_write){
32 | this.data = Util.byteMerger(this.data,new byte[]{to_write});
33 | }
34 |
35 | public void writeint(int to_write){
36 | byte[] test = Util.subByte(Util.ToByte(to_write),2,2);
37 |
38 | this.data = Util.byteMerger(this.data,test);
39 | }
40 | public void rewriteint(int to_write)
41 | {
42 | byte[] test = Util.subByte(Util.ToByte(to_write),2,2);
43 |
44 | this.data = Util.byteMerger(test,this.data);
45 | }
46 |
47 |
48 | public void writelong(long to_write){
49 | byte[] test = Util.subByte(Util.ToByte(to_write),4,4);
50 |
51 | this.data = Util.byteMerger(this.data,test);
52 | }
53 | public void writeshort(short to_write){
54 | byte[] test = Util.subByte(Util.ToByte(to_write),0,4);
55 |
56 | this.data = Util.byteMerger(this.data,test);
57 | }
58 |
59 | public byte[] getdata(){
60 | return this.data;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Utils/ByteFactory.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Utils;
2 |
3 | public class ByteFactory
4 | {
5 | public int position = 0;
6 | public byte[] data = null;
7 | public ByteFactory(byte[] _data){
8 | this.data=_data;
9 | }
10 |
11 | public byte[] readrestBytes()
12 | {
13 | int length = this.data.length -this.position;
14 | byte[] test = Util.subByte(this.data,this.position,length);
15 | this.position +=length;
16 | return test;
17 | }
18 |
19 |
20 |
21 | public String readStringbylength(){
22 | int length = Util.GetInt(Util.subByte(this.data,this.position,2));
23 | this.position +=2;
24 | byte[] test = Util.subByte(this.data,position,length);
25 | this.position +=length;
26 | return new String(test);
27 | }
28 |
29 | public String readString(int length)
30 | {
31 | byte[] test = Util.subByte(this.data,position,length);
32 | this.position +=length;
33 | return new String(test);
34 | }
35 |
36 |
37 | public byte[] readBytesbylength(){
38 | int length = Util.GetInt(Util.subByte(this.data,this.position,2));
39 | this.position +=2;
40 | byte[] test = Util.subByte(this.data,position,length);
41 | this.position +=length;
42 | return test;
43 | }
44 |
45 | public byte[] readBytes(int length){
46 | byte[] test = Util.subByte(this.data,this.position,length);
47 | this.position +=length;
48 | return test;
49 | }
50 |
51 |
52 |
53 | public int readint(){
54 | int test = Util.GetInt(Util.subByte(this.data,this.position,2));
55 | this.position +=2;
56 | return test;
57 | }
58 |
59 |
60 |
61 | public long readlong()
62 | {
63 | long test = Util.GetLong(Util.subByte(this.data,this.position,4));
64 | this.position +=4;
65 | return test;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Utils/Crypter.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Utils;
2 | import java.io.ByteArrayOutputStream;
3 | import java.util.Random;
4 |
5 | /**
6 | * 加密解密QQ消息的工具类. QQ消息的加密算法是一个16次的迭代过程,并且是反馈的,每一个加密单元是8字节,输出也是8字节,密钥是16字节
7 | * 我们以prePlain表示前一个明文块,plain表示当前明文块,crypt表示当前明文块加密得到的密文块,preCrypt表示前一个密文块
8 | * f表示加密算法,d表示解密算法 那么从plain得到crypt的过程是: crypt = f(plain ˆ preCrypt) ˆ
9 | * prePlain 所以,从crypt得到plain的过程自然是 plain = d(crypt ˆ prePlain) ˆ
10 | * preCrypt 此外,算法有它的填充机制,其会在明文前和明文后分别填充一定的字节数,以保证明文长度是8字节的倍数
11 | * 填充的字节数与原始明文长度有关,填充的方法是:
12 | *
13 | *
14 | * *
15 | * ------- 消息填充算法 -----------
16 | * a = (明文长度 + 10) mod 8
17 | * if(a 不等于 0) a = 8 - a;
18 | * b = 随机数 & 0xF8 | a; 这个的作用是把a的值保存了下来
19 | * plain[0] = b; 然后把b做为明文的第0个字节,这样第0个字节就保存了a的信息,这个信息在解密时就要用来找到真正明文的起始位置
20 | * plain[1 至 a+2] = 随机数 & 0xFF; 这里用随机数填充明文的第1到第a+2个字节
21 | * plain[a+3 至 a+3+明文长度-1] = 明文; 从a+3字节开始才是真正的明文
22 | * plain[a+3+明文长度, 最后] = 0; 在最后,填充0,填充到总长度为8的整数为止。到此为止,结束了,这就是最后得到的要加密的明文内容
23 | * ------- 消息填充算法 ------------ *
24 | *
25 | *
26 | */
27 | public class Crypter {
28 | // 指向当前的明文块
29 | private byte[] plain;
30 | // 这指向前面一个明文块
31 | private byte[] prePlain;
32 | // 输出的密文或者明文
33 | private byte[] out;
34 | // 当前加密的密文位置和上一次加密的密文块位置,他们相差8
35 | private int crypt, preCrypt;
36 | // 当前处理的加密解密块的位置
37 | private int pos;
38 | // 填充数
39 | private int padding;
40 | // 密钥
41 | private byte[] key;
42 | // 用于加密时,表示当前是否是第一个8字节块,因为加密算法是反馈的
43 | // 但是最开始的8个字节没有反馈可用,所有需要标明这种情况
44 | private boolean header = true;
45 | // 这个表示当前解密开始的位置,之所以要这么一个变量是为了避免当解密到最后时
46 | // 后面已经没有数据,这时候就会出错,这个变量就是用来判断这种情况免得出错
47 | private int contextStart;
48 | // 随机数对象
49 | private static Random random = CrypterUtil.random();
50 | // 字节输出流
51 | private ByteArrayOutputStream baos;
52 |
53 | /**
54 | * 构造函数
55 | */
56 | public Crypter() {
57 | baos = new ByteArrayOutputStream(8);
58 | }
59 |
60 | /**
61 | * 解密
62 | * @param in 密文
63 | * @param offset 密文开始的位置
64 | * @param len 密文长度
65 | * @param k 密钥
66 | * @return 明文
67 | */
68 | public byte[] decrypt(byte[] in, int offset, int len, byte[] k) {
69 | // 检查密钥
70 | if(k == null)
71 | return null;
72 |
73 | crypt = preCrypt = 0;
74 | this.key = k;
75 | int count;
76 | byte[] m = new byte[offset + 8];
77 |
78 | // 因为QQ消息加密之后至少是16字节,并且肯定是8的倍数,这里检查这种情况
79 | if((len % 8 != 0) || (len < 16)) return null;
80 | // 得到消息的头部,关键是得到真正明文开始的位置,这个信息存在第一个字节里面,所以其用解密得到的第一个字节与7做与
81 | prePlain = decipher(in, offset);
82 | pos = prePlain[0] & 0x7;
83 | // 得到真正明文的长度
84 | count = len - pos - 10;
85 | // 如果明文长度小于0,那肯定是出错了,比如传输错误之类的,返回
86 | if(count < 0) return null;
87 |
88 | // 这个是临时的preCrypt,和加密时第一个8字节块没有prePlain一样,解密时
89 | // 第一个8字节块也没有preCrypt,所有这里建一个全0的
90 | for(int i = offset; i < m.length; i++)
91 | m[i] = 0;
92 | // 通过了上面的代码,密文应该是没有问题了,我们分配输出缓冲区
93 | out = new byte[count];
94 | // 设置preCrypt的位置等于0,注意目前的preCrypt位置是指向m的,因为java没有指针,所以我们在后面要控制当前密文buf的引用
95 | preCrypt = 0;
96 | // 当前的密文位置,为什么是8不是0呢?注意前面我们已经解密了头部信息了,现在当然该8了
97 | crypt = 8;
98 | // 自然这个也是8
99 | contextStart = 8;
100 | // 加1,和加密算法是对应的
101 | pos++;
102 |
103 | // 开始跳过头部,如果在这个过程中满了8字节,则解密下一块
104 | // 因为是解密下一块,所以我们有一个语句 m = in,下一块当然有preCrypt了,我们不再用m了
105 | // 但是如果不满8,这说明了什么?说明了头8个字节的密文是包含了明文信息的,当然还是要用m把明文弄出来
106 | // 所以,很显然,满了8的话,说明了头8个字节的密文除了一个长度信息有用之外,其他都是无用的填充
107 | padding = 1;
108 | while(padding <= 2) {
109 | if(pos < 8) {
110 | pos++;
111 | padding++;
112 | }
113 | if(pos == 8) {
114 | m = in;
115 | if(!decrypt8Bytes(in, offset, len)) return null;
116 | }
117 | }
118 |
119 | // 这里是解密的重要阶段,这个时候头部的填充都已经跳过了,开始解密
120 | // 注意如果上面一个while没有满8,这里第一个if里面用的就是原始的m,否则这个m就是in了
121 | int i = 0;
122 | while(count != 0) {
123 | if(pos < 8) {
124 | out[i] = (byte)(m[offset + preCrypt + pos] ^ prePlain[pos]);
125 | i++;
126 | count--;
127 | pos++;
128 | }
129 | if(pos == 8) {
130 | m = in;
131 | preCrypt = crypt - 8;
132 | if(!decrypt8Bytes(in, offset, len))
133 | return null;
134 | }
135 | }
136 |
137 | // 最后的解密部分,上面一个while已经把明文都解出来了,就剩下尾部的填充了,应该全是0
138 | // 所以这里有检查是否解密了之后是不是0,如果不是的话那肯定出错了,返回null
139 | for(padding = 1; padding < 8; padding++) {
140 | if(pos < 8) {
141 | if((m[offset + preCrypt + pos] ^ prePlain[pos]) != 0)
142 | return null;
143 | pos++;
144 | }
145 | if(pos == 8) {
146 | m = in;
147 | preCrypt = crypt;
148 | if(!decrypt8Bytes(in, offset, len))
149 | return null;
150 | }
151 | }
152 | return out;
153 | }
154 |
155 | /**
156 | * @param in
157 | * 需要被解密的密文
158 | * @param inLen
159 | * 密文长度
160 | * @param k
161 | * 密钥
162 | * @return Message 已解密的消息
163 | */
164 | public byte[] decrypt(byte[] in, byte[] k) {
165 | return decrypt(in, 0, in.length, k);
166 | }
167 |
168 | /**
169 | * 加密
170 | * @param in 明文字节数组
171 | * @param offset 开始加密的偏移
172 | * @param len 加密长度
173 | * @param k 密钥
174 | * @return 密文字节数组
175 | */
176 | public byte[] encrypt(byte[] in, int offset, int len, byte[] k) {
177 | // 检查密钥
178 | if(k == null)
179 | return in;
180 |
181 | plain = new byte[8];
182 | prePlain = new byte[8];
183 | pos = 1;
184 | padding = 0;
185 | crypt = preCrypt = 0;
186 | this.key = k;
187 | header = true;
188 |
189 | // 计算头部填充字节数
190 | pos = (len + 0x0A) % 8;
191 | if(pos != 0)
192 | pos = 8 - pos;
193 | // 计算输出的密文长度
194 | out = new byte[len + pos + 10];
195 | // 这里的操作把pos存到了plain的第一个字节里面
196 | // 0xF8后面三位是空的,正好留给pos,因为pos是0到7的值,表示文本开始的字节位置
197 | plain[0] = (byte)((rand() & 0xF8) | pos);
198 |
199 | // 这里用随机产生的数填充plain[1]到plain[pos]之间的内容
200 | for(int i = 1; i <= pos; i++)
201 | plain[i] = (byte)(rand() & 0xFF);
202 | pos++;
203 | // 这个就是prePlain,第一个8字节块当然没有prePlain,所以我们做一个全0的给第一个8字节块
204 | for(int i = 0; i < 8; i++)
205 | prePlain[i] = 0x0;
206 |
207 | // 继续填充2个字节的随机数,这个过程中如果满了8字节就加密之
208 | padding = 1;
209 | while(padding <= 2) {
210 | if(pos < 8) {
211 | plain[pos++] = (byte)(rand() & 0xFF);
212 | padding++;
213 | }
214 | if(pos == 8)
215 | encrypt8Bytes();
216 | }
217 |
218 | // 头部填充完了,这里开始填真正的明文了,也是满了8字节就加密,一直到明文读完
219 | int i = offset;
220 | while(len > 0) {
221 | if(pos < 8) {
222 | plain[pos++] = in[i++];
223 | len--;
224 | }
225 | if(pos == 8)
226 | encrypt8Bytes();
227 | }
228 |
229 | // 最后填上0,以保证是8字节的倍数
230 | padding = 1;
231 | while(padding <= 7) {
232 | if(pos < 8) {
233 | plain[pos++] = 0x0;
234 | padding++;
235 | }
236 | if(pos == 8)
237 | encrypt8Bytes();
238 | }
239 |
240 | return out;
241 | }
242 |
243 | /**
244 | * @param in
245 | * 需要加密的明文
246 | * @param inLen
247 | * 明文长度
248 | * @param k
249 | * 密钥
250 | * @return Message 密文
251 | */
252 | public byte[] encrypt(byte[] in, byte[] k) {
253 | return encrypt(in, 0, in.length, k);
254 | }
255 |
256 | /**
257 | * 加密一个8字节块
258 | *
259 | * @param in
260 | * 明文字节数组
261 | * @return
262 | * 密文字节数组
263 | */
264 | private byte[] encipher(byte[] in) {
265 | // 迭代次数,16次
266 | int loop = 0x10;
267 | // 得到明文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数
268 | // 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的
269 | // 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与
270 | long y = CrypterUtil.getUnsignedInt(in, 0, 4);
271 | long z = CrypterUtil.getUnsignedInt(in, 4, 4);
272 | long a = CrypterUtil.getUnsignedInt(key, 0, 4);
273 | long b = CrypterUtil.getUnsignedInt(key, 4, 4);
274 | long c = CrypterUtil.getUnsignedInt(key, 8, 4);
275 | long d = CrypterUtil.getUnsignedInt(key, 12, 4);
276 | // 这是算法的一些控制变量,为什么delta是0x9E3779B9呢?
277 | // 这个数是TEA算法的delta,实际是就是(sqr(5) - 1) * 2^31 (根号5,减1,再乘2的31次方)
278 | long sum = 0;
279 | long delta = 0x9E3779B9;
280 | delta &= 0xFFFFFFFFL;
281 |
282 | // 开始迭代了,乱七八糟的,我也看不懂,反正和DES之类的差不多,都是这样倒来倒去
283 | while (loop-- > 0) {
284 | sum += delta;
285 | sum &= 0xFFFFFFFFL;
286 | y += ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b);
287 | y &= 0xFFFFFFFFL;
288 | z += ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d);
289 | z &= 0xFFFFFFFFL;
290 | }
291 |
292 | // 最后,我们输出密文,因为我用的long,所以需要强制转换一下变成int
293 | baos.reset();
294 | writeInt((int)y);
295 | writeInt((int)z);
296 | return baos.toByteArray();
297 | }
298 |
299 | /**
300 | * 解密从offset开始的8字节密文
301 | *
302 | * @param in
303 | * 密文字节数组
304 | * @param offset
305 | * 密文开始位置
306 | * @return
307 | * 明文
308 | */
309 | private byte[] decipher(byte[] in, int offset) {
310 | // 迭代次数,16次
311 | int loop = 0x10;
312 | // 得到密文和密钥的各个部分,注意java没有无符号类型,所以为了表示一个无符号的整数
313 | // 我们用了long,这个long的前32位是全0的,我们通过这种方式模拟无符号整数,后面用到的long也都是一样的
314 | // 而且为了保证前32位为0,需要和0xFFFFFFFF做一下位与
315 | long y = CrypterUtil.getUnsignedInt(in, offset, 4);
316 | long z = CrypterUtil.getUnsignedInt(in, offset + 4, 4);
317 | long a = CrypterUtil.getUnsignedInt(key, 0, 4);
318 | long b = CrypterUtil.getUnsignedInt(key, 4, 4);
319 | long c = CrypterUtil.getUnsignedInt(key, 8, 4);
320 | long d = CrypterUtil.getUnsignedInt(key, 12, 4);
321 | // 算法的一些控制变量,sum在这里也有数了,这个sum和迭代次数有关系
322 | // 因为delta是这么多,所以sum如果是这么多的话,迭代的时候减减减,减16次,最后
323 | // 得到0。反正这就是为了得到和加密时相反顺序的控制变量,这样才能解密呀~~
324 | long sum = 0xE3779B90;
325 | sum &= 0xFFFFFFFFL;
326 | long delta = 0x9E3779B9;
327 | delta &= 0xFFFFFFFFL;
328 |
329 | // 迭代开始了, @_@
330 | while(loop-- > 0) {
331 | z -= ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d);
332 | z &= 0xFFFFFFFFL;
333 | y -= ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b);
334 | y &= 0xFFFFFFFFL;
335 | sum -= delta;
336 | sum &= 0xFFFFFFFFL;
337 | }
338 |
339 | baos.reset();
340 | writeInt((int)y);
341 | writeInt((int)z);
342 | return baos.toByteArray();
343 | }
344 |
345 | /**
346 | * 写入一个整型到输出流,高字节优先
347 | *
348 | * @param t
349 | */
350 | private void writeInt(int t) {
351 | baos.write(t >>> 24);
352 | baos.write(t >>> 16);
353 | baos.write(t >>> 8);
354 | baos.write(t);
355 | }
356 |
357 | /**
358 | * 解密
359 | *
360 | * @param in
361 | * 密文
362 | * @return
363 | * 明文
364 | */
365 | private byte[] decipher(byte[] in) {
366 | return decipher(in, 0);
367 | }
368 |
369 | /**
370 | * 加密8字节
371 | */
372 | private void encrypt8Bytes() {
373 | // 这部分完成我上面所说的 plain ^ preCrypt,注意这里判断了是不是第一个8字节块,如果是的话,那个prePlain就当作preCrypt用
374 | for(pos = 0; pos < 8; pos++) {
375 | if(header)
376 | plain[pos] ^= prePlain[pos];
377 | else
378 | plain[pos] ^= out[preCrypt + pos];
379 | }
380 | // 这个完成我上面说的 f(plain ^ preCrypt)
381 | byte[] crypted = encipher(plain);
382 | // 这个没什么,就是拷贝一下,java不像c,所以我只好这么干,c就不用这一步了
383 | System.arraycopy(crypted, 0, out, crypt, 8);
384 |
385 | // 这个完成了 f(plain ^ preCrypt) ^ prePlain,ok,下面拷贝一下就行了
386 | for(pos = 0; pos < 8; pos++)
387 | out[crypt + pos] ^= prePlain[pos];
388 | System.arraycopy(plain, 0, prePlain, 0, 8);
389 |
390 | // 完成了加密,现在是调整crypt,preCrypt等等东西的时候了
391 | preCrypt = crypt;
392 | crypt += 8;
393 | pos = 0;
394 | header = false;
395 | }
396 |
397 | /**
398 | * 解密8个字节
399 | *
400 | * @param in
401 | * 密文字节数组
402 | * @param offset
403 | * 从何处开始解密
404 | * @param len
405 | * 密文的长度
406 | * @return
407 | * true表示解密成功
408 | */
409 | private boolean decrypt8Bytes(byte[] in , int offset, int len) {
410 | // 这里第一步就是判断后面还有没有数据,没有就返回,如果有,就执行 crypt ^ prePlain
411 | for(pos = 0; pos < 8; pos++) {
412 | if(contextStart + pos >= len)
413 | return true;
414 | prePlain[pos] ^= in[offset + crypt + pos];
415 | }
416 |
417 | // 好,这里执行到了 d(crypt ^ prePlain)
418 | prePlain = decipher(prePlain);
419 | if(prePlain == null)
420 | return false;
421 |
422 | // 解密完成,最后一步好像没做?
423 | // 这里最后一步放到decrypt里面去做了,因为解密的步骤有点不太一样
424 | // 调整这些变量的值先
425 | contextStart += 8;
426 | crypt += 8;
427 | pos = 0;
428 | return true;
429 | }
430 |
431 | /**
432 | * 这是个随机因子产生器,用来填充头部的,如果为了调试,可以用一个固定值
433 | * 随机因子可以使相同的明文每次加密出来的密文都不一样
434 | *
435 | * @return
436 | * 随机因子
437 | */
438 | private int rand() {
439 | return random.nextInt();
440 | }
441 |
442 | }
443 |
444 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Utils/ZLibUtils.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Utils;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.util.zip.Deflater;
8 | import java.util.zip.DeflaterOutputStream;
9 | import java.util.zip.Inflater;
10 | import java.util.zip.InflaterInputStream;
11 |
12 | /**
13 | * ZLib压缩工具
14 | *
15 | * @author 梁栋
16 | * @version 1.0
17 | * @since 1.0
18 | */
19 | public class ZLibUtils {
20 |
21 | /**
22 | * 压缩
23 | *
24 | * @param data
25 | * 待压缩数据
26 | * @return byte[] 压缩后的数据
27 | */
28 | public static byte[] compress(byte[] data) {
29 | byte[] output = new byte[0];
30 |
31 | Deflater compresser = new Deflater();
32 |
33 | compresser.reset();
34 | compresser.setInput(data);
35 | compresser.finish();
36 | ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
37 | try {
38 | byte[] buf = new byte[1024];
39 | while (!compresser.finished()) {
40 | int i = compresser.deflate(buf);
41 | bos.write(buf, 0, i);
42 | }
43 | output = bos.toByteArray();
44 | } catch (Exception e) {
45 | output = data;
46 | e.printStackTrace();
47 | } finally {
48 | try {
49 | bos.close();
50 | } catch (IOException e) {
51 | e.printStackTrace();
52 | }
53 | }
54 | compresser.end();
55 | return output;
56 | }
57 |
58 | /**
59 | * 压缩
60 | *
61 | * @param data
62 | * 待压缩数据
63 | *
64 | * @param os
65 | * 输出流
66 | */
67 | public static void compress(byte[] data, OutputStream os) {
68 | DeflaterOutputStream dos = new DeflaterOutputStream(os);
69 |
70 | try {
71 | dos.write(data, 0, data.length);
72 |
73 | dos.finish();
74 |
75 | dos.flush();
76 | } catch (IOException e) {
77 | e.printStackTrace();
78 | }
79 | }
80 |
81 | /**
82 | * 解压缩
83 | *
84 | * @param data
85 | * 待压缩的数据
86 | * @return byte[] 解压缩后的数据
87 | */
88 | public static byte[] decompress(byte[] data) {
89 | byte[] output = new byte[0];
90 |
91 | Inflater decompresser = new Inflater();
92 | decompresser.reset();
93 | decompresser.setInput(data);
94 |
95 | ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);
96 | try {
97 | byte[] buf = new byte[1024];
98 | while (!decompresser.finished()) {
99 | int i = decompresser.inflate(buf);
100 | o.write(buf, 0, i);
101 | }
102 | output = o.toByteArray();
103 | } catch (Exception e) {
104 | output = data;
105 | e.printStackTrace();
106 | } finally {
107 | try {
108 | o.close();
109 | } catch (IOException e) {
110 | e.printStackTrace();
111 | }
112 | }
113 |
114 | decompresser.end();
115 | return output;
116 | }
117 |
118 | /**
119 | * 解压缩
120 | *
121 | * @param is
122 | * 输入流
123 | * @return byte[] 解压缩后的数据
124 | */
125 | public static byte[] decompress(InputStream is) {
126 | InflaterInputStream iis = new InflaterInputStream(is);
127 | ByteArrayOutputStream o = new ByteArrayOutputStream(1024);
128 | try {
129 | int i = 1024;
130 | byte[] buf = new byte[i];
131 |
132 | while ((i = iis.read(buf, 0, i)) > 0) {
133 | o.write(buf, 0, i);
134 | }
135 |
136 | } catch (IOException e) {
137 | e.printStackTrace();
138 | }
139 | return o.toByteArray();
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Window/BaseWindow.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Window;
2 | import com.googlecode.lanterna.gui2.*;
3 | import com.googlecode.lanterna.*;
4 |
5 | public class BaseWindow extends BasicWindow
6 | {
7 | public BaseWindow(String title){
8 | super(title);
9 | }
10 |
11 | public void setposition(TerminalSize size)
12 | {
13 | // TODO: Implement this method
14 | }
15 |
16 | public void setsize(TerminalSize size)
17 | {
18 | // TODO: Implement this method
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Window/ChatListWindow.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Window;
2 | import com.ignoreos.jvmqq.MainApp;
3 | import com.ignoreos.jvmqq.Utils.Util;
4 | import com.ignoreos.jvmqq.sdk.QQMessage;
5 | import com.googlecode.lanterna.*;
6 | import com.googlecode.lanterna.gui2.table.*;
7 | import java.util.*;
8 | import com.googlecode.lanterna.gui2.*;
9 |
10 | public class ChatListWindow extends BaseWindow
11 | {
12 | private Panel contentPanel;
13 |
14 | private Table table;
15 | private ChatWindow chatwindow;
16 |
17 | private MainApp app;
18 | public ChatListWindow(String title, ChatWindow _chatwindow, MainApp _app)
19 | {
20 | super(title);
21 | this.chatwindow=_chatwindow;
22 | this.app=_app;
23 | super.setHints(Arrays.asList(Window.Hint.FIXED_SIZE, Window.Hint.NO_POST_RENDERING));
24 | this.contentPanel = new Panel(new LinearLayout(Direction.VERTICAL)); // can hold multiple sub-components that will be added to a wind
25 | this.table = new Table("类型","QQ", "名称", "最后消息");
26 | this.table.setSelectAction(new Runnable() {
27 | @Override
28 | public void run() {
29 | if(table.getTableModel().getRowCount()==0){
30 | return;
31 | }
32 | List data = table.getTableModel().getRow(table.getSelectedRow());
33 | if(data.get(0).equals("好友")){
34 | ChatListWindow.this.chatwindow.onupdate(Long.parseLong(data.get(1)),1,data.get(2));
35 | }else{
36 | ChatListWindow.this.chatwindow.onupdate(Long.parseLong(data.get(1)),2,data.get(2));
37 | }
38 | ChatListWindow.this.app.setvisiblewindow(ChatListWindow.this.chatwindow);
39 | }
40 | });
41 | this.contentPanel.addComponent(this.table);
42 | this.setComponent(this.contentPanel);
43 |
44 | }
45 |
46 | public void onmessage(QQMessage qqmessage)
47 | {
48 | if (qqmessage.Group_uin == 0)
49 | {
50 | if (!this.ischatexist(qqmessage.Sender_Uin))
51 | {
52 | this.table.getTableModel().addRow("好友",""+qqmessage.Sender_Uin, Util.getFriendnamebyuin(qqmessage.Sender_Uin),qqmessage.Message);
53 | }else{
54 | this.updatemessage(qqmessage.Sender_Uin,qqmessage.Message);
55 | }
56 | }else{
57 | if (!this.ischatexist(qqmessage.Group_uin))
58 | {
59 | this.table.getTableModel().addRow("群组",""+qqmessage.Group_uin,Util.getGroupnamebyuin(qqmessage.Group_uin),qqmessage.SendName+":"+qqmessage.Message);
60 | }else{
61 | this.updatemessage(qqmessage.Group_uin,qqmessage.SendName+":"+qqmessage.Message);
62 | }
63 | }
64 | }
65 |
66 | private void updatemessage(long uin, String message)
67 | {
68 | int index =0;
69 | List> rows = this.table.getTableModel().getRows();
70 | for (List row:rows)
71 | {
72 | if (Long.parseLong(row.get(1)) == uin)
73 | {
74 | this.table.getTableModel().setCell(3,index,message);
75 | }
76 | index+=1;
77 | }
78 |
79 | }
80 |
81 |
82 |
83 |
84 | private boolean ischatexist(long uin)
85 | {
86 |
87 | List> rows = this.table.getTableModel().getRows();
88 | for (List row:rows)
89 | {
90 | if (Long.parseLong(row.get(1)) == uin)
91 | {
92 | return true;
93 | }
94 | }
95 | return false;
96 | }
97 |
98 |
99 | public Table getlisttable()
100 | {
101 | return this.table;
102 | }
103 |
104 | @Override public void setsize(TerminalSize size)
105 | {
106 | this.setSize(new TerminalSize(size.getColumns()-2, size.getRows() / 10 * 9 - 2));
107 | }
108 |
109 | @Override public void setposition(TerminalSize size)
110 | {
111 | this.setPosition(new TerminalPosition(0, size.getRows() / 10));
112 |
113 | }
114 |
115 | public void settablesize(TerminalSize size)
116 | {
117 | this.table.setPreferredSize(new TerminalSize(size.getColumns() - 2, size.getRows() / 10 * 9 - 2));
118 |
119 | }
120 |
121 |
122 |
123 |
124 |
125 | public static ChatListWindow convertobj(Object p1)
126 | {
127 | return (ChatListWindow)p1;
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Window/ChatWindow.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Window;
2 | import com.ignoreos.jvmqq.sdk.QQMessage;
3 | import com.googlecode.lanterna.gui2.*;
4 | import java.util.*;
5 |
6 | import com.googlecode.lanterna.*;
7 | import com.googlecode.lanterna.input.*;
8 |
9 | public class ChatWindow extends BaseWindow
10 | {
11 |
12 | private Panel contentPanel;
13 | private TextBox textbox;
14 | private Label label;
15 |
16 | public int chattype=0;
17 |
18 | public Long uin=0l;
19 |
20 | private TextBox inputmessagebox;
21 |
22 |
23 | public ChatWindow(String title){
24 | super(title);
25 | this.setHints(Arrays.asList(Window.Hint.FIXED_SIZE,Window.Hint.NO_POST_RENDERING));
26 | this.contentPanel = new Panel(new GridLayout(2)); // can hold multiple sub-components that will be added to a windo
27 | this.label=new Label("未选定聊天目标");
28 | this.textbox = new TextBox().setEnabled(false);
29 | this.inputmessagebox = new TextBox();
30 | com.googlecode.lanterna.gui2.TextBox.TextBoxRenderer tbr = this.textbox.getRenderer();
31 | com.googlecode.lanterna.gui2.TextBox.DefaultTextBoxRenderer dtbr = (TextBox.DefaultTextBoxRenderer) tbr;
32 | dtbr.setHideScrollBars(true);
33 | this.contentPanel.addComponent(this.label.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.CENTER,GridLayout.Alignment.BEGINNING,true,false,2,1)));
34 | this.contentPanel.addComponent(this.inputmessagebox.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.CENTER,GridLayout.Alignment.BEGINNING,true,false,2,1)));
35 | contentPanel.addComponent(
36 | new Separator(Direction.HORIZONTAL)
37 | .setLayoutData(
38 | GridLayout.createHorizontallyFilledLayoutData(2)));
39 | this.contentPanel.addComponent(this.textbox.setReadOnly(true),LinearLayout.createLayoutData(LinearLayout.Alignment.Beginning));
40 | this.setComponent(this.contentPanel);
41 |
42 | }
43 |
44 | public static ChatWindow getconvertobj(Window p1)
45 | {
46 | return (ChatWindow)p1;
47 | }
48 |
49 | public TextBox getinputbox()
50 | {
51 |
52 |
53 | return this.inputmessagebox;
54 | }
55 |
56 |
57 | @Override public void setsize(TerminalSize size){
58 | this.setSize(new TerminalSize(size.getColumns()-2,size.getRows()/10*9-2));
59 |
60 | }
61 |
62 |
63 | @Override public void setposition(TerminalSize size){
64 | this.setPosition(new TerminalPosition(0,size.getRows()/10));
65 | }
66 |
67 |
68 | public void settextboxsize(){
69 | this.textbox.setPreferredSize(new TerminalSize(this.getSize().getColumns(),this.getSize().getRows()-5));
70 |
71 | }
72 |
73 |
74 |
75 | public void onupdate(Long _uin,int _chattype,String targetname){
76 | this.label.setText(targetname);
77 | this.chattype=_chattype;
78 | this.uin=_uin;
79 | this.textbox.setText("");
80 | }
81 |
82 | public void onself(QQMessage message)
83 | {
84 |
85 | if(this.getacturesizeoftext(message.Message+message.SendName)>this.textbox.getPreferredSize().getColumns()){
86 | this.cutmessage2(message);
87 | return;
88 | }
89 | this.print(stringreader.createblank(this.textbox.getPreferredSize().getColumns()-(this.getacturesizeoftext(message.Message+" :"+message.SendName)))+message.Message+" :"+message.SendName);
90 |
91 | }
92 |
93 | private void cutmessage2(QQMessage message)
94 | {
95 | int textboxwidth = this.textbox.getPreferredSize().getColumns();
96 | String head =" :"+message.SendName;
97 | int headersize = getacturesizeoftext(head);
98 | int messagesize = textboxwidth-headersize-this.textbox.getPreferredSize().getColumns()/5;
99 | stringreader reader = new stringreader(message.Message);
100 | this.print(reader.createblank(this.textbox.getPreferredSize().getColumns()/5)+reader.readstring(messagesize)+head);
101 | while(!reader.isover()){
102 | this.print(reader.createblank(this.textbox.getPreferredSize().getColumns()/5)+reader.readstring(messagesize));
103 | }
104 | }
105 |
106 | public void onothers(QQMessage message){
107 | if(this.chattype==1){
108 | message.SendName=this.label.getText();
109 | }
110 | if(this.getacturesizeoftext(message.Message+message.SendName)>this.textbox.getPreferredSize().getColumns()){
111 | this.cutmessage(message);
112 | return;
113 | }
114 | this.print(message.SendName+": "+message.Message);
115 |
116 | }
117 |
118 | private void print(String message)
119 | {
120 | this.textbox.addLine(message);
121 | this.textbox.handleInput(new KeyStroke(KeyType.ArrowDown));
122 | }
123 |
124 | private void cutmessage(QQMessage message)
125 | {
126 | int textboxwidth = this.textbox.getPreferredSize().getColumns();
127 | String head =message.SendName+": ";
128 | int headersize = getacturesizeoftext(head);
129 | int messagesize = textboxwidth-headersize-this.textbox.getPreferredSize().getColumns()/5;
130 | stringreader reader = new stringreader(message.Message);
131 | this.print(head+reader.readstring(messagesize));
132 | while(!reader.isover()){
133 | this.print(reader.createblank(headersize)+reader.readstring(messagesize));
134 | }
135 | }
136 |
137 |
138 | private int getacturesizeoftext(String text){
139 | int length=0;
140 | for(int i=0;i=this.chartext.length){
173 | break;
174 | }
175 | String str= String.valueOf(this.chartext[i]);
176 | if(str.getBytes().length==1){
177 | toreturn+=str;
178 | lengthcount+=1;
179 | }
180 | else if(str.getBytes().length==3){
181 | toreturn+=str;
182 | lengthcount+=2;
183 | }
184 | startlength+=1;
185 | if( lengthcount>=length||this.chartext.length table;
21 |
22 | private MainApp app;
23 |
24 |
25 | public FriendListWindow(String title, ChatWindow _chatwindow, MainApp _app){
26 | super(title);
27 | this.chatwindow = _chatwindow;
28 | this.app=_app;
29 | this.setHints(Arrays.asList(Window.Hint.FIXED_SIZE,Window.Hint.NO_POST_RENDERING));
30 | this.contentPanel = new Panel(new LinearLayout(Direction.VERTICAL)); // can hold multiple sub-components that will be added to a wind
31 | this.table= new Table("好友号码","好友名称");
32 | this.table.setSelectAction(new Runnable() {
33 | @Override
34 | public void run() {
35 | List data = table.getTableModel().getRow(table.getSelectedRow());
36 | FriendListWindow.this.chatwindow.onupdate(Long.parseLong(data.get(0)),1,data.get(1));
37 | FriendListWindow.this.app.setvisiblewindow(FriendListWindow.this.chatwindow);
38 | }
39 | });
40 | this.contentPanel.addComponent(this.table);
41 | this.setComponent(this.contentPanel);
42 |
43 | }
44 |
45 | public Table getlisttable()
46 | {
47 | return this.table;
48 | }
49 |
50 |
51 | @Override public void setsize(TerminalSize size){
52 | this.setSize(new TerminalSize(size.getColumns()/2-1,size.getRows()/10*9));
53 | }
54 |
55 | @Override public void setposition(TerminalSize size){
56 | this.setPosition(new TerminalPosition(0,size.getRows()/10));
57 |
58 | }
59 |
60 | public static FriendListWindow getconvertobj(Window p1)
61 | {
62 | return (FriendListWindow)p1;
63 | }
64 |
65 |
66 | public void settablesize(TerminalSize size){
67 | this.table.setPreferredSize(new TerminalSize(size.getColumns()/2,size.getRows()));
68 | }
69 |
70 |
71 |
72 |
73 | public void setfriendlist(final QQUser user){
74 |
75 | if(user.friend_list!=null){
76 | for(Friend_List.Friend members:user.friend_list.members){
77 | this.table.getTableModel().addRow(""+members.friend_uin,members.friend_name);
78 | }
79 |
80 | }else{
81 |
82 | }
83 |
84 | }
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Window/GroupListWindow.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Window;
2 |
3 | import com.ignoreos.jvmqq.QQUser;
4 | import com.ignoreos.jvmqq.sdk.Group_List;
5 | import com.googlecode.lanterna.gui2.*;
6 | import java.util.*;
7 |
8 | import com.googlecode.lanterna.gui2.table.*;
9 | import com.googlecode.lanterna.*;
10 | import com.ignoreos.jvmqq.MainApp;
11 |
12 | public class GroupListWindow extends BaseWindow
13 | {
14 |
15 | private Panel contentPanel;
16 |
17 | private Button button;
18 |
19 | private ChatWindow chatwindow;
20 |
21 | private Table table;
22 |
23 | private MainApp app;
24 | public GroupListWindow(String title, ChatWindow _chatwindow, MainApp _app){
25 | super(title);
26 | this.app=_app;
27 | this.chatwindow=_chatwindow;
28 | this.setHints(Arrays.asList(Window.Hint.FIXED_SIZE,Window.Hint.NO_POST_RENDERING));
29 | this.contentPanel = new Panel(new LinearLayout(Direction.VERTICAL)); // can hold multiple sub-components that will be added to a wind
30 | this.table= new Table("群号码","群名称");
31 | this.table.setSelectAction(new Runnable() {
32 | @Override
33 | public void run() {
34 | List data = table.getTableModel().getRow(table.getSelectedRow());
35 | GroupListWindow.this.chatwindow.onupdate(Long.parseLong(data.get(0)),2,data.get(1));
36 | GroupListWindow.this.app.setvisiblewindow(GroupListWindow.this.chatwindow);
37 | }
38 | });
39 | this.contentPanel.addComponent(this.table);
40 | this.setComponent(this.contentPanel);
41 | }
42 |
43 | public static GroupListWindow getconvertobj(Window p1)
44 | {
45 | return (GroupListWindow)p1;
46 | }
47 | public Table getlisttable()
48 | {
49 | return this.table;
50 | }
51 |
52 | @Override public void setsize(TerminalSize size){
53 | this.setSize(new TerminalSize(size.getColumns()/2-2,size.getRows()/10*9));
54 | }
55 |
56 | @Override public void setposition(TerminalSize size){
57 | this.setPosition(new TerminalPosition(size.getColumns()/2,size.getRows()/10));
58 |
59 | }
60 |
61 |
62 |
63 |
64 | public void settablesize(TerminalSize size){
65 | this.table.setPreferredSize(new TerminalSize(this.getSize().getColumns(),size.getRows()));
66 | }
67 | public void setgrouplist(QQUser user)
68 | {
69 | if(user.friend_list!=null){
70 | for(Group_List.Group group:user.group_list.getall_group()){
71 | this.table.getTableModel().addRow(""+group.group_uin,group.group_name);
72 | }
73 |
74 | }else{
75 |
76 | }
77 | }
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Window/LoginWindow.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Window;
2 | import com.googlecode.lanterna.gui2.*;
3 | import java.util.*;
4 | import com.googlecode.lanterna.gui2.dialogs.*;
5 |
6 | public class LoginWindow extends BaseWindow
7 | {
8 |
9 | private Panel contentPanel;
10 |
11 | private TextBox accountinput;
12 |
13 | private TextBox passwordinput;
14 |
15 | public LoginWindow(String title){
16 | super(title);
17 | this.setHints(Arrays.asList(Window.Hint.FULL_SCREEN,Window.Hint.NO_POST_RENDERING));
18 |
19 |
20 | this.contentPanel = new Panel(new GridLayout(2)); // can hold multiple sub-components that will be added to a window
21 | this.accountinput = new TextBox();
22 | this.passwordinput = new TextBox();
23 |
24 | contentPanel.addComponent(new Label("QQ"));
25 | this.contentPanel.addComponent(this.accountinput).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER));
26 | contentPanel.addComponent(new Label("password"));
27 | this.contentPanel.addComponent(this.passwordinput).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER));
28 |
29 | this.contentPanel.addComponent(new Button("Login", new Runnable() {
30 | @Override
31 | public void run() {
32 | if(LoginWindow.this.account()==null||LoginWindow.this.account()==null){
33 | MessageDialog.showMessageDialog(LoginWindow.this.getTextGUI(), "错误", "账号密码不能为空", MessageDialogButton.OK);
34 | }
35 | else{
36 | LoginWindow.this.close();
37 | }
38 | }
39 | }).setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER)));
40 |
41 | this.setComponent(contentPanel);
42 |
43 | }
44 |
45 |
46 | public String account(){
47 | return this.accountinput.getText();
48 | }
49 |
50 |
51 | public String password(){
52 | return this.passwordinput.getText();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Window/NavigatorWindow.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Window;
2 | import com.googlecode.lanterna.gui2.*;
3 | import java.util.*;
4 | import com.googlecode.lanterna.*;
5 |
6 |
7 |
8 | public class NavigatorWindow extends BaseWindow
9 | {
10 |
11 | private Panel contentPanel;
12 |
13 | private Button button1;
14 |
15 | private Button button2;
16 |
17 | private Button button3;
18 |
19 | private Button button4;
20 |
21 | private Button button5;
22 | public NavigatorWindow(){
23 | super("");
24 | super.setHints(Arrays.asList(Window.Hint.FIXED_SIZE,Window.Hint.NO_POST_RENDERING));
25 |
26 | this.contentPanel = new Panel(new LinearLayout(Direction.HORIZONTAL)); // can hold multiple sub-components that will be added to a wind
27 | this.button1=new Button(" 消息列表");
28 | this.button2=new Button(" 聊天窗口");
29 | this.button3=new Button(" 联系列表");
30 | this.button4=new Button(" 插件列表");
31 | this.button5=new Button(" 日志窗口");
32 |
33 | this.contentPanel.addComponent(this.button1);
34 | this.contentPanel.addComponent(this.button2);
35 | this.contentPanel.addComponent(this.button3);
36 | this.contentPanel.addComponent(this.button4);
37 | this.contentPanel.addComponent(this.button5);
38 |
39 | this.setComponent(this.contentPanel);
40 | }
41 |
42 | public static NavigatorWindow getconvertobj(Window p1)
43 | {
44 | return (NavigatorWindow)p1;
45 | }
46 |
47 |
48 |
49 | public void setbuttonposition(){
50 | int width = this.getSize().getColumns();
51 | this.button1.setPosition(new TerminalPosition(0,0));
52 | this.button2.setPosition(new TerminalPosition(0,width/5));
53 | this.button3.setPosition(new TerminalPosition(0,width/5*2));
54 | this.button4.setPosition(new TerminalPosition(0,width/5*3));
55 | this.button4.setPosition(new TerminalPosition(0,width/5*4));
56 |
57 | }
58 |
59 |
60 |
61 | public Button getfocusedbutton(){
62 |
63 | for (Button button: Arrays.asList(this.button1,this.button2,this.button3,this.button4,this.button5)){
64 | if(button.isFocused()){
65 | return button;
66 | }
67 | }
68 | return null;
69 | }
70 |
71 |
72 | @Override public void setsize(TerminalSize size){
73 | this.setSize(new TerminalSize(size.getColumns()-2,size.getRows()/10-2));
74 |
75 | }
76 |
77 | @Override public void setposition(TerminalSize size){
78 | this.setPosition(new TerminalPosition(0,0));
79 |
80 | }
81 |
82 |
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Window/OutPutWindow.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Window;
2 | import com.googlecode.lanterna.gui2.*;
3 | import java.util.*;
4 | import com.googlecode.lanterna.*;
5 | import com.googlecode.lanterna.input.*;
6 |
7 | public class OutPutWindow extends BaseWindow
8 | {
9 |
10 | private TextBox textbox;
11 |
12 | private Panel contentPanel;
13 |
14 | private Button button;
15 |
16 |
17 | public OutPutWindow(String title){
18 | super(title);
19 | this.setHints(Arrays.asList(Window.Hint.FIXED_SIZE,Window.Hint.NO_POST_RENDERING));
20 |
21 | this.contentPanel = new Panel(new LinearLayout(Direction.VERTICAL)); // can hold multiple sub-components that will be added to a window
22 | this.textbox = new TextBox().setReadOnly(true);
23 | this.button=new Button(" 标记");
24 | this.contentPanel.addComponent(this.button);
25 | this.contentPanel.addComponent(this.textbox);
26 | com.googlecode.lanterna.gui2.TextBox.TextBoxRenderer tbr = this.textbox.getRenderer();
27 | com.googlecode.lanterna.gui2.TextBox.DefaultTextBoxRenderer dtbr = (TextBox.DefaultTextBoxRenderer) tbr;
28 | dtbr.setHideScrollBars(true);
29 |
30 |
31 | this.setComponent(contentPanel);
32 |
33 |
34 | }
35 |
36 | public void setlogsize(TerminalSize size, int p1)
37 | {
38 | this.textbox.setPreferredSize(new TerminalSize(size.getColumns(),size.getRows()/10*9));
39 |
40 | }
41 |
42 | @Override public void setsize(TerminalSize size){
43 | this.setSize(new TerminalSize(size.getColumns()-2,size.getRows()/10*9));
44 | }
45 |
46 | @Override public void setposition(TerminalSize size){
47 | this.setPosition(new TerminalPosition(0,size.getRows()/10));
48 |
49 | }
50 |
51 | public static OutPutWindow getconvertobj(Window p1)
52 | {
53 | return (OutPutWindow)p1;
54 | }
55 |
56 | public void setlogsize(TerminalSize size){
57 | this.textbox.setPreferredSize(size);
58 | }
59 |
60 | public Button getbutton(){
61 | return this.button;
62 | }
63 |
64 | public void print(String text){
65 | this.textbox.addLine(text);
66 | this.textbox.handleInput(new KeyStroke(KeyType.ArrowDown));
67 | }
68 |
69 |
70 |
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/src/com/ignoreos/jvmqq/Window/PluginWindow.java:
--------------------------------------------------------------------------------
1 | package com.ignoreos.jvmqq.Window;
2 | import java.util.*;
3 |
4 | import com.ignoreos.jvmqq.Utils.Util;
5 | import com.ignoreos.jvmqq.sdk.Plugin;
6 | import com.googlecode.lanterna.gui2.*;
7 | import com.googlecode.lanterna.gui2.table.*;
8 | import com.googlecode.lanterna.*;
9 | import java.io.*;
10 | import java.net.*;
11 |
12 | import org.luaj.vm2.*;
13 | import org.luaj.vm2.lib.jse.*;
14 |
15 | public class PluginWindow extends BaseWindow
16 | {
17 |
18 | private Panel contentPanel;
19 |
20 | private Table table;
21 |
22 | private Button button;
23 |
24 | public PluginWindow(String title)
25 | {
26 | super(title);
27 | super.setHints(Arrays.asList(Window.Hint.FIXED_SIZE, Window.Hint.NO_POST_RENDERING));
28 | this.contentPanel = new Panel(new LinearLayout(Direction.VERTICAL)); // can hold multiple sub-components that will be added to a wind
29 | this.table = new Table("类型","文件名", "插件名", "是否开启");
30 | this.button = new Button(" 刷新列表",new Runnable(){
31 | @Override public void run(){
32 | int rowcount = PluginWindow.this.table.getTableModel().getRowCount();
33 | for(int i =0;i data = table.getTableModel().getRow(table.getSelectedRow());
49 | if(data.get(0).equals("java")){
50 | if(data.get(3).equals("否")){
51 | if(Util.javarobot!=null){
52 | Util.javarobot.plug(data.get(1));
53 | Util.setactivatedplugin(data.get(2));
54 | table.getTableModel().setCell(3,table.getSelectedRow(),"是");
55 | }
56 | }else if(data.get(3).equals("是")){
57 | if(Util.javarobot!=null){
58 | Util.javarobot.unplug(data.get(2));
59 | Util.setdeactivatedplugin(data.get(2));
60 | table.getTableModel().setCell(3,table.getSelectedRow(),"否");
61 | }
62 | }
63 | }else if(data.get(0).equals("lua")){
64 | if(data.get(3).equals("否")){
65 | if(Util.luarobot!=null){
66 | Util.luarobot.plug(data.get(1));
67 | Util.setactivatedplugin(data.get(2));
68 | table.getTableModel().setCell(3,table.getSelectedRow(),"是");
69 | }
70 | }else if(data.get(3).equals("是")){
71 | if(Util.luarobot!=null){
72 | Util.luarobot.unplug(data.get(2));
73 | Util.setdeactivatedplugin(data.get(2));
74 | table.getTableModel().setCell(3,table.getSelectedRow(),"否");
75 | }
76 | }
77 | }
78 |
79 | }
80 | });
81 |
82 | this.setComponent(this.contentPanel);
83 |
84 | }
85 |
86 | private void displaypluginlist()
87 | {
88 | try
89 | {
90 | String exact_directory = new File("").getCanonicalPath();
91 | File plugin_path = new File(exact_directory + "/plugin");
92 | String[] plugin_list = plugin_path.list();
93 | if (plugin_list != null)
94 | {
95 | List list = Arrays.asList(plugin_list);
96 | for (String file: list)
97 | {
98 | if (file.endsWith(".jar"))
99 | {
100 |
101 | ClassLoader loader = new URLClassLoader(new URL[]{new URL("file://" + exact_directory + "/plugin/" + file)});
102 | Class> pluginCls = loader.loadClass("com.robot.Main");
103 | Plugin plugin = (Plugin)pluginCls.getDeclaredConstructor().newInstance();
104 | if (plugin.name() != null)
105 | {
106 | if (Util.isactivatedplugin(plugin.name()))
107 | {
108 | this.table.getTableModel().addRow("java",file,plugin.name(),"是");
109 | }else{
110 | this.table.getTableModel().addRow("java",file,plugin.name(),"否");
111 | }
112 | }
113 |
114 | }
115 | }
116 | }
117 |
118 | plugin_path = new File(exact_directory + "/plugin-lua");
119 | plugin_list = plugin_path.list();
120 |
121 | if (plugin_list != null)
122 | {
123 | List list = Arrays.asList(plugin_list);
124 | Globals globals = JsePlatform.standardGlobals();
125 | for (String file: list)
126 | {
127 | if (file.endsWith(".lua"))
128 | {
129 | String script_path=exact_directory + "/plugin-lua/" + file;
130 | LuaValue plugin = globals.loadfile(script_path).call();
131 | final LuaValue name = plugin.get(LuaValue.valueOf("name"));
132 | if (name.call() != null)
133 | {
134 | if (Util.isactivatedplugin(name.call().toString()))
135 | {
136 | this.table.getTableModel().addRow("lua",file,name.call().toString(),"是");
137 | }else{
138 | this.table.getTableModel().addRow("lua",file,name.call().toString(),"否");
139 | }
140 | }
141 | }
142 | }
143 | }
144 | }
145 | catch (Exception e)
146 | {
147 |
148 | e.printStackTrace();
149 | }
150 |
151 | }
152 |
153 | @Override public void setsize(TerminalSize size)
154 | {
155 | this.setSize(new TerminalSize(size.getColumns()-2, size.getRows() / 10 * 9 - 2));
156 | }
157 |
158 | @Override public void setposition(TerminalSize size)
159 | {
160 | this.setPosition(new TerminalPosition(0, size.getRows() / 10));
161 |
162 | }
163 | public Button getrefreshbutton()
164 | {
165 | return this.button;
166 | }
167 |
168 | public void settablesize(TerminalSize size)
169 | {
170 | this.table.setPreferredSize(new TerminalSize(size.getColumns() - 2, size.getRows() / 10 * 9 - 2));
171 |
172 | }
173 |
174 | public static PluginWindow convertobj(Object p1)
175 | {
176 | return (PluginWindow)p1;
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------