1 |
/* Tera Term |
2 |
Copyright(C) 1994-1998 T. Teranishi |
3 |
All rights reserved. */ |
4 |
|
5 |
/* TERATERM.EXE, DDE routines */ |
6 |
#include "teraterm.h" |
7 |
#include "tttypes.h" |
8 |
#include <stdio.h> |
9 |
#include <string.h> |
10 |
#include <ddeml.h> |
11 |
#include "ttwinman.h" |
12 |
#include "ttftypes.h" |
13 |
#include "filesys.h" |
14 |
#include "clipboar.h" |
15 |
#include "ttsetup.h" |
16 |
#include "telnet.h" |
17 |
#include "ttlib.h" |
18 |
|
19 |
#include "ttdde.h" |
20 |
#include "commlib.h" |
21 |
|
22 |
#include "vtwin.h" |
23 |
|
24 |
#define ServiceName "TERATERM" |
25 |
#define ItemName "DATA" |
26 |
#define ItemName2 "PARAM" |
27 |
|
28 |
char TopicName[21] = ""; |
29 |
HCONV ConvH = 0; |
30 |
BOOL AdvFlag = FALSE; |
31 |
BOOL CloseTT = FALSE; |
32 |
|
33 |
static BOOL DdeCmnd = FALSE; |
34 |
|
35 |
static DWORD Inst = 0; |
36 |
static HSZ Service = 0; |
37 |
static HSZ Topic = 0; |
38 |
static HSZ Item = 0; |
39 |
static HSZ Item2 = 0; |
40 |
static HWND HWndDdeCli = NULL; |
41 |
|
42 |
static StartupFlag = FALSE; |
43 |
|
44 |
// for sync mode |
45 |
static BOOL SyncMode = FALSE; |
46 |
static BOOL SyncRecv; |
47 |
static LONG SyncFreeSpace; |
48 |
|
49 |
static char ParamFileName[256]; |
50 |
static WORD ParamBinaryFlag; |
51 |
static WORD ParamAppendFlag; |
52 |
static WORD ParamXmodemOpt; |
53 |
static char ParamSecondFileName[256]; |
54 |
|
55 |
#define CBBufSize TermWidthMax |
56 |
|
57 |
void GetClientHWnd(PCHAR HWndStr) |
58 |
{ |
59 |
int i; |
60 |
BYTE b; |
61 |
LONG HCli; |
62 |
|
63 |
HCli = 0; |
64 |
i = 0; |
65 |
b = HWndStr[0]; |
66 |
while (b > 0) |
67 |
{ |
68 |
if (b <= 0x39) |
69 |
HCli = (HCli << 4) + (b-0x30); |
70 |
else |
71 |
HCli = (HCli << 4) + (b-0x37); |
72 |
i++; |
73 |
b = HWndStr[i]; |
74 |
} |
75 |
HWndDdeCli = (HWND)HCli; |
76 |
} |
77 |
|
78 |
void Byte2HexStr(BYTE b, LPSTR HexStr) |
79 |
{ |
80 |
if (b<0xa0) |
81 |
HexStr[0] = 0x30 + (b >> 4); |
82 |
else |
83 |
HexStr[0] = 0x37 + (b >> 4); |
84 |
if ((b & 0x0f) < 0x0a) |
85 |
HexStr[1] = 0x30 + (b & 0x0f); |
86 |
else |
87 |
HexStr[1] = 0x37 + (b & 0x0f); |
88 |
HexStr[2] = 0; |
89 |
} |
90 |
|
91 |
void SetTopic() |
92 |
{ |
93 |
WORD w; |
94 |
|
95 |
w = HIWORD(HVTWin); |
96 |
Byte2HexStr(HIBYTE(w),&(TopicName[0])); |
97 |
Byte2HexStr(LOBYTE(w),&(TopicName[2])); |
98 |
w = LOWORD(HVTWin); |
99 |
Byte2HexStr(HIBYTE(w),&(TopicName[4])); |
100 |
Byte2HexStr(LOBYTE(w),&(TopicName[6])); |
101 |
} |
102 |
|
103 |
HDDEDATA WildConnect(HSZ ServiceHsz, HSZ TopicHsz, UINT ClipFmt) |
104 |
{ |
105 |
HSZPAIR Pairs[2]; |
106 |
BOOL Ok; |
107 |
|
108 |
Pairs[0].hszSvc = Service; |
109 |
Pairs[0].hszTopic = Topic; |
110 |
Pairs[1].hszSvc = NULL; |
111 |
Pairs[1].hszTopic = NULL; |
112 |
|
113 |
Ok = FALSE; |
114 |
|
115 |
if ((ServiceHsz == 0) && (TopicHsz == 0)) |
116 |
Ok = TRUE; |
117 |
else |
118 |
if ((TopicHsz == 0) && |
119 |
(DdeCmpStringHandles(Service, ServiceHsz) == 0)) |
120 |
Ok = TRUE; |
121 |
else |
122 |
if ((DdeCmpStringHandles(Topic, TopicHsz) == 0) && |
123 |
(ServiceHsz == 0)) |
124 |
Ok = TRUE; |
125 |
|
126 |
if (Ok) |
127 |
return DdeCreateDataHandle(Inst, (LPBYTE)(&Pairs), sizeof(Pairs), |
128 |
0, NULL, ClipFmt, 0); |
129 |
else |
130 |
return 0; |
131 |
} |
132 |
|
133 |
BOOL DDEGet1(LPBYTE b) |
134 |
{ |
135 |
if (cv.DCount <= 0) return FALSE; |
136 |
*b = ((LPSTR)cv.LogBuf)[cv.DStart]; |
137 |
cv.DStart++; |
138 |
if (cv.DStart>=InBuffSize) |
139 |
cv.DStart = cv.DStart-InBuffSize; |
140 |
cv.DCount--; |
141 |
return TRUE; |
142 |
} |
143 |
|
144 |
LONG DDEGetDataLen() |
145 |
{ |
146 |
BYTE b; |
147 |
LONG Len; |
148 |
int Start, Count; |
149 |
|
150 |
Len = cv.DCount; |
151 |
Start = cv.DStart; |
152 |
Count = cv.DCount; |
153 |
while (Count>0) |
154 |
{ |
155 |
b = ((LPSTR)cv.LogBuf)[Start]; |
156 |
if ((b==0x00) || (b==0x01)) Len++; |
157 |
Start++; |
158 |
if (Start>=InBuffSize) Start = Start-InBuffSize; |
159 |
Count--; |
160 |
} |
161 |
|
162 |
return Len; |
163 |
} |
164 |
|
165 |
HDDEDATA AcceptRequest(HSZ ItemHSz) |
166 |
{ |
167 |
BYTE b; |
168 |
BOOL Unlock; |
169 |
HDDEDATA DH; |
170 |
LPSTR DP; |
171 |
int i; |
172 |
LONG Len; |
173 |
|
174 |
if ((! DDELog) || (ConvH==0)) return 0; |
175 |
|
176 |
if (DdeCmpStringHandles(ItemHSz, Item2) == 0) // item "PARAM" |
177 |
DH = DdeCreateDataHandle(Inst,ParamFileName,sizeof(ParamFileName),0, |
178 |
Item2,CF_OEMTEXT,0); |
179 |
else if (DdeCmpStringHandles(ItemHSz, Item) == 0) // item "DATA" |
180 |
{ |
181 |
if (cv.HLogBuf==0) return 0; |
182 |
|
183 |
if (cv.LogBuf==NULL) |
184 |
{ |
185 |
Unlock = TRUE; |
186 |
cv.LogBuf = GlobalLock(cv.HLogBuf); |
187 |
if (cv.LogBuf == NULL) return 0; |
188 |
} |
189 |
else Unlock = FALSE; |
190 |
|
191 |
Len = DDEGetDataLen(); |
192 |
if ((SyncMode) && |
193 |
(SyncFreeSpace<Len)) |
194 |
Len = SyncFreeSpace; |
195 |
|
196 |
DH = DdeCreateDataHandle(Inst,NULL,Len+2,0, |
197 |
Item,CF_OEMTEXT,0); |
198 |
DP = DdeAccessData(DH,NULL); |
199 |
if (DP != NULL) |
200 |
{ |
201 |
i = 0; |
202 |
while (i < Len) |
203 |
{ |
204 |
if (DDEGet1(&b)) { |
205 |
if ((b==0x00) || (b==0x01)) |
206 |
{ |
207 |
DP[i] = 0x01; |
208 |
DP[i+1] = b + 1; |
209 |
i = i + 2; |
210 |
} |
211 |
else { |
212 |
DP[i] = b; |
213 |
i++; |
214 |
} |
215 |
} |
216 |
else |
217 |
Len = 0; |
218 |
} |
219 |
DP[i] = 0; |
220 |
DdeUnaccessData(DH); |
221 |
} |
222 |
|
223 |
if (Unlock) |
224 |
{ |
225 |
GlobalUnlock(cv.HLogBuf); |
226 |
cv.LogBuf = NULL; |
227 |
} |
228 |
} |
229 |
else |
230 |
return 0; |
231 |
|
232 |
return DH; |
233 |
} |
234 |
|
235 |
HDDEDATA AcceptPoke(HSZ ItemHSz, UINT ClipFmt, |
236 |
HDDEDATA Data) |
237 |
{ |
238 |
LPSTR DataPtr; |
239 |
DWORD DataSize; |
240 |
|
241 |
// �A������XTYP_POKE���N���C�A���g�i�}�N���j�������������������A�T�[�o�i�{���j�������� |
242 |
// �R�}���h���\���t�����s���������������ATalkStatus�� IdTalkCB ���������ADDE_FNOTPROCESSED�� |
243 |
// ���������������BDDE_FBUSY�����X�B |
244 |
// (2006.11.6 yutaka) |
245 |
if (TalkStatus != IdTalkKeyb) |
246 |
return (HDDEDATA)DDE_FBUSY; |
247 |
|
248 |
if (ConvH==0) return DDE_FNOTPROCESSED; |
249 |
|
250 |
if ((ClipFmt!=CF_TEXT) && (ClipFmt!=CF_OEMTEXT)) return DDE_FNOTPROCESSED; |
251 |
|
252 |
if (DdeCmpStringHandles(ItemHSz, Item) != 0) return DDE_FNOTPROCESSED; |
253 |
|
254 |
DataPtr = DdeAccessData(Data,&DataSize); |
255 |
if (DataPtr==NULL) return DDE_FNOTPROCESSED; |
256 |
CBStartPaste(NULL,FALSE,CBBufSize,DataPtr,DataSize); |
257 |
DdeUnaccessData(Data); |
258 |
if (TalkStatus==IdTalkCB) |
259 |
return (HDDEDATA)DDE_FACK; |
260 |
else |
261 |
return DDE_FNOTPROCESSED; |
262 |
} |
263 |
|
264 |
WORD HexStr2Word(PCHAR Str) |
265 |
{ |
266 |
int i; |
267 |
BYTE b; |
268 |
WORD w; |
269 |
|
270 |
for (i=0; i<=3; i++) |
271 |
{ |
272 |
b = Str[i]; |
273 |
if (b <= 0x39) |
274 |
w = (w << 4) + (b-0x30); |
275 |
else |
276 |
w = (w << 4) + (b-0x37); |
277 |
} |
278 |
return w; |
279 |
} |
280 |
|
281 |
#define CmdSetHWnd ' ' |
282 |
#define CmdSetFile '!' |
283 |
#define CmdSetBinary '"' |
284 |
#define CmdSetAppend '#' |
285 |
#define CmdSetXmodemOpt '$' |
286 |
#define CmdSetSync '%' |
287 |
|
288 |
#define CmdBPlusRecv '&' |
289 |
#define CmdBPlusSend '\'' |
290 |
#define CmdChangeDir '(' |
291 |
#define CmdClearScreen ')' |
292 |
#define CmdCloseWin '*' |
293 |
#define CmdConnect '+' |
294 |
#define CmdDisconnect ',' |
295 |
#define CmdEnableKeyb '-' |
296 |
#define CmdGetTitle '.' |
297 |
#define CmdInit '/' |
298 |
#define CmdKmtFinish '0' |
299 |
#define CmdKmtGet '1' |
300 |
#define CmdKmtRecv '2' |
301 |
#define CmdKmtSend '3' |
302 |
#define CmdLoadKeyMap '4' |
303 |
#define CmdLogClose '5' |
304 |
#define CmdLogOpen '6' |
305 |
#define CmdLogPause '7' |
306 |
#define CmdLogStart '8' |
307 |
#define CmdLogWrite '9' |
308 |
#define CmdQVRecv ':' |
309 |
#define CmdQVSend ';' |
310 |
#define CmdRestoreSetup '<' |
311 |
#define CmdSendBreak '=' |
312 |
#define CmdSendFile '>' |
313 |
#define CmdSendKCode '?' |
314 |
#define CmdSetEcho '@' |
315 |
#define CmdSetTitle 'A' |
316 |
#define CmdShowTT 'B' |
317 |
#define CmdXmodemSend 'C' |
318 |
#define CmdXmodemRecv 'D' |
319 |
#define CmdZmodemSend 'E' |
320 |
#define CmdZmodemRecv 'F' |
321 |
#define CmdCallMenu 'G' |
322 |
#define CmdScpSend 'H' |
323 |
#define CmdScpRcv 'I' |
324 |
#define CmdSetSecondFile 'J' |
325 |
#define CmdSetBaud 'K' |
326 |
#define CmdSetRts 'L' |
327 |
#define CmdSetDtr 'M' |
328 |
#define CmdGetHostname 'N' |
329 |
#define CmdSendBroadcast 'O' |
330 |
#define CmdSendMulticast 'P' |
331 |
#define CmdSetMulticastName 'Q' |
332 |
|
333 |
HDDEDATA AcceptExecute(HSZ TopicHSz, HDDEDATA Data) |
334 |
{ |
335 |
char Command[260]; |
336 |
char Temp[MAXPATHLEN]; |
337 |
int i; |
338 |
WORD w, c; |
339 |
|
340 |
memset(Command, 0, sizeof(Command)); |
341 |
|
342 |
if ((ConvH==0) || |
343 |
(DdeCmpStringHandles(TopicHSz, Topic) != 0) || |
344 |
(DdeGetData(Data,Command,sizeof(Command),0) == 0)) |
345 |
return DDE_FNOTPROCESSED; |
346 |
|
347 |
switch (Command[0]) { |
348 |
case CmdSetHWnd: |
349 |
GetClientHWnd(&Command[1]); |
350 |
if (cv.Ready) |
351 |
SetDdeComReady(1); |
352 |
break; |
353 |
case CmdSetFile: |
354 |
strncpy_s(ParamFileName, sizeof(ParamFileName),&(Command[1]), _TRUNCATE); |
355 |
break; |
356 |
case CmdSetBinary: |
357 |
ParamBinaryFlag = Command[1] & 1; |
358 |
break; |
359 |
case CmdSetAppend: |
360 |
ParamAppendFlag = Command[1] & 1; |
361 |
ts.LogTypePlainText = Command[13] & 1; |
362 |
ts.LogTimestamp = Command[14] & 1; |
363 |
ts.LogHideDialog = Command[15] & 1; |
364 |
break; |
365 |
case CmdSetXmodemOpt: |
366 |
ParamXmodemOpt = Command[1] & 3; |
367 |
if (ParamXmodemOpt==0) ParamXmodemOpt = 1; |
368 |
break; |
369 |
case CmdSetSync: |
370 |
if (sscanf(&(Command[1]),"%u",&SyncFreeSpace)!=1) |
371 |
SyncFreeSpace = 0; |
372 |
SyncMode = (SyncFreeSpace>0); |
373 |
SyncRecv = TRUE; |
374 |
break; |
375 |
case CmdBPlusRecv: |
376 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
377 |
{ |
378 |
FileVar->NoMsg = TRUE; |
379 |
DdeCmnd = TRUE; |
380 |
BPStart(IdBPReceive); |
381 |
} |
382 |
else |
383 |
return DDE_FNOTPROCESSED; |
384 |
break; |
385 |
case CmdBPlusSend: |
386 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
387 |
{ |
388 |
FileVar->DirLen = 0; |
389 |
strncpy_s(FileVar->FullName, sizeof(FileVar->FullName),ParamFileName, _TRUNCATE); |
390 |
FileVar->NumFname = 1; |
391 |
FileVar->NoMsg = TRUE; |
392 |
DdeCmnd = TRUE; |
393 |
BPStart(IdBPSend); |
394 |
} |
395 |
else |
396 |
return DDE_FNOTPROCESSED; |
397 |
break; |
398 |
case CmdChangeDir: |
399 |
strncpy_s(ts.FileDir, sizeof(ts.FileDir),ParamFileName, _TRUNCATE); |
400 |
break; |
401 |
case CmdClearScreen: |
402 |
switch (ParamFileName[0]) { |
403 |
case '0': |
404 |
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdEditCLS,0); |
405 |
break; |
406 |
case '1': |
407 |
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdEditCLB,0); |
408 |
break; |
409 |
case '2': |
410 |
PostMessage(HTEKWin,WM_USER_ACCELCOMMAND,IdCmdEditCLS,0); |
411 |
break; |
412 |
} |
413 |
break; |
414 |
case CmdCloseWin: |
415 |
CloseTT = TRUE; |
416 |
break; |
417 |
case CmdConnect: |
418 |
if (cv.Open) { |
419 |
if (cv.Ready) |
420 |
SetDdeComReady(1); |
421 |
break; |
422 |
} |
423 |
strncpy_s(Temp, sizeof(Temp),"a ", _TRUNCATE); // dummy exe name |
424 |
strncat_s(Temp,sizeof(Temp),ParamFileName,_TRUNCATE); |
425 |
if (LoadTTSET()) |
426 |
(*ParseParam)(Temp, &ts, NULL); |
427 |
FreeTTSET(); |
428 |
cv.NoMsg = 1; /* suppress error messages */ |
429 |
PostMessage(HVTWin,WM_USER_COMMSTART,0,0); |
430 |
break; |
431 |
case CmdDisconnect: |
432 |
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdDisconnect,0); |
433 |
break; |
434 |
case CmdEnableKeyb: |
435 |
KeybEnabled = (ParamBinaryFlag!=0); |
436 |
break; |
437 |
case CmdGetTitle: |
438 |
// title is transfered later by XTYP_REQUEST |
439 |
strncpy_s(ParamFileName, sizeof(ParamFileName),ts.Title, _TRUNCATE); |
440 |
break; |
441 |
case CmdInit: // initialization signal from TTMACRO |
442 |
if (StartupFlag) // in case of startup macro |
443 |
{ // TTMACRO is waiting for connecting to the host |
444 |
// �V���A�������������������������������A�����_�C�A���O���o������ (2006.9.15 maya) |
445 |
if (!((ts.PortType==IdSerial) && (ts.ComAutoConnect == FALSE)) && |
446 |
((ts.PortType==IdSerial) || (ts.HostName[0]!=0))) |
447 |
{ |
448 |
cv.NoMsg = 1; |
449 |
// start connecting |
450 |
PostMessage(HVTWin,WM_USER_COMMSTART,0,0); |
451 |
} |
452 |
else // notify TTMACRO that I can not connect |
453 |
SetDdeComReady(0); |
454 |
StartupFlag = FALSE; |
455 |
} |
456 |
break; |
457 |
case CmdKmtFinish: |
458 |
case CmdKmtRecv: |
459 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
460 |
{ |
461 |
FileVar->NoMsg = TRUE; |
462 |
DdeCmnd = TRUE; |
463 |
if (Command[0]==CmdKmtFinish) |
464 |
i = IdKmtFinish; |
465 |
else |
466 |
i = IdKmtReceive; |
467 |
KermitStart(i); |
468 |
} |
469 |
else |
470 |
return DDE_FNOTPROCESSED; |
471 |
break; |
472 |
case CmdKmtGet: |
473 |
case CmdKmtSend: |
474 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
475 |
{ |
476 |
FileVar->DirLen = 0; |
477 |
strncpy_s(FileVar->FullName, sizeof(FileVar->FullName),ParamFileName, _TRUNCATE); |
478 |
FileVar->NumFname = 1; |
479 |
FileVar->NoMsg = TRUE; |
480 |
DdeCmnd = TRUE; |
481 |
if (Command[0]==CmdKmtGet) |
482 |
i = IdKmtGet; |
483 |
else |
484 |
i = IdKmtSend; |
485 |
KermitStart(i); |
486 |
} |
487 |
else |
488 |
return DDE_FNOTPROCESSED; |
489 |
break; |
490 |
case CmdLoadKeyMap: |
491 |
strncpy_s(ts.KeyCnfFN, sizeof(ts.KeyCnfFN),ParamFileName, _TRUNCATE); |
492 |
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdLoadKeyMap,0); |
493 |
break; |
494 |
case CmdLogClose: |
495 |
if (LogVar != NULL) FileTransEnd(OpLog); |
496 |
break; |
497 |
case CmdLogOpen: |
498 |
if ((LogVar==NULL) && NewFileVar(&LogVar)) |
499 |
{ |
500 |
BOOL ret; |
501 |
LogVar->DirLen = 0; |
502 |
LogVar->NoMsg = TRUE; |
503 |
strncpy_s(LogVar->FullName, sizeof(LogVar->FullName),ParamFileName, _TRUNCATE); |
504 |
ParseStrftimeFileName(LogVar->FullName, sizeof(LogVar->FullName)); |
505 |
ts.TransBin = ParamBinaryFlag; |
506 |
ts.Append = ParamAppendFlag; |
507 |
ret = LogStart(); |
508 |
if (ret) { |
509 |
strncpy_s(ParamFileName, sizeof(ParamFileName),"1", _TRUNCATE); |
510 |
} |
511 |
else { |
512 |
strncpy_s(ParamFileName, sizeof(ParamFileName),"0", _TRUNCATE); |
513 |
} |
514 |
} |
515 |
else |
516 |
return DDE_FNOTPROCESSED; |
517 |
break; |
518 |
case CmdLogPause: |
519 |
FLogChangeButton(TRUE); |
520 |
break; |
521 |
case CmdLogStart: |
522 |
FLogChangeButton(FALSE); |
523 |
break; |
524 |
case CmdLogWrite: |
525 |
if (LogVar != NULL) |
526 |
{ |
527 |
_lwrite(LogVar->FileHandle, |
528 |
ParamFileName,strlen(ParamFileName)); |
529 |
LogVar->ByteCount = |
530 |
LogVar->ByteCount + strlen(ParamFileName); |
531 |
FLogRefreshNum(); |
532 |
} |
533 |
break; |
534 |
case CmdQVRecv: |
535 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
536 |
{ |
537 |
FileVar->NoMsg = TRUE; |
538 |
DdeCmnd = TRUE; |
539 |
QVStart(IdQVReceive); |
540 |
} |
541 |
else |
542 |
return DDE_FNOTPROCESSED; |
543 |
break; |
544 |
case CmdQVSend: |
545 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
546 |
{ |
547 |
FileVar->DirLen = 0; |
548 |
strncpy_s(FileVar->FullName, sizeof(FileVar->FullName),ParamFileName, _TRUNCATE); |
549 |
FileVar->NumFname = 1; |
550 |
FileVar->NoMsg = TRUE; |
551 |
DdeCmnd = TRUE; |
552 |
QVStart(IdQVSend); |
553 |
} |
554 |
else |
555 |
return DDE_FNOTPROCESSED; |
556 |
break; |
557 |
case CmdRestoreSetup: |
558 |
strncpy_s(ts.SetupFName, sizeof(ts.SetupFName),ParamFileName, _TRUNCATE); |
559 |
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdRestoreSetup,0); |
560 |
break; |
561 |
case CmdSendBreak: |
562 |
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdBreak,0); |
563 |
break; |
564 |
case CmdSendFile: |
565 |
if ((SendVar==NULL) && NewFileVar(&SendVar)) |
566 |
{ |
567 |
SendVar->DirLen = 0; |
568 |
strncpy_s(SendVar->FullName, sizeof(SendVar->FullName),ParamFileName, _TRUNCATE); |
569 |
ts.TransBin = ParamBinaryFlag; |
570 |
SendVar->NoMsg = TRUE; |
571 |
DdeCmnd = TRUE; |
572 |
FileSendStart(); |
573 |
} |
574 |
else |
575 |
return DDE_FNOTPROCESSED; |
576 |
break; |
577 |
case CmdSendKCode: |
578 |
w = HexStr2Word(ParamFileName); |
579 |
c = HexStr2Word(&ParamFileName[4]); |
580 |
PostMessage(HVTWin,WM_USER_KEYCODE,w,(LPARAM)c); |
581 |
break; |
582 |
case CmdSetEcho: |
583 |
ts.LocalEcho = ParamBinaryFlag; |
584 |
if (cv.Ready && cv.TelFlag && (ts.TelEcho>0)) |
585 |
TelChangeEcho(); |
586 |
break; |
587 |
case CmdSetTitle: |
588 |
strncpy_s(ts.Title, sizeof(ts.Title),ParamFileName, _TRUNCATE); |
589 |
ChangeTitle(); |
590 |
break; |
591 |
case CmdShowTT: |
592 |
switch (ParamFileName[0]) { |
593 |
case '-': ShowWindow(HVTWin,SW_HIDE); break; |
594 |
case '0': ShowWindow(HVTWin,SW_MINIMIZE); break; |
595 |
case '1': ShowWindow(HVTWin,SW_RESTORE); break; |
596 |
case '2': ShowWindow(HTEKWin,SW_HIDE); break; |
597 |
case '3': ShowWindow(HTEKWin,SW_MINIMIZE); break; |
598 |
case '4': |
599 |
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdCtrlOpenTEK,0); |
600 |
break; |
601 |
case '5': |
602 |
PostMessage(HVTWin,WM_USER_ACCELCOMMAND,IdCmdCtrlCloseTEK,0); |
603 |
break; |
604 |
case '6': //steven add |
605 |
if (HWndLog == NULL) |
606 |
break; |
607 |
else |
608 |
ShowWindow(HWndLog, SW_HIDE); |
609 |
break; |
610 |
case '7': //steven add |
611 |
if (HWndLog == NULL) |
612 |
break; |
613 |
else |
614 |
ShowWindow(HWndLog, SW_MINIMIZE); |
615 |
break; |
616 |
case '8': //steven add |
617 |
if (HWndLog == NULL) |
618 |
break; |
619 |
else |
620 |
ShowWindow(HWndLog, SW_RESTORE); |
621 |
break; |
622 |
} |
623 |
break; |
624 |
case CmdXmodemRecv: |
625 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
626 |
{ |
627 |
FileVar->DirLen = 0; |
628 |
strncpy_s(FileVar->FullName, sizeof(FileVar->FullName),ParamFileName, _TRUNCATE); |
629 |
ts.XmodemOpt = ParamXmodemOpt; |
630 |
ts.XmodemBin = ParamBinaryFlag; |
631 |
FileVar->NoMsg = TRUE; |
632 |
DdeCmnd = TRUE; |
633 |
XMODEMStart(IdXReceive); |
634 |
} |
635 |
else |
636 |
return DDE_FNOTPROCESSED; |
637 |
break; |
638 |
case CmdXmodemSend: |
639 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
640 |
{ |
641 |
FileVar->DirLen = 0; |
642 |
strncpy_s(FileVar->FullName, sizeof(FileVar->FullName),ParamFileName, _TRUNCATE); |
643 |
ts.XmodemOpt = ParamXmodemOpt; |
644 |
FileVar->NoMsg = TRUE; |
645 |
DdeCmnd = TRUE; |
646 |
XMODEMStart(IdXSend); |
647 |
} |
648 |
else |
649 |
return DDE_FNOTPROCESSED; |
650 |
break; |
651 |
case CmdZmodemRecv: |
652 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
653 |
{ |
654 |
FileVar->NoMsg = TRUE; |
655 |
DdeCmnd = TRUE; |
656 |
ZMODEMStart(IdZReceive); |
657 |
} |
658 |
else |
659 |
return DDE_FNOTPROCESSED; |
660 |
break; |
661 |
case CmdZmodemSend: |
662 |
if ((FileVar==NULL) && NewFileVar(&FileVar)) |
663 |
{ |
664 |
FileVar->DirLen = 0; |
665 |
strncpy_s(FileVar->FullName, sizeof(FileVar->FullName),ParamFileName, _TRUNCATE); |
666 |
FileVar->NumFname = 1; |
667 |
ts.XmodemBin = ParamBinaryFlag; |
668 |
FileVar->NoMsg = TRUE; |
669 |
DdeCmnd = TRUE; |
670 |
ZMODEMStart(IdZSend); |
671 |
} |
672 |
else |
673 |
return DDE_FNOTPROCESSED; |
674 |
break; |
675 |
// add 'callmenu' (2007.11.18 maya) |
676 |
case CmdCallMenu: |
677 |
i = atoi(Command + 1); |
678 |
if (i >= 51110 && i <= 51990) { |
679 |
PostMessage(HTEKWin,WM_COMMAND,MAKELONG(i,0),0); |
680 |
} |
681 |
else { |
682 |
PostMessage(HVTWin,WM_COMMAND,MAKELONG(i,0),0); |
683 |
} |
684 |
break; |
685 |
|
686 |
case CmdSetSecondFile: // add 'scpsend' (2008.1.3 yutaka) |
687 |
memset(ParamSecondFileName, 0, sizeof(ParamSecondFileName)); |
688 |
strncpy_s(ParamSecondFileName, sizeof(ParamSecondFileName),&(Command[1]), _TRUNCATE); |
689 |
break; |
690 |
|
691 |
case CmdScpSend: // add 'scpsend' (2008.1.1 yutaka) |
692 |
{ |
693 |
typedef int (CALLBACK *PSSH_start_scp)(char *, char *); |
694 |
static PSSH_start_scp func = NULL; |
695 |
static HMODULE h = NULL, h2 = NULL; |
696 |
char msg[128]; |
697 |
|
698 |
//MessageBox(NULL, "hoge", "foo", MB_OK); |
699 |
|
700 |
if (func == NULL) { |
701 |
h2 = LoadLibrary("ttxssh.dll"); |
702 |
if ( ((h = GetModuleHandle("ttxssh.dll")) == NULL) ) { |
703 |
_snprintf_s(msg, sizeof(msg), _TRUNCATE, "GetModuleHandle(\"ttxssh.dll\")) %d", GetLastError()); |
704 |
goto scp_send_error; |
705 |
} |
706 |
func = (PSSH_start_scp)GetProcAddress(h, "TTXScpSendfile"); |
707 |
if (func == NULL) { |
708 |
_snprintf_s(msg, sizeof(msg), _TRUNCATE, "GetProcAddress(\"TTXScpSendfile\")) %d", GetLastError()); |
709 |
goto scp_send_error; |
710 |
} |
711 |
} |
712 |
|
713 |
if (func != NULL) { |
714 |
//MessageBox(NULL, ParamFileName, "foo2", MB_OK); |
715 |
//MessageBox(NULL, ParamSecondFileName, "foo3", MB_OK); |
716 |
DdeCmnd = TRUE; |
717 |
func(ParamFileName, ParamSecondFileName); |
718 |
EndDdeCmnd(1); // �}�N�����s���I���������B�{�������ASCP�]���������������������o�����������]�������B |
719 |
break; |
720 |
} |
721 |
|
722 |
scp_send_error: |
723 |
MessageBox(NULL, msg, "Tera Term: scpsend command error", MB_OK | MB_ICONERROR); |
724 |
FreeLibrary(h2); |
725 |
return DDE_FNOTPROCESSED; |
726 |
} |
727 |
break; |
728 |
|
729 |
case CmdScpRcv: |
730 |
{ |
731 |
typedef int (CALLBACK *PSSH_start_scp)(char *, char *); |
732 |
static PSSH_start_scp func = NULL; |
733 |
static HMODULE h = NULL, h2 = NULL; |
734 |
char msg[128]; |
735 |
|
736 |
//MessageBox(NULL, "hoge", "foo", MB_OK); |
737 |
|
738 |
if (func == NULL) { |
739 |
h2 = LoadLibrary("ttxssh.dll"); |
740 |
if ( ((h = GetModuleHandle("ttxssh.dll")) == NULL) ) { |
741 |
_snprintf_s(msg, sizeof(msg), _TRUNCATE, "GetModuleHandle(\"ttxssh.dll\")) %d", GetLastError()); |
742 |
goto scp_rcv_error; |
743 |
} |
744 |
func = (PSSH_start_scp)GetProcAddress(h, "TTXScpReceivefile"); |
745 |
if (func == NULL) { |
746 |
_snprintf_s(msg, sizeof(msg), _TRUNCATE, "GetProcAddress(\"TTXScpReceivefile\")) %d", GetLastError()); |
747 |
goto scp_rcv_error; |
748 |
} |
749 |
} |
750 |
|
751 |
if (func != NULL) { |
752 |
//MessageBox(NULL, ParamFileName, "foo2", MB_OK); |
753 |
//MessageBox(NULL, ParamSecondFileName, "foo3", MB_OK); |
754 |
DdeCmnd = TRUE; |
755 |
func(ParamFileName, ParamSecondFileName); |
756 |
EndDdeCmnd(1); // �}�N�����s���I���������B�{�������ASCP�]���������������������o�����������]�������B |
757 |
break; |
758 |
} |
759 |
|
760 |
scp_rcv_error: |
761 |
MessageBox(NULL, msg, "Tera Term: scpsend command error", MB_OK | MB_ICONERROR); |
762 |
FreeLibrary(h2); |
763 |
return DDE_FNOTPROCESSED; |
764 |
} |
765 |
break; |
766 |
|
767 |
case CmdSetBaud: // add 'setbaud' (2008.2.13 steven patch) |
768 |
{ |
769 |
int val, ret; |
770 |
|
771 |
//OutputDebugPrintf("CmdSetBaud entered\n"); |
772 |
|
773 |
if (!cv.Open || cv.PortType != IdSerial) |
774 |
return DDE_FNOTPROCESSED; |
775 |
|
776 |
val = atoi(ParamFileName); |
777 |
ret = GetCommSerialBaudRate(val); |
778 |
//OutputDebugPrintf("CmdSetBaud: %d %d (%d)\n", val, ret, ts.Baud); |
779 |
if (ret > 0) { |
780 |
ts.Baud = val; |
781 |
CommResetSerial(&ts,&cv,FALSE); // reset serial port |
782 |
PostMessage(HVTWin,WM_USER_CHANGETITLE,0,0); // refresh title bar |
783 |
} |
784 |
} |
785 |
break; |
786 |
|
787 |
case CmdSetRts: // add 'setrts' (2008.3.12 maya) |
788 |
{ |
789 |
int val, ret; |
790 |
|
791 |
if (!cv.Open || cv.PortType != IdSerial || ts.Flow != IdFlowNone) |
792 |
return DDE_FNOTPROCESSED; |
793 |
|
794 |
val = atoi(ParamFileName); |
795 |
if (val == 0) { |
796 |
ret = EscapeCommFunction(cv.ComID, CLRRTS); |
797 |
} |
798 |
else { |
799 |
ret = EscapeCommFunction(cv.ComID, SETRTS); |
800 |
} |
801 |
} |
802 |
break; |
803 |
|
804 |
case CmdSetDtr: // add 'setdtr' (2008.3.12 maya) |
805 |
{ |
806 |
int val, ret; |
807 |
|
808 |
if (!cv.Open || cv.PortType != IdSerial || ts.Flow != IdFlowNone) |
809 |
return DDE_FNOTPROCESSED; |
810 |
|
811 |
val = atoi(ParamFileName); |
812 |
if (val == 0) { |
813 |
ret = EscapeCommFunction(cv.ComID, CLRDTR); |
814 |
} |
815 |
else { |
816 |
ret = EscapeCommFunction(cv.ComID, SETDTR); |
817 |
} |
818 |
} |
819 |
break; |
820 |
|
821 |
case CmdGetHostname: // add 'gethostname' (2008.12.15 maya) |
822 |
if (cv.Open) { |
823 |
if (cv.PortType == IdTCPIP) { |
824 |
strncpy_s(ParamFileName, sizeof(ParamFileName),ts.HostName, _TRUNCATE); |
825 |
} |
826 |
else if (cv.PortType == IdSerial) { |
827 |
_snprintf_s(ParamFileName, sizeof(ParamFileName), _TRUNCATE, "COM%d", ts.ComPort); |
828 |
} |
829 |
} |
830 |
break; |
831 |
|
832 |
case CmdSendBroadcast: // 'sendbroadcast' |
833 |
SendAllBroadcastMessage(HVTWin, HVTWin, 0, ParamFileName, strlen(ParamFileName)); |
834 |
DdeCmnd = TRUE; |
835 |
EndDdeCmnd(0); // �}�N�����s���I���������B |
836 |
break; |
837 |
|
838 |
case CmdSendMulticast: // 'sendmulticast' |
839 |
SendMulticastMessage(HVTWin, HVTWin, ParamFileName, ParamSecondFileName, strlen(ParamSecondFileName)); |
840 |
DdeCmnd = TRUE; |
841 |
EndDdeCmnd(0); // �}�N�����s���I���������B |
842 |
break; |
843 |
|
844 |
case CmdSetMulticastName: // 'setmulticastname' |
845 |
SetMulticastName(ParamFileName); |
846 |
DdeCmnd = TRUE; |
847 |
EndDdeCmnd(0); // �}�N�����s���I���������B |
848 |
break; |
849 |
|
850 |
default: |
851 |
return DDE_FNOTPROCESSED; |
852 |
} |
853 |
return (HDDEDATA)DDE_FACK; |
854 |
} |
855 |
|
856 |
HDDEDATA CALLBACK DdeCallbackProc(UINT CallType, UINT Fmt, HCONV Conv, |
857 |
HSZ HSz1, HSZ HSz2, HDDEDATA Data, DWORD Data1, DWORD Data2) |
858 |
{ |
859 |
HDDEDATA Result; |
860 |
|
861 |
if (Inst==0) return 0; |
862 |
Result = 0; |
863 |
|
864 |
switch (CallType) { |
865 |
case XTYP_WILDCONNECT: |
866 |
Result = WildConnect(HSz2, HSz1, Fmt); |
867 |
break; |
868 |
case XTYP_CONNECT: |
869 |
if (Conv == 0) |
870 |
{ |
871 |
if ((DdeCmpStringHandles(Topic, HSz1) == 0) && |
872 |
(DdeCmpStringHandles(Service, HSz2) == 0)) |
873 |
{ |
874 |
if (cv.Ready) |
875 |
SetDdeComReady(1); |
876 |
Result = (HDDEDATA)TRUE; |
877 |
} |
878 |
} |
879 |
break; |
880 |
case XTYP_CONNECT_CONFIRM: |
881 |
ConvH = Conv; |
882 |
break; |
883 |
case XTYP_ADVREQ: |
884 |
case XTYP_REQUEST: |
885 |
Result = AcceptRequest(HSz2); |
886 |
break; |
887 |
|
888 |
// �N���C�A���g(ttpmacro.exe)�����T�[�o(ttermpro.exe)���f�[�^�����������������A |
889 |
// �������b�Z�[�W�n���h���������������B |
890 |
// ���������� DDE_FACK�A�r�W�[�������� DDE_FBUSY �A�������������� DDE_FNOTPROCESSED �� |
891 |
// �N���C�A���g�������K�v�������Abreak���������������������������B |
892 |
// (2006.11.6 yutaka) |
893 |
case XTYP_POKE: |
894 |
Result = AcceptPoke(HSz2, Fmt, Data); |
895 |
break; |
896 |
|
897 |
case XTYP_ADVSTART: |
898 |
if ((ConvH!=0) && |
899 |
(DdeCmpStringHandles(Topic, HSz1) == 0) && |
900 |
(DdeCmpStringHandles(Item, HSz2) == 0) && |
901 |
! AdvFlag) |
902 |
{ |
903 |
AdvFlag = TRUE; |
904 |
Result = (HDDEDATA)TRUE; |
905 |
} |
906 |
break; |
907 |
case XTYP_ADVSTOP: |
908 |
if ((ConvH!=0) && |
909 |
(DdeCmpStringHandles(Topic, HSz1) == 0) && |
910 |
(DdeCmpStringHandles(Item, HSz2) == 0) && |
911 |
AdvFlag) |
912 |
{ |
913 |
AdvFlag = FALSE; |
914 |
Result = (HDDEDATA)TRUE; |
915 |
} |
916 |
break; |
917 |
case XTYP_DISCONNECT: |
918 |
ConvH = 0; |
919 |
PostMessage(HVTWin,WM_USER_DDEEND,0,0); |
920 |
break; |
921 |
case XTYP_EXECUTE: |
922 |
Result = AcceptExecute(HSz1, Data); |
923 |
} /* switch (CallType) */ |
924 |
|
925 |
return Result; |
926 |
} |
927 |
|
928 |
BOOL InitDDE() |
929 |
{ |
930 |
BOOL Ok; |
931 |
|
932 |
if (ConvH != 0) return FALSE; |
933 |
|
934 |
Ok = TRUE; |
935 |
|
936 |
if (DdeInitialize(&Inst,(PFNCALLBACK)DdeCallbackProc,0,0) == DMLERR_NO_ERROR) |
937 |
{ |
938 |
Service= DdeCreateStringHandle(Inst, ServiceName, CP_WINANSI); |
939 |
Topic = DdeCreateStringHandle(Inst, TopicName, CP_WINANSI); |
940 |
Item = DdeCreateStringHandle(Inst, ItemName, CP_WINANSI); |
941 |
Item2 = DdeCreateStringHandle(Inst, ItemName2, CP_WINANSI); |
942 |
|
943 |
Ok = DdeNameService(Inst, Service, 0, DNS_REGISTER) != 0; |
944 |
} |
945 |
else |
946 |
Ok = FALSE; |
947 |
|
948 |
SyncMode = FALSE; |
949 |
CloseTT = FALSE; |
950 |
StartupFlag = FALSE; |
951 |
DDELog = FALSE; |
952 |
|
953 |
if (Ok) |
954 |
{ |
955 |
Ok = CreateLogBuf(); |
956 |
if (Ok) DDELog = TRUE; |
957 |
} |
958 |
|
959 |
if (! Ok) EndDDE(); |
960 |
return Ok; |
961 |
} |
962 |
|
963 |
void SendDDEReady() |
964 |
{ |
965 |
GetClientHWnd(TopicName); |
966 |
PostMessage(HWndDdeCli,WM_USER_DDEREADY,0,0); |
967 |
} |
968 |
|
969 |
void EndDDE() |
970 |
{ |
971 |
DWORD Temp; |
972 |
|
973 |
if (ConvH != 0) |
974 |
DdeDisconnect(ConvH); |
975 |
ConvH = 0; |
976 |
SyncMode = FALSE; |
977 |
StartupFlag = FALSE; |
978 |
|
979 |
Temp = Inst; |
980 |
if (Inst != 0) |
981 |
{ |
982 |
Inst = 0; |
983 |
DdeNameService(Temp, Service, 0, DNS_UNREGISTER); |
984 |
if (Service != 0) |
985 |
DdeFreeStringHandle(Temp, Service); |
986 |
Service = 0; |
987 |
if (Topic != 0) |
988 |
DdeFreeStringHandle(Temp, Topic); |
989 |
Topic = 0; |
990 |
if (Item != 0) |
991 |
DdeFreeStringHandle(Temp, Item); |
992 |
Item = 0; |
993 |
if (Item2 != 0) |
994 |
DdeFreeStringHandle(Temp, Item2); |
995 |
Item2 = 0; |
996 |
|
997 |
DdeUninitialize(Temp); |
998 |
} |
999 |
TopicName[0] = 0; |
1000 |
|
1001 |
if (HWndDdeCli!=NULL) |
1002 |
PostMessage(HWndDdeCli,WM_USER_DDECMNDEND,0,0); |
1003 |
HWndDdeCli = NULL; |
1004 |
AdvFlag = FALSE; |
1005 |
|
1006 |
DDELog = FALSE; |
1007 |
FreeLogBuf(); |
1008 |
cv.NoMsg = 0; |
1009 |
} |
1010 |
|
1011 |
void DDEAdv() |
1012 |
{ |
1013 |
if ((ConvH==0) || |
1014 |
(! AdvFlag) || |
1015 |
(cv.DCount==0)) |
1016 |
return; |
1017 |
|
1018 |
if ((! SyncMode) || |
1019 |
SyncMode && SyncRecv) |
1020 |
{ |
1021 |
if (SyncFreeSpace<10) |
1022 |
SyncFreeSpace=0; |
1023 |
else |
1024 |
SyncFreeSpace=SyncFreeSpace-10; |
1025 |
DdePostAdvise(Inst,Topic,Item); |
1026 |
SyncRecv = FALSE; |
1027 |
} |
1028 |
} |
1029 |
|
1030 |
void EndDdeCmnd(int Result) |
1031 |
{ |
1032 |
if ((ConvH==0) || (HWndDdeCli==NULL) || (! DdeCmnd)) return; |
1033 |
PostMessage(HWndDdeCli,WM_USER_DDECMNDEND,(WPARAM)Result,0); |
1034 |
DdeCmnd = FALSE; |
1035 |
} |
1036 |
|
1037 |
void SetDdeComReady(WORD Ready) |
1038 |
{ |
1039 |
if (HWndDdeCli==NULL) return; |
1040 |
PostMessage(HWndDdeCli,WM_USER_DDECOMREADY,Ready,0); |
1041 |
} |
1042 |
|
1043 |
void RunMacro(PCHAR FName, BOOL Startup) |
1044 |
// FName: macro filename |
1045 |
// Startup: TRUE in case of startup macro execution. |
1046 |
// In this case, the connection to the host will |
1047 |
// made after the link to TT(P)MACRO is established. |
1048 |
{ |
1049 |
int i; |
1050 |
char Cmnd[MAXPATHLEN+40]; |
1051 |
STARTUPINFO si; |
1052 |
PROCESS_INFORMATION pi; |
1053 |
DWORD pri = NORMAL_PRIORITY_CLASS; |
1054 |
|
1055 |
SetTopic(); |
1056 |
if (! InitDDE()) return; |
1057 |
strncpy_s(Cmnd, sizeof(Cmnd),"TTPMACRO /D=", _TRUNCATE); |
1058 |
strncat_s(Cmnd,sizeof(Cmnd),TopicName,_TRUNCATE); |
1059 |
if (FName!=NULL) |
1060 |
{ |
1061 |
strncat_s(Cmnd,sizeof(Cmnd)," ",_TRUNCATE); |
1062 |
i = strlen(Cmnd); |
1063 |
strncat_s(Cmnd,sizeof(Cmnd),FName,_TRUNCATE); |
1064 |
QuoteFName(&Cmnd[i]); |
1065 |
} |
1066 |
|
1067 |
StartupFlag = Startup; |
1068 |
if (Startup) |
1069 |
strncat_s(Cmnd,sizeof(Cmnd)," /S",_TRUNCATE); // "startup" flag |
1070 |
|
1071 |
#if 0 |
1072 |
if (WinExec(Cmnd,SW_MINIMIZE) < 32) |
1073 |
EndDDE(); |
1074 |
#else |
1075 |
|
1076 |
// ���O���������������������������B(2005.8.14 yutaka) |
1077 |
#if 0 |
1078 |
// Tera Term�{�������O���������}�N�������s�������A�}�N�������������~���������� |
1079 |
// ���������A�v���Z�X���D���x��1�����������s�������B(2004/9/5 yutaka) |
1080 |
// ���O�������������������B(2004/11/28 yutaka) |
1081 |
if (FileLog || BinLog) { |
1082 |
pri = BELOW_NORMAL_PRIORITY_CLASS; |
1083 |
} |
1084 |
// �b�����u�������A���������������������B(2005/5/15 yutaka) |
1085 |
// �}�N��������telnet�������O�C�������s�������������������A�������������������B(2005/5/23 yutaka) |
1086 |
pri = BELOW_NORMAL_PRIORITY_CLASS; |
1087 |
#endif |
1088 |
|
1089 |
ZeroMemory(&si, sizeof(si)); |
1090 |
ZeroMemory(&pi, sizeof(pi)); |
1091 |
GetStartupInfo(&si); |
1092 |
si.wShowWindow = SW_MINIMIZE; |
1093 |
|
1094 |
if (CreateProcess( |
1095 |
NULL, |
1096 |
Cmnd, |
1097 |
NULL, |
1098 |
NULL, |
1099 |
FALSE, |
1100 |
pri, |
1101 |
NULL, NULL, |
1102 |
&si, &pi) == 0) { |
1103 |
EndDDE(); |
1104 |
} |
1105 |
#endif |
1106 |
} |