Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/teraterm/teraterm/filesys_log.cpp

Parent Directory Parent Directory | Revision Log Revision Log


1 /*
2 * Copyright (C) 1994-1998 T. Teranishi
3 * (C) 2005-2017 TeraTerm Project
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /* TERATERM.EXE, file transfer routines */
31 #include "stdafx.h"
32 #include "teraterm.h"
33 #include "tttypes.h"
34 #include "ttftypes.h"
35 #include "tt_res.h"
36 #include "ftdlg.h"
37 #include "protodlg.h"
38 #include "ttwinman.h"
39 #include "commlib.h"
40 #include "ttcommon.h"
41 #include "ttdde.h"
42 #include "ttlib.h"
43 #include "helpid.h"
44 #include "dlglib.h"
45 #include "vtterm.h"
46
47 #include "filesys.h"
48 #include "ftlib.h"
49
50 #include "buffer.h"
51
52 #include <io.h>
53 #include <process.h>
54
55 #define FS_BRACKET_NONE 0
56 #define FS_BRACKET_START 1
57 #define FS_BRACKET_END 2
58
59 PFileVar LogVar = NULL;
60 PFileVar SendVar = NULL;
61 PFileVar FileVar = NULL;
62 static PCHAR ProtoVar = NULL;
63 static int ProtoId;
64
65 static BYTE LogLast = 0;
66 BOOL FileLog = FALSE;
67 BOOL BinLog = FALSE;
68 BOOL DDELog = FALSE;
69 static BOOL FileRetrySend, FileRetryEcho, FileCRSend, FileReadEOF, BinaryMode;
70 static BYTE FileByte;
71
72 #define FILE_SEND_BUF_SIZE 8192
73 struct FileSendHandler {
74 CHAR buf[FILE_SEND_BUF_SIZE];
75 int pos;
76 int end;
77 };
78 static struct FileSendHandler FileSendHandler;
79 static int FileDlgRefresh;
80
81 static int FileBracketMode = FS_BRACKET_NONE;
82 static int FileBracketPtr = 0;
83 static char BracketStartStr[] = "\033[200~";
84 static char BracketEndStr[] = "\033[201~";
85
86 static BOOL FSend = FALSE;
87
88 HWND HWndLog = NULL; //steven add
89
90 static HMODULE HTTFILE = NULL;
91 static int TTFILECount = 0;
92
93 PGetSetupFname GetSetupFname;
94 PGetTransFname GetTransFname;
95 PGetMultiFname GetMultiFname;
96 PGetGetFname GetGetFname;
97 PSetFileVar SetFileVar;
98 PGetXFname GetXFname;
99 PProtoInit ProtoInit;
100 PProtoParse ProtoParse;
101 PProtoTimeOutProc ProtoTimeOutProc;
102 PProtoCancel ProtoCancel;
103 PTTFILESetUILanguageFile TTFILESetUILanguageFile;
104 PTTFILESetFileSendFilter TTFILESetFileSendFilter;
105
106 #define IdGetSetupFname 1
107 #define IdGetTransFname 2
108 #define IdGetMultiFname 3
109 #define IdGetGetFname 4
110 #define IdSetFileVar 5
111 #define IdGetXFname 6
112
113 #define IdProtoInit 7
114 #define IdProtoParse 8
115 #define IdProtoTimeOutProc 9
116 #define IdProtoCancel 10
117
118 #define IdTTFILESetUILanguageFile 11
119 #define IdTTFILESetFileSendFilter 12
120
121 /*
122 Line Head flag for timestamping
123 2007.05.24 Gentaro
124 */
125 enum enumLineEnd {
126 Line_Other = 0,
127 Line_LineHead = 1,
128 Line_FileHead = 2,
129 };
130
131 enum enumLineEnd eLineEnd = Line_LineHead;
132
133
134 // �x�����������p�X���b�h�����b�Z�[�W
135 #define WM_DPC_LOGTHREAD_SEND (WM_APP + 1)
136
137 static void CloseFileSync(PFileVar ptr);
138
139
140 BOOL LoadTTFILE()
141 {
142 BOOL Err;
143
144 if (HTTFILE != NULL)
145 {
146 TTFILECount++;
147 return TRUE;
148 }
149 else
150 TTFILECount = 0;
151
152 HTTFILE = LoadHomeDLL("TTPFILE.DLL");
153 if (HTTFILE == NULL)
154 return FALSE;
155
156 Err = FALSE;
157
158 GetSetupFname = (PGetSetupFname)GetProcAddress(HTTFILE,
159 MAKEINTRESOURCE(IdGetSetupFname));
160 if (GetSetupFname==NULL)
161 Err = TRUE;
162
163 GetTransFname = (PGetTransFname)GetProcAddress(HTTFILE,
164 MAKEINTRESOURCE(IdGetTransFname));
165 if (GetTransFname==NULL)
166 Err = TRUE;
167
168 GetMultiFname = (PGetMultiFname)GetProcAddress(HTTFILE,
169 MAKEINTRESOURCE(IdGetMultiFname));
170 if (GetMultiFname==NULL)
171 Err = TRUE;
172
173 GetGetFname = (PGetGetFname)GetProcAddress(HTTFILE,
174 MAKEINTRESOURCE(IdGetGetFname));
175 if (GetGetFname==NULL)
176 Err = TRUE;
177
178 SetFileVar = (PSetFileVar)GetProcAddress(HTTFILE,
179 MAKEINTRESOURCE(IdSetFileVar));
180 if (SetFileVar==NULL)
181 Err = TRUE;
182
183 GetXFname = (PGetXFname)GetProcAddress(HTTFILE,
184 MAKEINTRESOURCE(IdGetXFname));
185 if (GetXFname==NULL)
186 Err = TRUE;
187
188 ProtoInit = (PProtoInit)GetProcAddress(HTTFILE,
189 MAKEINTRESOURCE(IdProtoInit));
190 if (ProtoInit==NULL)
191 Err = TRUE;
192
193 ProtoParse = (PProtoParse)GetProcAddress(HTTFILE,
194 MAKEINTRESOURCE(IdProtoParse));
195 if (ProtoParse==NULL)
196 Err = TRUE;
197
198 ProtoTimeOutProc = (PProtoTimeOutProc)GetProcAddress(HTTFILE,
199 MAKEINTRESOURCE(IdProtoTimeOutProc));
200 if (ProtoTimeOutProc==NULL)
201 Err = TRUE;
202
203 ProtoCancel = (PProtoCancel)GetProcAddress(HTTFILE,
204 MAKEINTRESOURCE(IdProtoCancel));
205 if (ProtoCancel==NULL)
206 Err = TRUE;
207
208 TTFILESetUILanguageFile = (PTTFILESetUILanguageFile)GetProcAddress(HTTFILE,
209 MAKEINTRESOURCE(IdTTFILESetUILanguageFile));
210 if (TTFILESetUILanguageFile==NULL) {
211 Err = TRUE;
212 }
213 else {
214 TTFILESetUILanguageFile(ts.UILanguageFile);
215 }
216
217 TTFILESetFileSendFilter = (PTTFILESetFileSendFilter)GetProcAddress(HTTFILE,
218 MAKEINTRESOURCE(IdTTFILESetFileSendFilter));
219 if (TTFILESetFileSendFilter==NULL) {
220 Err = TRUE;
221 }
222 else {
223 TTFILESetFileSendFilter(ts.FileSendFilter);
224 }
225
226 if (Err)
227 {
228 FreeLibrary(HTTFILE);
229 HTTFILE = NULL;
230 return FALSE;
231 }
232 else {
233 TTFILECount = 1;
234 return TRUE;
235 }
236 }
237
238 BOOL FreeTTFILE()
239 {
240 if (TTFILECount==0)
241 return FALSE;
242 TTFILECount--;
243 if (TTFILECount>0)
244 return TRUE;
245 if (HTTFILE!=NULL)
246 {
247 FreeLibrary(HTTFILE);
248 HTTFILE = NULL;
249 }
250 return TRUE;
251 }
252
253 static PFileTransDlg FLogDlg = NULL;
254 static PFileTransDlg SendDlg = NULL;
255 static PProtoDlg PtDlg = NULL;
256
257 BOOL OpenFTDlg(PFileVar fv)
258 {
259 PFileTransDlg FTDlg;
260 HWND HFTDlg;
261 char uimsg[MAX_UIMSG];
262
263 FTDlg = new CFileTransDlg();
264
265 fv->StartTime = 0;
266 fv->ProgStat = 0;
267
268 if (fv->OpId != OpLog) {
269 fv->HideDialog = ts.FTHideDialog;
270 }
271
272 if (FTDlg!=NULL)
273 {
274 FTDlg->Create(fv, &cv, &ts);
275 FTDlg->RefreshNum();
276 if (fv->OpId == OpLog) {
277 HWndLog = FTDlg->m_hWnd; // steven add
278 }
279 }
280
281 if (fv->OpId==OpLog)
282 FLogDlg = FTDlg; /* Log */
283 else
284 SendDlg = FTDlg; /* File send */
285
286 HFTDlg=FTDlg->GetSafeHwnd();
287
288 GetDlgItemText(HFTDlg, IDC_TRANS_FILENAME, uimsg, sizeof(uimsg));
289 get_lang_msg("DLG_FILETRANS_FILENAME", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
290 SetDlgItemText(HFTDlg, IDC_TRANS_FILENAME, ts.UIMsg);
291 GetDlgItemText(HFTDlg, IDC_FULLPATH_LABEL, uimsg, sizeof(uimsg));
292 get_lang_msg("DLG_FILETRANS_FULLPATH", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
293 SetDlgItemText(HFTDlg, IDC_FULLPATH_LABEL, ts.UIMsg);
294 GetDlgItemText(HFTDlg, IDC_TRANS_TRANS, uimsg, sizeof(uimsg));
295 get_lang_msg("DLG_FILETRANS_TRNAS", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
296 SetDlgItemText(HFTDlg, IDC_TRANS_TRANS, ts.UIMsg);
297 GetDlgItemText(HFTDlg, IDC_TRANS_ELAPSED, uimsg, sizeof(uimsg));
298 get_lang_msg("DLG_FILETRANS_ELAPSED", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
299 SetDlgItemText(HFTDlg, IDC_TRANS_ELAPSED, ts.UIMsg);
300 GetDlgItemText(HFTDlg, IDCANCEL, uimsg, sizeof(uimsg));
301 get_lang_msg("DLG_FILETRANS_CLOSE", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
302 SetDlgItemText(HFTDlg, IDCANCEL, ts.UIMsg);
303 GetDlgItemText(HFTDlg, IDC_TRANSPAUSESTART, uimsg, sizeof(uimsg));
304 get_lang_msg("DLG_FILETRANS_PAUSE", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
305 SetDlgItemText(HFTDlg, IDC_TRANSPAUSESTART, ts.UIMsg);
306 GetDlgItemText(HFTDlg, IDC_TRANSHELP, uimsg, sizeof(uimsg));
307 get_lang_msg("BTN_HELP", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
308 SetDlgItemText(HFTDlg, IDC_TRANSHELP, ts.UIMsg);
309
310 fv->StartTime = GetTickCount();
311 if (fv->OpId == OpSendFile) {
312 InitDlgProgress(HFTDlg, IDC_TRANSPROGRESS, &fv->ProgStat);
313 ShowWindow(GetDlgItem(HFTDlg, IDC_TRANS_ELAPSED), SW_SHOW);
314 }
315
316 return (FTDlg!=NULL);
317 }
318
319 void ShowFTDlg(WORD OpId)
320 {
321 if (OpId == OpLog) {
322 if (FLogDlg != NULL) {
323 FLogDlg->ShowWindow(SW_SHOWNORMAL);
324 SetForegroundWindow(FLogDlg->GetSafeHwnd());
325 }
326 }
327 else {
328 if (SendDlg != NULL) {
329 SendDlg->ShowWindow(SW_SHOWNORMAL);
330 SetForegroundWindow(SendDlg->GetSafeHwnd());
331 }
332 }
333 }
334
335 BOOL NewFileVar(PFileVar *fv)
336 {
337 if ((*fv)==NULL)
338 {
339 *fv = (PFileVar)malloc(sizeof(TFileVar));
340 if ((*fv)!=NULL)
341 {
342 memset(*fv, 0, sizeof(TFileVar));
343 strncpy_s((*fv)->FullName, sizeof((*fv)->FullName),ts.FileDir, _TRUNCATE);
344 AppendSlash((*fv)->FullName,sizeof((*fv)->FullName));
345 (*fv)->DirLen = strlen((*fv)->FullName);
346 (*fv)->FileOpen = FALSE;
347 (*fv)->OverWrite = ((ts.FTFlag & FT_RENAME) == 0);
348 (*fv)->HMainWin = HVTWin;
349 (*fv)->Success = FALSE;
350 (*fv)->NoMsg = FALSE;
351 (*fv)->HideDialog = FALSE;
352 }
353 }
354
355 return ((*fv)!=NULL);
356 }
357
358 void FreeFileVar(PFileVar *fv)
359 {
360 if ((*fv)!=NULL)
361 {
362 CloseFileSync(*fv);
363 //if ((*fv)->FileOpen) _lclose((*fv)->FileHandle);
364 if ((*fv)->FnStrMemHandle>0)
365 {
366 GlobalUnlock((*fv)->FnStrMemHandle);
367 GlobalFree((*fv)->FnStrMemHandle);
368 }
369 free(*fv);
370 *fv = NULL;
371 }
372 }
373
374 // &h ���z�X�g�����u�� (2007.5.14)
375 // &p ��TCP�|�[�g�������u�� (2009.6.12)
376 void ConvertLogname(char *c, int destlen)
377 {
378 char buf[MAXPATHLEN], buf2[MAXPATHLEN], *p = c;
379 char tmphost[1024];
380 char tmpuser[256+1];
381 DWORD len_user = sizeof(tmpuser);
382
383 memset(buf, 0, sizeof(buf));
384
385 while(*p != '\0') {
386 if (*p == '&' && *(p+1) != '\0') {
387 switch (*(p+1)) {
388 case 'h':
389 if (cv.Open) {
390 if (cv.PortType == IdTCPIP) {
391 // �z�X�g����IPv6�A�h���X�����A�t�@�C�������g�p�����������������������A
392 // �]�v�����������������B
393 // (2013.3.9 yutaka)
394 strncpy_s(tmphost, sizeof(tmphost), ts.HostName, _TRUNCATE);
395 //strncpy_s(tmphost, sizeof(tmphost), "2001:0db8:bd05:01d2:288a:1fc0:0001:10ee", _TRUNCATE);
396 replaceInvalidFileNameChar(tmphost, '_');
397 strncat_s(buf,sizeof(buf), tmphost, _TRUNCATE);
398 }
399 else if (cv.PortType == IdSerial) {
400 strncpy_s(buf2,sizeof(buf2),buf,_TRUNCATE);
401 _snprintf_s(buf, sizeof(buf), _TRUNCATE, "%sCOM%d", buf2, ts.ComPort);
402 }
403 }
404 break;
405 case 'p':
406 if (cv.Open) {
407 if (cv.PortType == IdTCPIP) {
408 char port[6];
409 _snprintf_s(port, sizeof(port), _TRUNCATE, "%d", ts.TCPPort);
410 strncat_s(buf,sizeof(buf),port,_TRUNCATE);
411 }
412 }
413 break;
414 case 'u':
415 if (GetUserName(tmpuser, &len_user) != 0) {
416 strncat_s(buf,sizeof(buf),tmpuser,_TRUNCATE);
417 }
418 break;
419 default:
420 strncpy_s(buf2,sizeof(buf2),p,2);
421 strncat_s(buf,sizeof(buf),buf2,_TRUNCATE);
422 }
423 p++;
424 }
425 else {
426 strncpy_s(buf2,sizeof(buf2),p,1);
427 strncat_s(buf,sizeof(buf),buf2,_TRUNCATE);
428 }
429 p++;
430 }
431 strncpy_s(c, destlen, buf, _TRUNCATE);
432 }
433
434 void FixLogOption()
435 {
436 if (ts.LogBinary) {
437 ts.LogTypePlainText = false;
438 ts.LogTimestamp = false;
439 }
440 }
441
442
443 // �X���b�h���I�����t�@�C�����N���[�Y
444 static void CloseFileSync(PFileVar ptr)
445 {
446 BOOL ret;
447 DWORD code;
448
449 if (!ptr->FileOpen)
450 return;
451
452 if (ptr->LogThread != (HANDLE)-1) {
453 // �X���b�h���I������
454 ret = PostThreadMessage(ptr->LogThreadId, WM_QUIT, 0, 0);
455 if (ret != 0) {
456 // �X���b�h�L���[���G���L���[���������������������������s���B
457 WaitForSingleObject(ptr->LogThread, INFINITE);
458 }
459 else {
460 code = GetLastError();
461 }
462 CloseHandle(ptr->LogThread);
463 ptr->LogThread = (HANDLE)-1;
464 }
465 CloseHandle((HANDLE)ptr->FileHandle);
466 }
467
468 // �x�����������p�X���b�h
469 static unsigned _stdcall DeferredLogWriteThread(void *arg)
470 {
471 MSG msg;
472 PFileVar fv = (PFileVar)arg;
473 PCHAR buf;
474 DWORD buflen;
475 DWORD wrote;
476
477 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
478
479 // �X���b�h�L���[���������I�������������X���b�h�����������m�����B
480 if (fv->LogThreadEvent != NULL) {
481 SetEvent(fv->LogThreadEvent);
482 }
483
484 while (GetMessage(&msg, NULL, 0, 0) > 0) {
485 switch (msg.message) {
486 case WM_DPC_LOGTHREAD_SEND:
487 buf = (PCHAR)msg.wParam;
488 buflen = (DWORD)msg.lParam;
489 WriteFile((HANDLE)LogVar->FileHandle, buf, buflen, &wrote, NULL);
490 free(buf); // ����������������
491 break;
492
493 case WM_QUIT:
494 goto end;
495 break;
496 }
497 }
498
499 end:
500 _endthreadex(0);
501 return (0);
502 }
503
504
505 extern "C" {
506 BOOL LogStart()
507 {
508 LONG Option;
509 char *logdir;
510 unsigned tid;
511 DWORD ofs, size, written_size;
512 char buf[512];
513 const char *crlf = "\r\n";
514 DWORD crlf_len = 2;
515
516 if ((FileLog) || (BinLog)) return FALSE;
517
518 if (! LoadTTFILE()) return FALSE;
519 if (! NewFileVar(&LogVar))
520 {
521 FreeTTFILE();
522 return FALSE;
523 }
524 LogVar->OpId = OpLog;
525
526 if (strlen(ts.LogDefaultPath) > 0) {
527 logdir = ts.LogDefaultPath;
528 }
529 else if (strlen(ts.FileDir) > 0) {
530 logdir = ts.FileDir;
531 }
532 else {
533 logdir = ts.HomeDir;
534 }
535
536 if (strlen(&(LogVar->FullName[LogVar->DirLen]))==0) {
537 Option = 0;
538 if (ts.LogBinary) {
539 Option |= LOGDLG_BINARY;
540 }
541 if (ts.Append) {
542 Option |= LOGDLG_APPEND;
543 }
544 if (ts.LogTypePlainText) {
545 Option |= LOGDLG_PLAINTEXT;
546 }
547 if (ts.LogTimestamp) {
548 Option |= LOGDLG_TIMESTAMP;
549 }
550 if (ts.LogHideDialog) {
551 Option |= LOGDLG_HIDEDIALOG;
552 }
553 if (ts.LogAllBuffIncludedInFirst) {
554 Option |= LOGDLG_INCSCRBUFF;
555 }
556
557 switch (ts.LogTimestampType) {
558 case TIMESTAMP_LOCAL:
559 // nothing to do
560 break;
561 case TIMESTAMP_UTC:
562 Option |= LOGDLG_UTC;
563 break;
564 case TIMESTAMP_ELAPSED_LOGSTART:
565 Option |= LOGDLG_ELAPSED;
566 break;
567 case TIMESTAMP_ELAPSED_CONNECTED:
568 Option |= LOGDLG_ELAPSED | LOGDLG_ELAPSEDCON;
569 break;
570 default:
571 // not reached
572 break;
573 }
574
575 // ���O���f�t�H���g�t�@�C���������� (2006.8.28 maya)
576 strncat_s(LogVar->FullName, sizeof(LogVar->FullName), ts.LogDefaultName, _TRUNCATE);
577 ParseStrftimeFileName(LogVar->FullName, sizeof(LogVar->FullName));
578 ConvertLogname(LogVar->FullName, sizeof(LogVar->FullName));
579
580 strncpy_s(LogVar->LogDefaultPath, sizeof(LogVar->LogDefaultPath), ts.LogDefaultPath, _TRUNCATE);
581 if (! (*GetTransFname)(LogVar, logdir, GTF_LOG, &Option)) {
582 FreeFileVar(&LogVar);
583 FreeTTFILE();
584 return FALSE;
585 }
586
587 ts.LogBinary = CheckFlag(Option, LOGDLG_BINARY);
588 CheckFlag(Option, LOGDLG_BINARY);
589 ts.Append =
590 CheckFlag(Option, LOGDLG_APPEND);
591 ts.LogTypePlainText =
592 CheckFlag(Option, LOGDLG_PLAINTEXT);
593 ts.LogTimestamp =
594 CheckFlag(Option, LOGDLG_TIMESTAMP);
595 ts.LogHideDialog =
596 CheckFlag(Option, LOGDLG_HIDEDIALOG);
597 ts.LogAllBuffIncludedInFirst =
598 CheckFlag(Option, LOGDLG_INCSCRBUFF);
599
600 if (Option & LOGDLG_ELAPSED) {
601 // �o������
602 if (Option & LOGDLG_ELAPSEDCON) {
603 ts.LogTimestampType = TIMESTAMP_ELAPSED_CONNECTED;
604 }
605 else {
606 ts.LogTimestampType = TIMESTAMP_ELAPSED_LOGSTART;
607 }
608 }
609 else {
610 // �����`��
611 if (Option & LOGDLG_UTC) {
612 ts.LogTimestampType = TIMESTAMP_UTC;
613 }
614 else {
615 ts.LogTimestampType = TIMESTAMP_LOCAL;
616 }
617 }
618 }
619 else {
620 // LogVar->DirLen = 0 ��������������
621 // �t���p�X�E�����p�X������ LogVar->FullName �������������K�v������
622 char FileName[MAX_PATH];
623
624 // �t���p�X��
625 strncpy_s(FileName, sizeof(FileName), LogVar->FullName, _TRUNCATE);
626 ConvFName(logdir, FileName, sizeof(FileName), "", LogVar->FullName, sizeof(LogVar->FullName));
627
628 ParseStrftimeFileName(LogVar->FullName, sizeof(LogVar->FullName));
629 ConvertLogname(LogVar->FullName, sizeof(LogVar->FullName));
630
631 (*SetFileVar)(LogVar);
632
633 FixLogOption();
634 }
635
636 if (ts.LogBinary > 0)
637 {
638 BinLog = TRUE;
639 FileLog = FALSE;
640 if (! CreateBinBuf())
641 {
642 FileTransEnd(OpLog);
643 return FALSE;
644 }
645 }
646 else {
647 BinLog = FALSE;
648 FileLog = TRUE;
649 if (! CreateLogBuf())
650 {
651 FileTransEnd(OpLog);
652 return FALSE;
653 }
654 }
655 cv.LStart = cv.LogPtr;
656 cv.LCount = 0;
657 if (ts.LogHideDialog)
658 LogVar->HideDialog = 1;
659
660 HelpId = HlpFileLog;
661 /* 2007.05.24 Gentaro */
662 eLineEnd = Line_LineHead;
663
664 if (ts.Append > 0)
665 {
666 int dwShareMode = FILE_SHARE_READ;
667 if (!ts.LogLockExclusive) {
668 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
669 }
670 LogVar->FileHandle = (int)CreateFile(LogVar->FullName, GENERIC_WRITE, dwShareMode, NULL,
671 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
672 if (LogVar->FileHandle>0){
673 SetFilePointer((HANDLE)LogVar->FileHandle, 0, NULL, FILE_END);
674 /* 2007.05.24 Gentaro
675 If log file already exists,
676 a newline is inserted before the first timestamp.
677 */
678 eLineEnd = Line_FileHead;
679 }
680 }
681 else {
682 int dwShareMode = FILE_SHARE_READ;
683 if (!ts.LogLockExclusive) {
684 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
685 }
686 LogVar->FileHandle = (int)CreateFile(LogVar->FullName, GENERIC_WRITE, dwShareMode, NULL,
687 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
688 }
689 LogVar->FileOpen = (LogVar->FileHandle>0);
690 if (! LogVar->FileOpen)
691 {
692 char msg[128];
693
694 // �t�@�C���I�[�v���G���[�������b�Z�[�W�\�������������B(2008.7.9 yutaka)
695 if (LogVar->NoMsg == FALSE) {
696 _snprintf_s(msg, sizeof(msg), _TRUNCATE, "Can not create a `%s' file. (%d)", LogVar->FullName, GetLastError());
697 MessageBox(NULL, msg, "Tera Term: File open error", MB_OK | MB_ICONERROR);
698 }
699
700 FileTransEnd(OpLog);
701 return FALSE;
702 }
703 LogVar->ByteCount = 0;
704
705 // Log rotate configuration
706 LogVar->RotateMode = ts.LogRotate;
707 LogVar->RotateSize = ts.LogRotateSize;
708 LogVar->RotateStep = ts.LogRotateStep;
709
710 // Log rotate���L���������A�����t�@�C���T�C�Y�����������B
711 // �������t�@�C�������������T�C�Y�����[�e�[�g�������������C���B
712 // (2016.4.9 yutaka)
713 if (LogVar->RotateMode != ROTATE_NONE) {
714 size = GetFileSize((HANDLE)LogVar->FileHandle, NULL);
715 if (size != -1)
716 LogVar->ByteCount = size;
717 }
718
719 if (! OpenFTDlg(LogVar)) {
720 FileTransEnd(OpLog);
721 return FALSE;
722 }
723
724 // �x�����������p�X���b�h���N�����B
725 // (2013.4.19 yutaka)
726 // DeferredLogWriteThread �X���b�h���N�������A�X���b�h�L���[�����������������O���A
727 // ���O�t�@�C�����N���[�Y(CloseFileSync)���s���������A�G���L���[�����s���A�f�b�h���b�N
728 // �����������������C�������B
729 // �X���b�h�����������s�������A���O�����C�x���g�I�u�W�F�N�g���g�����A�X���b�h�L���[��
730 // ���������������������������������B���O�t���C�x���g�I�u�W�F�N�g���g���������A
731 // �V�X�e��(Windows OS)�������j�[�N�����O�������K�v�������B
732 // (2016.9.23 yutaka)
733 LogVar->LogThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
734 LogVar->LogThread = (HANDLE)_beginthreadex(NULL, 0, DeferredLogWriteThread, LogVar, 0, &tid);
735 LogVar->LogThreadId = tid;
736 if (LogVar->LogThreadEvent != NULL) {
737 WaitForSingleObject(LogVar->LogThreadEvent, INFINITE);
738 CloseHandle(LogVar->LogThreadEvent);
739 }
740
741 // �����o�b�t�@�������f�[�^�������������o���������A
742 // ���O�������J�n�����B
743 // (2013.9.29 yutaka)
744 if (ts.LogAllBuffIncludedInFirst) {
745 for (ofs = 0 ; ; ofs++ ) {
746 // 1�����s�����������B���������������A�G�X�P�[�v�V�[�P���X�������������B
747 size = BuffGetAnyLineData(ofs, buf, sizeof(buf));
748 if (size == -1)
749 break;
750
751 #if 0
752 if (ts.DeferredLogWriteMode) { // �x����������
753 char *pbuf = (char *)malloc(size + 2);
754 memcpy(pbuf, buf, size);
755 pbuf[size] = '\r';
756 pbuf[size+1] = '\n';
757 Sleep(1); // �X���b�h�L���[�����������������A�R���e�L�X�g�X�C�b�`�������B
758 PostThreadMessage(LogVar->LogThreadId, WM_DPC_LOGTHREAD_SEND, (WPARAM)pbuf, size + 2);
759 } else { // �������B�l�b�g���[�N�o�R�����x���B
760 #endif
761 WriteFile((HANDLE)LogVar->FileHandle, buf, size, &written_size, NULL);
762 WriteFile((HANDLE)LogVar->FileHandle, crlf, crlf_len, &written_size, NULL);
763 #if 0
764 }
765 #endif
766 }
767 }
768
769 return TRUE;
770 }
771 }
772
773 void LogPut1(BYTE b)
774 {
775 LogLast = b;
776 cv.LogBuf[cv.LogPtr] = b;
777 cv.LogPtr++;
778 if (cv.LogPtr>=InBuffSize)
779 cv.LogPtr = cv.LogPtr-InBuffSize;
780
781 if (FileLog)
782 {
783 if (cv.LCount>=InBuffSize)
784 {
785 cv.LCount = InBuffSize;
786 cv.LStart = cv.LogPtr;
787 }
788 else
789 cv.LCount++;
790 }
791 else
792 cv.LCount = 0;
793
794 if (DDELog)
795 {
796 if (cv.DCount>=InBuffSize)
797 {
798 cv.DCount = InBuffSize;
799 cv.DStart = cv.LogPtr;
800 }
801 else
802 cv.DCount++;
803 }
804 else {
805 cv.DCount = 0;
806 // ���O���������}�N�����X�g�[���������������C���B
807 // ���O�����������x�}�N�����~�������A�o�b�t�@���C���f�b�N�X�������������������A
808 // ���x�}�N�������������������f�[�^�������������������B
809 // �}�N�������~���������������C���f�b�N�X�����������������������B
810 // (2006.12.26 yutaka)
811 cv.DStart = cv.LogPtr;
812 }
813 }
814
815 void Log1Byte(BYTE b)
816 {
817 if (b==0x0d)
818 {
819 LogLast = b;
820 return;
821 }
822 if ((b==0x0a) && (LogLast==0x0d))
823 LogPut1(0x0d);
824 LogPut1(b);
825 }
826
827 static BOOL Get1(PCHAR Buf, int *Start, int *Count, PBYTE b)
828 {
829 if (*Count<=0) return FALSE;
830 *b = Buf[*Start];
831 (*Start)++;
832 if (*Start>=InBuffSize)
833 *Start = *Start-InBuffSize;
834 (*Count)--;
835 return TRUE;
836 }
837
838
839
840 static CRITICAL_SECTION g_filelog_lock; /* ���b�N�p���� */
841
842 void logfile_lock_initialize(void)
843 {
844 InitializeCriticalSection(&g_filelog_lock);
845 }
846
847 static inline void logfile_lock(void)
848 {
849 EnterCriticalSection(&g_filelog_lock);
850 }
851
852 static inline void logfile_unlock(void)
853 {
854 LeaveCriticalSection(&g_filelog_lock);
855 }
856
857 // �R�����g�����O����������
858 void CommentLogToFile(char *buf, int size)
859 {
860 DWORD wrote;
861
862 if (LogVar == NULL || !LogVar->FileOpen) {
863 char uimsg[MAX_UIMSG];
864 get_lang_msg("MSG_ERROR", uimsg, sizeof(uimsg), "ERROR", ts.UILanguageFile);
865 get_lang_msg("MSG_COMMENT_LOG_OPEN_ERROR", ts.UIMsg, sizeof(ts.UIMsg),
866 "It is not opened by the log file yet.", ts.UILanguageFile);
867 ::MessageBox(NULL, ts.UIMsg, uimsg, MB_OK|MB_ICONEXCLAMATION);
868 return;
869 }
870
871 logfile_lock();
872 WriteFile((HANDLE)LogVar->FileHandle, buf, size, &wrote, NULL);
873 WriteFile((HANDLE)LogVar->FileHandle, "\r\n", 2, &wrote, NULL); // ���s
874 /* Set Line End Flag
875 2007.05.24 Gentaro
876 */
877 eLineEnd = Line_LineHead;
878 logfile_unlock();
879 }
880
881 // ���O�����[�e�[�g�����B
882 // (2013.3.21 yutaka)
883 static void LogRotate(void)
884 {
885 int loopmax = 10000; // XXX
886 char filename[1024];
887 char newfile[1024], oldfile[1024];
888 int i, k;
889 int dwShareMode = FILE_SHARE_READ;
890 unsigned tid;
891
892 if (! LogVar->FileOpen) return;
893
894 if (LogVar->RotateMode == ROTATE_NONE)
895 return;
896
897 if (LogVar->RotateMode == ROTATE_SIZE) {
898 if (LogVar->ByteCount <= LogVar->RotateSize)
899 return;
900 //OutputDebugPrintf("%s: mode %d size %ld\n", __FUNCTION__, LogVar->RotateMode, LogVar->ByteCount);
901 } else {
902 return;
903 }
904
905 logfile_lock();
906 // ���O�T�C�Y���������������B
907 LogVar->ByteCount = 0;
908
909 // �������������t�@�C�����N���[�Y�����A�������t�@�C�����I�[�v�������B
910 CloseFileSync(LogVar);
911 //_lclose(LogVar->FileHandle);
912
913 // �������[�e�[�V�������X�e�b�v�����w����������
914 if (LogVar->RotateStep > 0)
915 loopmax = LogVar->RotateStep;
916
917 for (i = 1 ; i <= loopmax ; i++) {
918 _snprintf_s(filename, sizeof(filename), _TRUNCATE, "%s.%d", LogVar->FullName, i);
919 if (_access_s(filename, 0) != 0)
920 break;
921 }
922 if (i > loopmax) {
923 // �������������������������A�������t�@�C�������p�������B
924 i = loopmax;
925 }
926
927 // ���t�@�C�������l�[���B
928 for (k = i-1 ; k >= 0 ; k--) {
929 if (k == 0)
930 strncpy_s(oldfile, sizeof(oldfile), LogVar->FullName, _TRUNCATE);
931 else
932 _snprintf_s(oldfile, sizeof(oldfile), _TRUNCATE, "%s.%d", LogVar->FullName, k);
933 _snprintf_s(newfile, sizeof(newfile), _TRUNCATE, "%s.%d", LogVar->FullName, k+1);
934 remove(newfile);
935 if (rename(oldfile, newfile) != 0) {
936 OutputDebugPrintf("%s: rename %d\n", __FUNCTION__, errno);
937 }
938 }
939
940 // ���I�[�v��
941 if (!ts.LogLockExclusive) {
942 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
943 }
944 LogVar->FileHandle = (int)CreateFile(LogVar->FullName, GENERIC_WRITE, dwShareMode, NULL,
945 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
946
947 // �x�����������p�X���b�h���N�����B
948 // (2013.4.19 yutaka)
949 // DeferredLogWriteThread �X���b�h���N�������A�X���b�h�L���[�����������������O���A
950 // ���O�t�@�C�����N���[�Y(CloseFileSync)���s���������A�G���L���[�����s���A�f�b�h���b�N
951 // �����������������C�������B
952 // �X���b�h�����������s�������A���O�����C�x���g�I�u�W�F�N�g���g�����A�X���b�h�L���[��
953 // ���������������������������������B���O�t���C�x���g�I�u�W�F�N�g���g���������A
954 // �V�X�e��(Windows OS)�������j�[�N�����O�������K�v�������B
955 // (2016.9.26 yutaka)
956 LogVar->LogThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
957 LogVar->LogThread = (HANDLE)_beginthreadex(NULL, 0, DeferredLogWriteThread, LogVar, 0, &tid);
958 LogVar->LogThreadId = tid;
959 if (LogVar->LogThreadEvent != NULL) {
960 WaitForSingleObject(LogVar->LogThreadEvent, INFINITE);
961 CloseHandle(LogVar->LogThreadEvent);
962 }
963
964 logfile_unlock();
965
966 }
967
968 void LogToFile()
969 {
970 PCHAR Buf;
971 int Start, Count;
972 BYTE b;
973 PCHAR WriteBuf;
974 DWORD WriteBufMax, WriteBufLen;
975 CHAR tmp[128];
976 DWORD wrote;
977
978 if (! LogVar->FileOpen) return;
979 if (FileLog)
980 {
981 Buf = cv.LogBuf;
982 Start = cv.LStart;
983 Count = cv.LCount;
984 }
985 else if (BinLog)
986 {
987 Buf = cv.BinBuf;
988 Start = cv.BStart;
989 Count = cv.BCount;
990 }
991 else
992 return;
993
994 if (Buf==NULL) return;
995 if (Count==0) return;
996
997 // ���b�N������(2004.8.6 yutaka)
998 logfile_lock();
999
1000 if (ts.DeferredLogWriteMode) {
1001 WriteBufMax = 8192;
1002 WriteBufLen = 0;
1003 WriteBuf = (PCHAR)malloc(WriteBufMax);
1004 while (Get1(Buf,&Start,&Count,&b)) {
1005 if (((cv.FilePause & OpLog)==0) && (! cv.ProtoFlag))
1006 {
1007 tmp[0] = 0;
1008 if ( ts.LogTimestamp && eLineEnd ) {
1009 char *strtime = NULL;
1010
1011 switch (ts.LogTimestampType) {
1012 case TIMESTAMP_LOCAL:
1013 strtime = mctimelocal(ts.LogTimestampFormat, FALSE);
1014 break;
1015 case TIMESTAMP_UTC:
1016 strtime = mctimelocal(ts.LogTimestampFormat, TRUE);
1017 break;
1018 case TIMESTAMP_ELAPSED_LOGSTART:
1019 strtime = strelapsed(LogVar->StartTime);
1020 break;
1021 case TIMESTAMP_ELAPSED_CONNECTED:
1022 strtime = strelapsed(cv.ConnectedTime);
1023 break;
1024 }
1025
1026 /* 2007.05.24 Gentaro */
1027 if( eLineEnd == Line_FileHead ){
1028 strncat_s(tmp, sizeof(tmp), "\r\n", _TRUNCATE);
1029 }
1030 strncat_s(tmp, sizeof(tmp), "[", _TRUNCATE);
1031 strncat_s(tmp, sizeof(tmp), strtime, _TRUNCATE);
1032 strncat_s(tmp, sizeof(tmp), "] ", _TRUNCATE);
1033 }
1034
1035 /* 2007.05.24 Gentaro */
1036 if( b == 0x0a ){
1037 eLineEnd = Line_LineHead; /* set endmark*/
1038 }
1039 else {
1040 eLineEnd = Line_Other; /* clear endmark*/
1041 }
1042
1043 if (WriteBufLen >= (WriteBufMax*4/5)) {
1044 WriteBufMax *= 2;
1045 WriteBuf = (PCHAR)realloc(WriteBuf, WriteBufMax);
1046 }
1047 memcpy(&WriteBuf[WriteBufLen], tmp, strlen(tmp));
1048 WriteBufLen += strlen(tmp);
1049 WriteBuf[WriteBufLen++] = b;
1050
1051 (LogVar->ByteCount)++;
1052 }
1053 }
1054
1055 PostThreadMessage(LogVar->LogThreadId, WM_DPC_LOGTHREAD_SEND, (WPARAM)WriteBuf, WriteBufLen);
1056
1057 } else {
1058
1059 while (Get1(Buf,&Start,&Count,&b))
1060 {
1061 if (((cv.FilePause & OpLog)==0) && (! cv.ProtoFlag))
1062 {
1063 if ( ts.LogTimestamp && eLineEnd ) {
1064 char *strtime = NULL;
1065
1066 switch (ts.LogTimestampType) {
1067 case TIMESTAMP_LOCAL:
1068 strtime = mctimelocal(ts.LogTimestampFormat, FALSE);
1069 break;
1070 case TIMESTAMP_UTC:
1071 strtime = mctimelocal(ts.LogTimestampFormat, TRUE);
1072 break;
1073 case TIMESTAMP_ELAPSED_LOGSTART:
1074 strtime = strelapsed(LogVar->StartTime);
1075 break;
1076 case TIMESTAMP_ELAPSED_CONNECTED:
1077 strtime = strelapsed(cv.ConnectedTime);
1078 break;
1079 }
1080 WriteFile((HANDLE)LogVar->FileHandle, "[", 1, &wrote, NULL);
1081 WriteFile((HANDLE)LogVar->FileHandle, strtime, strlen(strtime), &wrote, NULL);
1082 WriteFile((HANDLE)LogVar->FileHandle, "] ", 2, &wrote, NULL);
1083 }
1084
1085 /* 2007.05.24 Gentaro */
1086 if( b == 0x0a ){
1087 eLineEnd = Line_LineHead; /* set endmark*/
1088 }
1089 else {
1090 eLineEnd = Line_Other; /* clear endmark*/
1091 }
1092
1093 WriteFile((HANDLE)LogVar->FileHandle, (PCHAR)&b, 1, &wrote, NULL);
1094 (LogVar->ByteCount)++;
1095 }
1096 }
1097
1098 }
1099
1100 logfile_unlock();
1101
1102 if (FileLog)
1103 {
1104 cv.LStart = Start;
1105 cv.LCount = Count;
1106 }
1107 else {
1108 cv.BStart = Start;
1109 cv.BCount = Count;
1110 }
1111 if (((cv.FilePause & OpLog) !=0) || cv.ProtoFlag) return;
1112 if (FLogDlg!=NULL)
1113 FLogDlg->RefreshNum();
1114
1115 // ���O�E���[�e�[�g
1116 LogRotate();
1117
1118 }
1119
1120 BOOL CreateLogBuf()
1121 {
1122 if (cv.HLogBuf==NULL)
1123 {
1124 cv.HLogBuf = GlobalAlloc(GMEM_MOVEABLE,InBuffSize);
1125 cv.LogBuf = NULL;
1126 cv.LogPtr = 0;
1127 cv.LStart = 0;
1128 cv.LCount = 0;
1129 cv.DStart = 0;
1130 cv.DCount = 0;
1131 }
1132 return (cv.HLogBuf!=NULL);
1133 }
1134
1135 void FreeLogBuf()
1136 {
1137 if ((cv.HLogBuf==NULL) || FileLog || DDELog)
1138 return;
1139 if (cv.LogBuf!=NULL)
1140 GlobalUnlock(cv.HLogBuf);
1141 GlobalFree(cv.HLogBuf);
1142 cv.HLogBuf = NULL;
1143 cv.LogBuf = NULL;
1144 cv.LogPtr = 0;
1145 cv.LStart = 0;
1146 cv.LCount = 0;
1147 cv.DStart = 0;
1148 cv.DCount = 0;
1149 }
1150
1151 BOOL CreateBinBuf()
1152 {
1153 if (cv.HBinBuf==NULL)
1154 {
1155 cv.HBinBuf = GlobalAlloc(GMEM_MOVEABLE,InBuffSize);
1156 cv.BinBuf = NULL;
1157 cv.BinPtr = 0;
1158 cv.BStart = 0;
1159 cv.BCount = 0;
1160 }
1161 return (cv.HBinBuf!=NULL);
1162 }
1163
1164 void FreeBinBuf()
1165 {
1166 if ((cv.HBinBuf==NULL) || BinLog)
1167 return;
1168 if (cv.BinBuf!=NULL)
1169 GlobalUnlock(cv.HBinBuf);
1170 GlobalFree(cv.HBinBuf);
1171 cv.HBinBuf = NULL;
1172 cv.BinBuf = NULL;
1173 cv.BinPtr = 0;
1174 cv.BStart = 0;
1175 cv.BCount = 0;
1176 }
1177
1178 extern "C" {
1179 void FileSendStart()
1180 {
1181 LONG Option = 0;
1182
1183 if (! cv.Ready || FSend) return;
1184 if (cv.ProtoFlag)
1185 {
1186 FreeFileVar(&SendVar);
1187 return;
1188 }
1189
1190 if (! LoadTTFILE())
1191 return;
1192 if (! NewFileVar(&SendVar))
1193 {
1194 FreeTTFILE();
1195 return;
1196 }
1197 SendVar->OpId = OpSendFile;
1198
1199 FSend = TRUE;
1200
1201 if (strlen(&(SendVar->FullName[SendVar->DirLen]))==0) {
1202 if (ts.TransBin)
1203 Option |= LOGDLG_BINARY;
1204 SendVar->FullName[0] = 0;
1205 if (! (*GetTransFname)(SendVar, ts.FileDir, GTF_SEND, &Option)) {
1206 FileTransEnd(OpSendFile);
1207 return;
1208 }
1209 ts.TransBin = CheckFlag(Option, LOGDLG_BINARY);
1210 }
1211 else
1212 (*SetFileVar)(SendVar);
1213
1214 SendVar->FileHandle = (int)CreateFile(SendVar->FullName, GENERIC_READ, FILE_SHARE_READ, NULL,
1215 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
1216 SendVar->FileOpen = (SendVar->FileHandle>0);
1217 if (! SendVar->FileOpen)
1218 {
1219 FileTransEnd(OpSendFile);
1220 return;
1221 }
1222 SendVar->ByteCount = 0;
1223 SendVar->FileSize = GetFSize(SendVar->FullName);
1224
1225 TalkStatus = IdTalkFile;
1226 FileRetrySend = FALSE;
1227 FileRetryEcho = FALSE;
1228 FileCRSend = FALSE;
1229 FileReadEOF = FALSE;
1230 FileSendHandler.pos = 0;
1231 FileSendHandler.end = 0;
1232 FileDlgRefresh = 0;
1233
1234 if (BracketedPasteMode()) {
1235 FileBracketMode = FS_BRACKET_START;
1236 FileBracketPtr = 0;
1237 BinaryMode = TRUE;
1238 }
1239 else {
1240 FileBracketMode = FS_BRACKET_NONE;
1241 BinaryMode = ts.TransBin;
1242 }
1243
1244 if (! OpenFTDlg(SendVar))
1245 FileTransEnd(OpSendFile);
1246 }
1247 }
1248
1249 void FileTransEnd(WORD OpId)
1250 /* OpId = 0: close Log and FileSend
1251 OpLog: close Log
1252 OpSendFile: close FileSend */
1253 {
1254 if (((OpId==0) || (OpId==OpLog)) && (FileLog || BinLog))
1255 {
1256 FileLog = FALSE;
1257 BinLog = FALSE;
1258 if (FLogDlg!=NULL)
1259 {
1260 FLogDlg->DestroyWindow();
1261 FLogDlg = NULL;
1262 HWndLog = NULL; // steven add
1263 }
1264 FreeFileVar(&LogVar);
1265 FreeLogBuf();
1266 FreeBinBuf();
1267 FreeTTFILE();
1268 }
1269
1270 if (((OpId==0) || (OpId==OpSendFile)) && FSend)
1271 {
1272 FSend = FALSE;
1273 TalkStatus = IdTalkKeyb;
1274 if (SendDlg!=NULL)
1275 {
1276 SendDlg->DestroyWindow();
1277 SendDlg = NULL;
1278 }
1279 FreeFileVar(&SendVar);
1280 FreeTTFILE();
1281 }
1282
1283 EndDdeCmnd(0);
1284 }
1285
1286 int FSOut1(BYTE b)
1287 {
1288 if (BinaryMode)
1289 return CommBinaryOut(&cv,(PCHAR)&b,1);
1290 else if ((b>=0x20) || (b==0x09) || (b==0x0A) || (b==0x0D))
1291 return CommTextOut(&cv,(PCHAR)&b,1);
1292 else
1293 return 1;
1294 }
1295
1296 int FSEcho1(BYTE b)
1297 {
1298 if (BinaryMode)
1299 return CommBinaryEcho(&cv,(PCHAR)&b,1);
1300 else
1301 return CommTextEcho(&cv,(PCHAR)&b,1);
1302 }
1303
1304 extern "C" {
1305 // �������������������������g��
1306 // - BinaryMode == true
1307 // - FileBracketMode == false
1308 // - cv.TelFlag == false
1309 // - ts.LocalEcho == 0
1310 void FileSendBinayBoost()
1311 {
1312 WORD c, fc;
1313 LONG BCOld;
1314 DWORD read_bytes;
1315
1316 if ((SendDlg == NULL) ||
1317 ((cv.FilePause & OpSendFile) != 0))
1318 return;
1319
1320 BCOld = SendVar->ByteCount;
1321
1322 if (FileRetrySend)
1323 {
1324 c = CommRawOut(&cv, &(FileSendHandler.buf[FileSendHandler.pos]),
1325 FileSendHandler.end - FileSendHandler.pos);
1326 FileSendHandler.pos += c;
1327 FileRetrySend = (FileSendHandler.end != FileSendHandler.pos);
1328 if (FileRetrySend)
1329 return;
1330 }
1331
1332 do {
1333 if (FileSendHandler.pos == FileSendHandler.end) {
1334 ReadFile((HANDLE)SendVar->FileHandle, &(FileSendHandler.buf[0]), sizeof(FileSendHandler.buf), &read_bytes, NULL);
1335 fc = LOWORD(read_bytes);
1336 FileSendHandler.pos = 0;
1337 FileSendHandler.end = fc;
1338 } else {
1339 fc = FileSendHandler.end - FileSendHandler.end;
1340 }
1341
1342 if (fc != 0)
1343 {
1344 c = CommRawOut(&cv, &(FileSendHandler.buf[FileSendHandler.pos]),
1345 FileSendHandler.end - FileSendHandler.pos);
1346 FileSendHandler.pos += c;
1347 FileRetrySend = (FileSendHandler.end != FileSendHandler.pos);
1348 SendVar->ByteCount = SendVar->ByteCount + c;
1349 if (FileRetrySend)
1350 {
1351 if (SendVar->ByteCount != BCOld)
1352 SendDlg->RefreshNum();
1353 return;
1354 }
1355 }
1356 FileDlgRefresh = SendVar->ByteCount;
1357 SendDlg->RefreshNum();
1358 BCOld = SendVar->ByteCount;
1359 if (fc != 0)
1360 return;
1361 } while (fc != 0);
1362
1363 FileTransEnd(OpSendFile);
1364 }
1365 }
1366
1367 extern "C" {
1368 void FileSend()
1369 {
1370 WORD c, fc;
1371 LONG BCOld;
1372 DWORD read_bytes;
1373
1374 if (cv.PortType == IdSerial && ts.FileSendHighSpeedMode &&
1375 BinaryMode && !FileBracketMode && !cv.TelFlag &&
1376 (ts.LocalEcho == 0) && (ts.Baud >= 115200)) {
1377 return FileSendBinayBoost();
1378 }
1379
1380 if ((SendDlg==NULL) ||
1381 ((cv.FilePause & OpSendFile) !=0))
1382 return;
1383
1384 BCOld = SendVar->ByteCount;
1385
1386 if (FileRetrySend)
1387 {
1388 FileRetryEcho = (ts.LocalEcho>0);
1389 c = FSOut1(FileByte);
1390 FileRetrySend = (c==0);
1391 if (FileRetrySend)
1392 return;
1393 }
1394
1395 if (FileRetryEcho)
1396 {
1397 c = FSEcho1(FileByte);
1398 FileRetryEcho = (c==0);
1399 if (FileRetryEcho)
1400 return;
1401 }
1402
1403 do {
1404 if (FileBracketMode == FS_BRACKET_START) {
1405 FileByte = BracketStartStr[FileBracketPtr++];
1406 fc = 1;
1407
1408 if (FileBracketPtr >= sizeof(BracketStartStr) - 1) {
1409 FileBracketMode = FS_BRACKET_END;
1410 FileBracketPtr = 0;
1411 BinaryMode = ts.TransBin;
1412 }
1413 }
1414 else if (! FileReadEOF) {
1415 ReadFile((HANDLE)SendVar->FileHandle, &FileByte, 1, &read_bytes, NULL);
1416 fc = LOWORD(read_bytes);
1417 SendVar->ByteCount = SendVar->ByteCount + fc;
1418
1419 if (FileCRSend && (fc==1) && (FileByte==0x0A)) {
1420 ReadFile((HANDLE)SendVar->FileHandle, &FileByte, 1, &read_bytes, NULL);
1421 fc = LOWORD(read_bytes);
1422 SendVar->ByteCount = SendVar->ByteCount + fc;
1423 }
1424 }
1425 else {
1426 fc = 0;
1427 }
1428
1429 if (fc == 0 && FileBracketMode == FS_BRACKET_END) {
1430 FileReadEOF = TRUE;
1431 FileByte = BracketEndStr[FileBracketPtr++];
1432 fc = 1;
1433 BinaryMode = TRUE;
1434
1435 if (FileBracketPtr >= sizeof(BracketEndStr) - 1) {
1436 FileBracketMode = FS_BRACKET_NONE;
1437 FileBracketPtr = 0;
1438 }
1439 }
1440
1441
1442 if (fc!=0)
1443 {
1444 c = FSOut1(FileByte);
1445 FileCRSend = (ts.TransBin==0) && (FileByte==0x0D);
1446 FileRetrySend = (c==0);
1447 if (FileRetrySend)
1448 {
1449 if (SendVar->ByteCount != BCOld)
1450 SendDlg->RefreshNum();
1451 return;
1452 }
1453 if (ts.LocalEcho>0)
1454 {
1455 c = FSEcho1(FileByte);
1456 FileRetryEcho = (c==0);
1457 if (FileRetryEcho)
1458 return;
1459 }
1460 }
1461 if ((fc==0) || ((SendVar->ByteCount % 100 == 0) && (FileBracketPtr == 0))) {
1462 SendDlg->RefreshNum();
1463 BCOld = SendVar->ByteCount;
1464 if (fc!=0)
1465 return;
1466 }
1467 } while (fc!=0);
1468
1469 FileTransEnd(OpSendFile);
1470 }
1471 }
1472
1473 extern "C" {
1474 void FLogChangeButton(BOOL Pause)
1475 {
1476 if (FLogDlg!=NULL)
1477 FLogDlg->ChangeButton(Pause);
1478 }
1479 }
1480
1481 extern "C" {
1482 void FLogRefreshNum()
1483 {
1484 if (FLogDlg!=NULL)
1485 FLogDlg->RefreshNum();
1486 }
1487 }
1488
1489 BOOL OpenProtoDlg(PFileVar fv, int IdProto, int Mode, WORD Opt1, WORD Opt2)
1490 {
1491 int vsize;
1492 PProtoDlg pd;
1493 HWND Hpd;
1494 char uimsg[MAX_UIMSG];
1495
1496 ProtoId = IdProto;
1497
1498 switch (ProtoId) {
1499 case PROTO_KMT:
1500 vsize = sizeof(TKmtVar);
1501 break;
1502 case PROTO_XM:
1503 vsize = sizeof(TXVar);
1504 break;
1505 case PROTO_YM:
1506 vsize = sizeof(TYVar);
1507 break;
1508 case PROTO_ZM:
1509 vsize = sizeof(TZVar);
1510 break;
1511 case PROTO_BP:
1512 vsize = sizeof(TBPVar);
1513 break;
1514 case PROTO_QV:
1515 vsize = sizeof(TQVVar);
1516 break;
1517 }
1518 ProtoVar = (PCHAR)malloc(vsize);
1519 if (ProtoVar==NULL)
1520 return FALSE;
1521
1522 switch (ProtoId) {
1523 case PROTO_KMT:
1524 ((PKmtVar)ProtoVar)->KmtMode = Mode;
1525 break;
1526 case PROTO_XM:
1527 ((PXVar)ProtoVar)->XMode = Mode;
1528 ((PXVar)ProtoVar)->XOpt = Opt1;
1529 ((PXVar)ProtoVar)->TextFlag = 1 - (Opt2 & 1);
1530 break;
1531 case PROTO_YM:
1532 ((PYVar)ProtoVar)->YMode = Mode;
1533 ((PYVar)ProtoVar)->YOpt = Opt1;
1534 break;
1535 case PROTO_ZM:
1536 ((PZVar)ProtoVar)->BinFlag = (Opt1 & 1) != 0;
1537 ((PZVar)ProtoVar)->ZMode = Mode;
1538 break;
1539 case PROTO_BP:
1540 ((PBPVar)ProtoVar)->BPMode = Mode;
1541 break;
1542 case PROTO_QV:
1543 ((PQVVar)ProtoVar)->QVMode = Mode;
1544 break;
1545 }
1546
1547 pd = new CProtoDlg();
1548 if (pd==NULL)
1549 {
1550 free(ProtoVar);
1551 ProtoVar = NULL;
1552 return FALSE;
1553 }
1554 pd->Create(fv,&ts);
1555
1556 Hpd=pd->GetSafeHwnd();
1557
1558 GetDlgItemText(Hpd, IDC_PROT_FILENAME, uimsg, sizeof(uimsg));
1559 get_lang_msg("DLG_PROT_FILENAME", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
1560 SetDlgItemText(Hpd, IDC_PROT_FILENAME, ts.UIMsg);
1561 GetDlgItemText(Hpd, IDC_PROT_PROT, uimsg, sizeof(uimsg));
1562 get_lang_msg("DLG_PROT_PROTO", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
1563 SetDlgItemText(Hpd, IDC_PROT_PROT, ts.UIMsg);
1564 GetDlgItemText(Hpd, IDC_PROT_PACKET, uimsg, sizeof(uimsg));
1565 get_lang_msg("DLG_PROT_PACKET", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
1566 SetDlgItemText(Hpd, IDC_PROT_PACKET, ts.UIMsg);
1567 GetDlgItemText(Hpd, IDC_PROT_TRANS, uimsg, sizeof(uimsg));
1568 get_lang_msg("DLG_PROT_TRANS", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
1569 SetDlgItemText(Hpd, IDC_PROT_TRANS, ts.UIMsg);
1570 GetDlgItemText(Hpd, IDC_PROT_ELAPSED, uimsg, sizeof(uimsg));
1571 get_lang_msg("DLG_PROT_ELAPSED", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
1572 SetDlgItemText(Hpd, IDC_PROT_ELAPSED, ts.UIMsg);
1573 GetDlgItemText(Hpd, IDCANCEL, uimsg, sizeof(uimsg));
1574 get_lang_msg("BTN_CANCEL", ts.UIMsg, sizeof(ts.UIMsg), uimsg, ts.UILanguageFile);
1575 SetDlgItemText(Hpd, IDCANCEL, ts.UIMsg);
1576
1577 (*ProtoInit)(ProtoId,FileVar,ProtoVar,&cv,&ts);
1578
1579 PtDlg = pd;
1580 return TRUE;
1581 }
1582
1583 extern "C" {
1584 void CloseProtoDlg()
1585 {
1586 if (PtDlg!=NULL)
1587 {
1588 PtDlg->DestroyWindow();
1589 PtDlg = NULL;
1590
1591 ::KillTimer(FileVar->HMainWin,IdProtoTimer);
1592 if ((ProtoId==PROTO_QV) &&
1593 (((PQVVar)ProtoVar)->QVMode==IdQVSend))
1594 CommTextOut(&cv,"\015",1);
1595 if (FileVar->LogFlag)
1596 _lclose(FileVar->LogFile);
1597 FileVar->LogFile = 0;
1598 if (ProtoVar!=NULL)
1599 {
1600 free(ProtoVar);
1601 ProtoVar = NULL;
1602 }
1603 }
1604 }
1605 }
1606
1607 BOOL ProtoStart()
1608 {
1609 if (cv.ProtoFlag)
1610 return FALSE;
1611 if (FSend)
1612 {
1613 FreeFileVar(&FileVar);
1614 return FALSE;
1615 }
1616
1617 if (! LoadTTFILE())
1618 return FALSE;
1619 NewFileVar(&FileVar);
1620
1621 if (FileVar==NULL)
1622 {
1623 FreeTTFILE();
1624 return FALSE;
1625 }
1626 cv.ProtoFlag = TRUE;
1627 return TRUE;
1628 }
1629
1630 void ProtoEnd()
1631 {
1632 if (! cv.ProtoFlag)
1633 return;
1634 cv.ProtoFlag = FALSE;
1635
1636 /* Enable transmit delay (serial port) */
1637 cv.DelayFlag = TRUE;
1638 TalkStatus = IdTalkKeyb;
1639
1640 CloseProtoDlg();
1641
1642 if ((FileVar!=NULL) && FileVar->Success)
1643 EndDdeCmnd(1);
1644 else
1645 EndDdeCmnd(0);
1646
1647 FreeTTFILE();
1648 FreeFileVar(&FileVar);
1649 }
1650
1651 extern "C" {
1652 int ProtoDlgParse()
1653 {
1654 int P;
1655
1656 P = ActiveWin;
1657 if (PtDlg==NULL)
1658 return P;
1659
1660 if ((*ProtoParse)(ProtoId,FileVar,ProtoVar,&cv))
1661 P = 0; /* continue */
1662 else {
1663 CommSend(&cv);
1664 ProtoEnd();
1665 }
1666 return P;
1667 }
1668 }
1669
1670 extern "C" {
1671 void ProtoDlgTimeOut()
1672 {
1673 if (PtDlg!=NULL)
1674 (*ProtoTimeOutProc)(ProtoId,FileVar,ProtoVar,&cv);
1675 }
1676 }
1677
1678 extern "C" {
1679 void ProtoDlgCancel()
1680 {
1681 if ((PtDlg!=NULL) &&
1682 (*ProtoCancel)(ProtoId,FileVar,ProtoVar,&cv))
1683 ProtoEnd();
1684 }
1685 }
1686
1687 extern "C" {
1688 void KermitStart(int mode)
1689 {
1690 WORD w;
1691
1692 if (! ProtoStart())
1693 return;
1694
1695 switch (mode) {
1696 case IdKmtSend:
1697 FileVar->OpId = OpKmtSend;
1698 if (strlen(&(FileVar->FullName[FileVar->DirLen]))==0)
1699 {
1700 if (! (*GetMultiFname)(FileVar,ts.FileDir,GMF_KERMIT,&w) ||
1701 (FileVar->NumFname==0))
1702 {
1703 ProtoEnd();
1704 return;
1705 }
1706 }
1707 else
1708 (*SetFileVar)(FileVar);
1709 break;
1710 case IdKmtReceive:
1711 FileVar->OpId = OpKmtRcv;
1712 break;
1713 case IdKmtGet:
1714 FileVar->OpId = OpKmtSend;
1715 if (strlen(&(FileVar->FullName[FileVar->DirLen]))==0)
1716 {
1717 if (! (*GetGetFname)(FileVar->HMainWin,FileVar) ||
1718 (strlen(FileVar->FullName)==0))
1719 {
1720 ProtoEnd();
1721 return;
1722 }
1723 }
1724 else
1725 (*SetFileVar)(FileVar);
1726 break;
1727 case IdKmtFinish:
1728 FileVar->OpId = OpKmtFin;
1729 break;
1730 default:
1731 ProtoEnd();
1732 return;
1733 }
1734 TalkStatus = IdTalkQuiet;
1735
1736 /* disable transmit delay (serial port) */
1737 cv.DelayFlag = FALSE;
1738
1739 if (! OpenProtoDlg(FileVar,PROTO_KMT,mode,0,0))
1740 ProtoEnd();
1741 }
1742 }
1743
1744 extern "C" {
1745 void XMODEMStart(int mode)
1746 {
1747 LONG Option;
1748 int tmp;
1749
1750 if (! ProtoStart())
1751 return;
1752
1753 if (mode==IdXReceive)
1754 FileVar->OpId = OpXRcv;
1755 else
1756 FileVar->OpId = OpXSend;
1757
1758 if (strlen(&(FileVar->FullName[FileVar->DirLen]))==0)
1759 {
1760 Option = MAKELONG(ts.XmodemBin,ts.XmodemOpt);
1761 if (! (*GetXFname)(FileVar->HMainWin,
1762 mode==IdXReceive,&Option,FileVar,ts.FileDir))
1763 {
1764 ProtoEnd();
1765 return;
1766 }
1767 tmp = HIWORD(Option);
1768 if (mode == IdXReceive) {
1769 if (IsXoptCRC(tmp)) {
1770 if (IsXopt1k(ts.XmodemOpt)) {
1771 ts.XmodemOpt = Xopt1kCRC;
1772 }
1773 else {
1774 ts.XmodemOpt = XoptCRC;
1775 }
1776 }
1777 else {
1778 if (IsXopt1k(ts.XmodemOpt)) {
1779 ts.XmodemOpt = Xopt1kCksum;
1780 }
1781 else {
1782 ts.XmodemOpt = XoptCheck;
1783 }
1784 }
1785 ts.XmodemBin = LOWORD(Option);
1786 }
1787 else {
1788 if (IsXopt1k(tmp)) {
1789 if (IsXoptCRC(ts.XmodemOpt)) {
1790 ts.XmodemOpt = Xopt1kCRC;
1791 }
1792 else {
1793 ts.XmodemOpt = Xopt1kCksum;
1794 }
1795 }
1796 else {
1797 if (IsXoptCRC(ts.XmodemOpt)) {
1798 ts.XmodemOpt = XoptCRC;
1799 }
1800 else {
1801 ts.XmodemOpt = XoptCheck;
1802 }
1803 }
1804 }
1805 }
1806 else
1807 (*SetFileVar)(FileVar);
1808
1809 if (mode==IdXReceive)
1810 FileVar->FileHandle = _lcreat(FileVar->FullName,0);
1811 else
1812 FileVar->FileHandle = _lopen(FileVar->FullName,OF_READ);
1813
1814 FileVar->FileOpen = FileVar->FileHandle>0;
1815 if (! FileVar->FileOpen)
1816 {
1817 ProtoEnd();
1818 return;
1819 }
1820 TalkStatus = IdTalkQuiet;
1821
1822 /* disable transmit delay (serial port) */
1823 cv.DelayFlag = FALSE;
1824
1825 if (! OpenProtoDlg(FileVar,PROTO_XM,mode,
1826 ts.XmodemOpt,ts.XmodemBin))
1827 ProtoEnd();
1828 }
1829 }
1830
1831 extern "C" {
1832 void YMODEMStart(int mode)
1833 {
1834 WORD Opt;
1835
1836 if (! ProtoStart())
1837 return;
1838
1839 if (mode==IdYSend)
1840 {
1841 // �t�@�C���]�������I�v�V������"Yopt1K"�����������B
1842 // TODO: "Yopt1K", "YoptG", "YoptSingle"�������������������AIDD_FOPT���g�������K�v�����B
1843 Opt = Yopt1K;
1844 FileVar->OpId = OpYSend;
1845 if (strlen(&(FileVar->FullName[FileVar->DirLen]))==0)
1846 {
1847 if (! (*GetMultiFname)(FileVar,ts.FileDir,GMF_Y,&Opt) ||
1848 (FileVar->NumFname==0))
1849 {
1850 ProtoEnd();
1851 return;
1852 }
1853 //ts.XmodemBin = Opt;
1854 }
1855 else
1856 (*SetFileVar)(FileVar);
1857 }
1858 else {
1859 FileVar->OpId = OpYRcv;
1860 // �t�@�C���]�������I�v�V������"Yopt1K"�����������B
1861 Opt = Yopt1K;
1862 (*SetFileVar)(FileVar);
1863 }
1864
1865 TalkStatus = IdTalkQuiet;
1866
1867 /* disable transmit delay (serial port) */
1868 cv.DelayFlag = FALSE;
1869
1870 if (! OpenProtoDlg(FileVar,PROTO_YM,mode,Opt,0))
1871 ProtoEnd();
1872 }
1873 }
1874
1875 extern "C" {
1876 void ZMODEMStart(int mode)
1877 {
1878 WORD Opt;
1879
1880 if (! ProtoStart())
1881 return;
1882
1883 if (mode == IdZSend || mode == IdZAutoS)
1884 {
1885 Opt = ts.XmodemBin;
1886 FileVar->OpId = OpZSend;
1887 if (strlen(&(FileVar->FullName[FileVar->DirLen]))==0)
1888 {
1889 if (! (*GetMultiFname)(FileVar,ts.FileDir,GMF_Z,&Opt) ||
1890 (FileVar->NumFname==0))
1891 {
1892 if (mode == IdZAutoS) {
1893 CommRawOut(&cv, "\030\030\030\030\030\030\030\030\b\b\b\b\b\b\b\b\b\b", 18);
1894 }
1895 ProtoEnd();
1896 return;
1897 }
1898 ts.XmodemBin = Opt;
1899 }
1900 else
1901 (*SetFileVar)(FileVar);
1902 }
1903 else /* IdZReceive or IdZAutoR */
1904 FileVar->OpId = OpZRcv;
1905
1906 TalkStatus = IdTalkQuiet;
1907
1908 /* disable transmit delay (serial port) */
1909 cv.DelayFlag = FALSE;
1910
1911 if (! OpenProtoDlg(FileVar,PROTO_ZM,mode,Opt,0))
1912 ProtoEnd();
1913 }
1914 }
1915
1916 extern "C" {
1917 void BPStart(int mode)
1918 {
1919 LONG Option = 0;
1920
1921 if (! ProtoStart())
1922 return;
1923 if (mode==IdBPSend)
1924 {
1925 FileVar->OpId = OpBPSend;
1926 if (strlen(&(FileVar->FullName[FileVar->DirLen]))==0)
1927 {
1928 FileVar->FullName[0] = 0;
1929 if (! (*GetTransFname)(FileVar, ts.FileDir, GTF_BP, &Option))
1930 {
1931 ProtoEnd();
1932 return;
1933 }
1934 }
1935 else
1936 (*SetFileVar)(FileVar);
1937 }
1938 else /* IdBPReceive or IdBPAuto */
1939 FileVar->OpId = OpBPRcv;
1940
1941 TalkStatus = IdTalkQuiet;
1942
1943 /* disable transmit delay (serial port) */
1944 cv.DelayFlag = FALSE;
1945
1946 if (! OpenProtoDlg(FileVar,PROTO_BP,mode,0,0))
1947 ProtoEnd();
1948 }
1949 }
1950
1951 extern "C" {
1952 void QVStart(int mode)
1953 {
1954 WORD W;
1955
1956 if (! ProtoStart())
1957 return;
1958
1959 if (mode==IdQVSend)
1960 {
1961 FileVar->OpId = OpQVSend;
1962 if (strlen(&(FileVar->FullName[FileVar->DirLen]))==0)
1963 {
1964 if (! (*GetMultiFname)(FileVar,ts.FileDir,GMF_QV, &W) ||
1965 (FileVar->NumFname==0))
1966 {
1967 ProtoEnd();
1968 return;
1969 }
1970 }
1971 else
1972 (*SetFileVar)(FileVar);
1973 }
1974 else
1975 FileVar->OpId = OpQVRcv;
1976
1977 TalkStatus = IdTalkQuiet;
1978
1979 /* disable transmit delay (serial port) */
1980 cv.DelayFlag = FALSE;
1981
1982 if (! OpenProtoDlg(FileVar,PROTO_QV,mode,0,0))
1983 ProtoEnd();
1984 }
1985 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26