OSDN Git Service

d037e02cd86a5e1cd71026235767676f81a22ca1
[winbottle/winbottle.git] / bottleclient / MainForm.pas
1 unit MainForm;
2
3 {
4 \83A\83v\83\8a\83P\81[\83V\83\87\83\93\82Ì\83\81\83C\83\93\83t\83H\81[\83\80\81B
5 \91\97\90M\81E\8eó\90M\81E\83{\83g\83\8b\94z\91\97\8aÖ\8cW\82Ì\82¢\82ë\82¢\82ë\82È\8f\88\97\9d\82ð\8ds\82¤\81B
6 }
7
8 interface
9
10 uses
11   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
12   Menus, StdCtrls, ComCtrls, BRegExp, BottleDef, BottleSstp, DirectSstp,
13 //  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdSLPP20,
14   SsParser, ImgList, AppEvnts, TaskTray, StdActns,
15   ActnList, MPlayer, MenuBar, ToolWin,
16   IniFiles, ExtCtrls, ShellAPI, Contnrs,
17   ConstEditor, Buttons, Clipbrd, HeadValue, Logs, MultipleChoiceEditor,
18 //  IdException, HttpThread, IdHTTP, LogDownload,
19   ScriptConsts, DateUtils, BottleChainRule, BottleChainEvent,
20   SakuraSeekerInstance, HEditor, HTSearch, heClasses, heFountain,
21   SakuraScriptFountain, SppList, SurfacePreview, XDOM_2_3_J3, SsPlayTime,
22   RegexUtils, StrReplace, StrReplaceDialog, ReplacePresetEditor;
23
24 type
25   TSurfacePreviewType = (spHint, spEditor);
26
27   TfrmSender = class(TForm)
28     MainMenu: TMainMenu;
29     mnFile: TMenuItem;
30     mnExit: TMenuItem;
31     mnRegister: TMenuItem;
32     mnStart: TMenuItem;
33     mnScript: TMenuItem;
34     StatusBar: TStatusBar;
35     mnHelp: TMenuItem;
36     mnAbout: TMenuItem;
37     mnEditConst: TMenuItem;
38     ActionList: TActionList;
39     mnPopUp: TPopupMenu;
40     mnPopPaste: TMenuItem;
41     mnPopCut: TMenuItem;
42     mnPopCopy: TMenuItem;
43     mnPopSelectAll: TMenuItem;
44     N6: TMenuItem;
45     mnPopConst: TMenuItem;
46     mnEdit: TMenuItem;
47     mnPaste: TMenuItem;
48     mnCopy: TMenuItem;
49     mnCut: TMenuItem;
50     mnSelectAll: TMenuItem;
51     TaskTray: TTaskTray;
52     ApplicationEvents: TApplicationEvents;
53     mnPopUpTaskTray: TPopupMenu;
54     mnTaskStart: TMenuItem;
55     mnTaskEnd: TMenuItem;
56     mnTaskRestore: TMenuItem;
57     mnTaskNewMessage: TMenuItem;
58     actStart: TAction;
59     actStop: TAction;
60     N8: TMenuItem;
61     mnTaskExit: TMenuItem;
62     actSend: TAction;
63     actConfirm: TAction;
64     actClear: TAction;
65     mnSend: TMenuItem;
66     mnConfirm: TMenuItem;
67     mnClear: TMenuItem;
68     imgIcon: TImageList;
69     mnPopupConst: TPopupMenu;
70     actEditConst: TAction;
71     mnView: TMenuItem;
72     mnShowToolBar: TMenuItem;
73     mnShowConstBar: TMenuItem;
74     ConstBarMenu: TMainMenu;
75     ToolBar: TToolBar;
76     tbtnClear: TToolButton;
77     tbtnConfirm: TToolButton;
78     tbtnSend: TToolButton;
79     tbtnSeparator: TToolButton;
80     tbtnStart: TToolButton;
81     tbtnSeparator2: TToolButton;
82     tbtnInsertConst: TToolButton;
83     ConstMenuBar: TMenuBar;
84     mnGoToHP: TMenuItem;
85     LabelTimer: TTimer;
86     mnCopyAll: TMenuItem;
87     actCopyAll: TAction;
88     actCopyAllNoReturn: TAction;
89     mnCopyAllNoReturn: TMenuItem;
90     mnPopCopyAll: TMenuItem;
91     mnPopCopyAllNoReturn: TMenuItem;
92     actSetting: TAction;
93     tbtnSetting: TToolButton;
94     mnStayOnTop: TMenuItem;
95     mnSetting: TMenuItem;
96     actExitClient: TAction;
97     SsParser: TSsParser;
98     tbtnEditConst: TToolButton;
99     actClearBottles: TAction;
100     mnClearBottles: TMenuItem;
101     MediaPlayer: TMediaPlayer;
102     mnGetNewId: TMenuItem;
103     actNextChannel: TAction;
104     actPrevChannel: TAction;
105     N2: TMenuItem;
106     mnNextChannel: TMenuItem;
107     mnPrevChannel: TMenuItem;
108     actShowLog: TAction;
109     N3: TMenuItem;
110     tbtnShowLog: TToolButton;
111     tbtnSleep: TToolButton;
112     actSleep: TAction;
113     N1: TMenuItem;
114     mnSleep: TMenuItem;
115     mnTaskSleep: TMenuItem;
116     pnlEditor: TPanel;
117     tabChannel: TTabControl;
118     pnlPanel: TPanel;
119     lblMessage: TLabel;
120     cbxTargetGhost: TComboBox;
121     actVoteMessage: TAction;
122     mnPopUpChannelTab: TPopupMenu;
123     mnLeaveThisChannel: TMenuItem;
124     N4: TMenuItem;
125     mnGotoVote: TMenuItem;
126     mnGoToHelp: TMenuItem;
127     btnSend: TButton;
128     btnConfirm: TButton;
129     btnClear: TButton;
130     mnExitAllChannels: TMenuItem;
131     actAgreeMessage: TAction;
132     btnIfGhost: TButton;
133     actPrevGhost: TAction;
134     actNextGhost: TAction;
135     mnPrevGhost: TMenuItem;
136     mnNextGhost: TMenuItem;
137     actResetGhost: TAction;
138     mnResetGhost: TMenuItem;
139     DirectSstp: TDirectSstp;
140     actDownloadLog: TAction;
141     actFMOExplorer: TAction;
142     tbtnFMOExplorer: TToolButton;
143     mnFMOExplorer: TMenuItem;
144     mnLine: TMenuItem;
145     actInsertCue: TAction;
146     SakuraScriptFountain: TSakuraScriptFountain;
147     memScript: TEditor;
148     actCopy: TAction;
149     actPaste: TAction;
150     actCut: TAction;
151     actSelectAll: TAction;
152     actRecallScriptBuffer: TAction;
153     N5: TMenuItem;
154     mnRecallScriptBuffer: TMenuItem;
155     tbtnEditorPreview: TToolButton;
156     actEditorPreview: TAction;
157     mnEditorPreview: TMenuItem;
158     actResetPlugins: TAction;
159     N7: TMenuItem;
160     mnResetPlugins: TMenuItem;
161     actReplace: TAction;
162     N10: TMenuItem;
163     mnReplace: TMenuItem;
164     actSendToEditor: TAction;
165     actSendToLogWindow: TAction;
166     mnSendLogWindow: TMenuItem;
167     actDeleteLogItem: TAction;
168     actAbout: TAction;
169     actEditCopy: TEditCopy;
170     tbtnSendToLogWindow: TToolButton;
171     SsPlayTime: TSsPlayTime;
172     actUndo: TAction;
173     actRedo: TAction;
174     mnUndo: TMenuItem;
175     mnRedo: TMenuItem;
176     N9: TMenuItem;
177     ScriptBackUp: TTimer;
178     mnPresetReplaceRoot: TMenuItem;
179     OpenDialog: TOpenDialog;
180     mnFileOpen: TMenuItem;
181     actFileOpen: TAction;
182     actFileSaveAs: TAction;
183     mnSaveAs: TMenuItem;
184     SaveDialog: TSaveDialog;
185     N11: TMenuItem;
186     mnSave: TMenuItem;
187     actFileSave: TAction;
188     procedure actConfirmExecute(Sender: TObject);
189     procedure FormCreate(Sender: TObject);
190     procedure FormDestroy(Sender: TObject);
191     procedure actSendExecute(Sender: TObject);
192 //    procedure HTTPSuccess(Sender: TObject);
193 //    procedure HTTPFailure(Sender: TObject);
194     procedure actStartClick(Sender: TObject);
195     procedure actStopExecute(Sender: TObject);
196     procedure FormShow(Sender: TObject);
197     procedure actAboutClick(Sender: TObject);
198     procedure actExitClientExecute(Sender: TObject);
199     procedure actClearExecute(Sender: TObject);
200     procedure memScriptChange(Sender: TObject);
201     procedure mnStayOnTopClick(Sender: TObject);
202     procedure actEditConstExecute(Sender: TObject);
203     procedure mnTaskBarClick(Sender: TObject);
204     procedure FormClose(Sender: TObject; var Action: TCloseAction);
205     procedure ApplicationEventsMinimize(Sender: TObject);
206     procedure ApplicationEventsRestore(Sender: TObject);
207     procedure mnTaskRestoreClick(Sender: TObject);
208     procedure TaskTrayDblClick(Seft: TObject; Button: TMouseButton);
209     procedure FormActivate(Sender: TObject);
210     procedure mnTaskNewMessageClick(Sender: TObject);
211     procedure ApplicationEventsHint(Sender: TObject);
212     procedure memScriptKeyDown(Sender: TObject; var Key: Word;
213       Shift: TShiftState);
214     procedure mnShowToolBarClick(Sender: TObject);
215     procedure mnShowConstBarClick(Sender: TObject);
216     procedure mnGoToHPClick(Sender: TObject);
217     procedure LabelTimerTimer(Sender: TObject);
218     procedure actCopyAllExecute(Sender: TObject);
219     procedure actCopyAllNoReturnExecute(Sender: TObject);
220 //    procedure Slpp20SlppEvent(Sender: TObject; EventType: TIdSlppEventType;
221 //      const Param: String);
222     procedure actSettingExecute(Sender: TObject);
223     procedure memScriptKeyPress(Sender: TObject; var Key: Char);
224 //    procedure Slpp20Disconnect(Sender: TObject);
225     procedure actClearBottlesExecute(Sender: TObject);
226     procedure SakuraSeekerDetectResultChanged(Sender: TObject);
227     procedure mnGetNewIdClick(Sender: TObject);
228     procedure tabChannelChange(Sender: TObject);
229     procedure actPrevChannelExecute(Sender: TObject);
230     procedure actNextChannelExecute(Sender: TObject);
231     procedure cbxTargetGhostDropDown(Sender: TObject);
232     procedure actShowLogExecute(Sender: TObject);
233     procedure actSleepExecute(Sender: TObject);
234     procedure actVoteMessageExecute(Sender: TObject);
235     procedure tabChannelContextPopup(Sender: TObject; MousePos: TPoint;
236       var Handled: Boolean);
237     procedure mnLeaveThisChannelClick(Sender: TObject);
238     procedure mnGotoVoteClick(Sender: TObject);
239     procedure tabChannelMouseMove(Sender: TObject; Shift: TShiftState; X,
240       Y: Integer);
241     procedure mnGoToHelpClick(Sender: TObject);
242     procedure tabChannelMouseDown(Sender: TObject; Button: TMouseButton;
243       Shift: TShiftState; X, Y: Integer);
244     procedure tabChannelDragOver(Sender, Source: TObject; X, Y: Integer;
245       State: TDragState; var Accept: Boolean);
246     procedure tabChannelDragDrop(Sender, Source: TObject; X, Y: Integer);
247     procedure tabChannelEndDrag(Sender, Target: TObject; X, Y: Integer);
248     procedure cbxTargetGhostDrawItem(Control: TWinControl; Index: Integer;
249       Rect: TRect; State: TOwnerDrawState);
250     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
251     procedure actAgreeMessageExecute(Sender: TObject);
252     procedure actPrevGhostExecute(Sender: TObject);
253     procedure actNextGhostExecute(Sender: TObject);
254     procedure actResetGhostExecute(Sender: TObject);
255 //    procedure timDisconnectCheckTimerTimer(Sender: TObject);
256     procedure actDownloadLogExecute(Sender: TObject);
257     procedure cbxTargetGhostChange(Sender: TObject);
258     procedure actFMOExplorerExecute(Sender: TObject);
259     // \8eÀ\8dÛ\82Ì\8f\88\97\9d\82ÍLogInsertCue\82Ö\88Ú\93®
260     procedure actInsertCueExecute(Sender: TObject);
261     procedure FormResize(Sender: TObject);
262     procedure actCopyExecute(Sender: TObject);
263     procedure actPasteExecute(Sender: TObject);
264     procedure actCutExecute(Sender: TObject);
265     procedure actSelectAllExecute(Sender: TObject);
266     procedure memScriptMouseMove(Sender: TObject; Shift: TShiftState; X,
267       Y: Integer);
268     procedure actRecallScriptBufferExecute(Sender: TObject);
269     procedure actEditorPreviewExecute(Sender: TObject);
270     procedure actResetPluginsExecute(Sender: TObject);
271 //    procedure IdSLPP20Connect(Sender: TObject);
272     procedure actReplaceExecute(Sender: TObject);
273     procedure actSendToEditorExecute(Sender: TObject);
274     procedure actSendToLogWindowExecute(Sender: TObject);
275     procedure memScriptDragOver(Sender, Source: TObject; X, Y: Integer;
276       State: TDragState; var Accept: Boolean);
277     procedure memScriptDragDrop(Sender, Source: TObject; X, Y: Integer);
278     procedure actDeleteLogItemExecute(Sender: TObject);
279     procedure memScriptSelectionChange(Sender: TObject; Selected: Boolean);
280     procedure actUndoExecute(Sender: TObject);
281     procedure actRedoExecute(Sender: TObject);
282 //    procedure IdSLPP20ConnectFailed(Sender: TObject);
283     procedure ScriptBackUpTimer(Sender: TObject);
284     procedure actFileOpenExecute(Sender: TObject);
285     procedure actFileSaveAsExecute(Sender: TObject);
286     procedure actFileSaveExecute(Sender: TObject);
287   private
288     FSleeping: boolean;  // \94z\91\97\83X\83\8a\81[\83v\92\86\82©\82Ç\82¤\82©
289     FStatusText: String;
290 //    FConnecting: boolean;
291 //    FAdded: boolean;
292     FBooted: boolean; //\8f\89\89ñ\8bN\93®\92Ê\90M\97p
293     FEndSession: Boolean; // Windows\8fI\97¹\82ð\8c\9f\92m\82µ\82Ätrue\82É\82È\82é
294     FOriginalCaption: String;
295 //    FAutoAddAfterGetChannel: boolean; //\83`\83\83\83\93\83l\83\8b\8eæ\93¾\8cã\82É\83_\83C\83A\83\8d\83O\82È\82µ\82É
296                                       //\83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82·\82é\82©\82Ç\82¤\82©
297     FConstDir: String;
298     FSppDir: String;
299     //
300 //    FNowChannel: String; //\8c»\8dÝ\91I\91ð\82³\82ê\82Ä\82¢\82é\83`\83\83\83\93\83l\83\8b
301 //    JoinChannelsBackup: TStringList; //\88ê\8e\9e\8eg\97p
302     //
303 //    FScriptModified: boolean; // \83X\83N\83\8a\83v\83g\82ª\95Ï\8dX\82³\82ê\82Ä\82¢\82é\82©\82Ç\82¤\82©\81B
304 //                              // \83\8d\81[\83J\83\8b\8am\94F\8b­\90§\97p\83t\83\89\83O\81BTRichEdit.Modified\82Í
305 //                              //\95Ê\82Ì\97p\93r\82Å\8eg\82Á\82Ä\82¢\82é\82Ì\82Å\8eg\82¦\82È\82¢
306     //
307     FScriptBackModified: boolean; //\83X\83N\83\8a\83v\83g\8e©\93®\95Û\91\83t\83\89\83O
308     FFileModified: boolean;       //\83t\83@\83C\83\8b\93à\97e\82ª\95Ï\8dX\82³\82ê\82Ä\82¢\82é\82©\81B
309     FFileName: string;            //\90V\8bK\82©\8aù\91\83t\83@\83C\83\8b\82Ì\94»\92f\81A\82Ü\82½\82Í\8aù\91\83t\83@\83C\83\8b\82Ì\8fê\8f\8a
310     //
311 //    FDragTabIndex: integer; //\83^\83u\83h\83\89\83b\83O\83h\83\8d\83b\83v\8aÖ\98A
312 //    FDragTabDest: integer;  //\83h\83\8d\83b\83v\82·\82é\88Ê\92u(\82·\82®\89E\82É\82­\82é\83^\83u\82Ì\83C\83\93\83f\83b\83N\83X)
313     //
314     FBottleSstp: TBottleSstp; // \8dÄ\91\97\83v\83\8d\83O\83\89\83\80
315     //
316 //    FHttp: THTTPDownloadThread; //HTTP\83_\83E\83\93\83\8d\81[\83h\83X\83\8c\83b\83h(\83C\83\93\83X\83^\83\93\83X\82Í1\8cÂ\82Ì\82Ý)
317 //    FBeginConnectFailCount: integer; //\89½\93x\82à\90Ú\91±\8e¸\94s\82µ\82½\82ç\83\8a\83g\83\89\83C\92\86\8e~
318     //
319     FVisiblePreviewGhost: String;
320     FVisiblePreviewSurface: integer; //\83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\82Å\8c©\82¦\82Ä\82¢\82é\82à\82Ì
321     FVisibleMenuItem: TMenuItem; //\83N\83\8a\83b\83N\82³\82ê\82½\83\81\83j\83\85\81[\83A\83C\83e\83\80\81B
322                                  //\83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\82ª\83\81\83j\83\85\81[\82Ì\89º\82É
323                                  //\89B\82ê\82È\82¢\82æ\82¤\82É\95\\8e¦\82³\82ê\82Ä\82¢\82é\82à\82Ì\82ð\8bL\89¯\82µ\82Ä\82¨\82­
324     //
325     FTargetGhostExpand: boolean; //\83S\81[\83X\83g\91I\91ð\83{\83b\83N\83X\82ª\81A
326                                  //\88ê\8e\9e\93I\82É\91S\95\94\95\\8e¦\82³\82ê\82Ä\82¢\82é\82©\82Ç\82¤\82©\82Ì\83t\83\89\83O
327     //
328     FScriptBuffer: TObjectList;  //\83X\83N\83\8a\83v\83g\83N\83\8a\83A\83o\83b\83t\83@
329     //
330     FWM_TaskBarCreated: WORD; // \83^\83X\83N\83o\81[\93o\98^\97p\83E\83B\83\93\83h\83E\83\81\83b\83Z\81[\83WID
331     //
332 //    procedure SetStatusText(const Value: String);
333     procedure SetSleeping(const Value: boolean);
334     procedure YenETrans;
335 //    procedure SetConnecting(const Value: boolean);
336 //    procedure SetAdded(const Value: boolean);
337     procedure mnConstClick(Sender: TObject);
338     procedure mnConstGroupClick(Sender: TObject);
339     procedure mnPresetReplaceClick(Sender: TObject);
340 //    property Added: boolean read FAdded write SetAdded;
341     property Sleeping: boolean read FSleeping write SetSleeping;
342 //    property StatusText: String read FStatusText write SetStatusText;
343     function GetScriptText: String;
344     procedure ChangeTaskIcon;
345     procedure ShowHintLabel(const Mes: String; Col: TColor = clBlue);
346     procedure UpdateLayout;
347 //    procedure DispatchBottle(EventType: TIdSlppEventType; Dat: THeadValue);
348     procedure DispatchBottle(Dat: THeadValue; LogTime: TDateTime;
349       Vote, Agree: integer);
350     //\83`\83\83\83\93\83l\83\8b\8aÖ\8cW
351 //    procedure UpdateChannelInfo(Dat: THeadValue);
352 //    procedure UpdateJoinChannelList(Dat: THeadValue);
353     procedure UpdateJoinChannelList;
354     procedure UpdateChannelList;
355 //    procedure NoLuidError;
356     procedure UpdateIfGhostBox;
357     function BuildMenuConditionCheck(const IfGhost, Ghost: String): boolean;
358     procedure BuildMenu(Root: TMenuItem; Simple: boolean);
359     procedure BuildReplaceMenu(Root: TMenuItem);
360     procedure PlaySound(const FileName: String);
361     //TBottleSstp\8aÖ\8cW\83C\83x\83\93\83g\83n\83\93\83h\83\89
362     procedure BottleSstpResendCountChange(Sender: TObject);
363     procedure BottleSstpResendTrying(Sender: TObject; MID: String);
364     procedure BottleSstpResendEnd(Sender: TObject; MID: String);
365     function IsSurfaceTag(const Script: String; var ID: integer): boolean;
366     procedure DoSurfacePreview(Surface: integer; const Kind:
367       TSurfacePreviewType);
368     function GetSurfacePreviewPositionHint(w, h: integer): TPoint;
369     function GetSurfacePreviewPositionScriptPoint(w, h: integer): TPoint;
370     procedure EditorPreview;
371     // \83^\83O\82Ì\95\8e\9a\97ñ\82ð\95Ï\8a·\82·\82é
372     function TagReplace(Script: String;
373       Before, After: array of String): String; overload;
374     function TagReplace(Script: String;
375       Before, After: TStrings): String; overload;
376     // \83T\81[\83t\83B\83X\82ð\95Ï\8a·\82·\82é
377     function ReplaceSurface(Script: String; Params: TCollection): String;
378     procedure ClearEditor;
379     procedure CopyFromLogToEditor(Log: TLogItem);
380     //
381     procedure AppendTextLog(const FileName, Line: String; FAppend: boolean);
382     procedure AppendXMLLog(const FileName: String; Args: THeadValue);
383     //\8e©\93®\95Û\91\90Ý\92è
384     procedure SetScriptAutoBackUp;
385     //\92P\91Ì\83t\83@\83C\83\8b\93ü\8fo\97Í\8aÖ\8cW
386     procedure PerformFileOpen(const AFileName: string);
387     procedure PerformFileSave(const AFileName: string);
388     procedure SetFileName(const FileName: String; const Value: boolean);
389     function CheckFileModified(Sender: TObject): integer;
390     function FileSave(Sender: TObject): integer;
391     function FileSaveAs(Sender: TObject): integer;
392     procedure EditerStatusChange;
393     procedure SetFileModified(const Value: boolean);
394     function CheckFileExt(const AFileName: string): boolean;
395
396   protected
397     procedure WndProc(var Message: TMessage); override;
398     procedure WMQueryEndSession(var msg: TWMQueryEndSession);
399       message WM_QUERYENDSESSION;
400 {$IFDEF PASS}
401     procedure CopyDataMessage(var WMCopyData: TWMCopyData); message WM_COPYDATA;
402 {$ENDIF}
403   public
404     function DoTrans(var Script: String;
405       Options: TScriptTransOptions): String; overload;
406     function DoTrans(var Script: String;
407       Options: TScriptTransOptions; out FoundURL: boolean): String; overload;
408     function ScriptTransForSSTP(const Script: String;
409       out Error: String): String; overload;
410 //    procedure BeginConnect;
411 //    procedure RetryBeginConnect;
412 //    procedure EndConnect;
413     procedure ConstructMenu(Simple: boolean);
414 //    property Connecting: boolean read FConnecting write SetConnecting;
415     property BottleSstp: TBottleSstp read FBottleSstp;
416     function GhostNameToSetName(const Ghost: String): String;
417 //    procedure PostCommand(const Command: array of String); overload;
418 //    procedure PostCommand(Command: TStrings); overload;
419 //    procedure PostSetChannel(Channels: TStrings);
420     procedure SaveChainRuleList;
421     //DispatchBottle()\82Ö\83o\83C\83p\83X
422     procedure BottleCnv(Log: TLogItem);
423     //\83u\83\89\83E\83U\94»\92f\82ÆURL\88ø\93n\82µ
424     procedure OpenBrowser(const Url: string);
425     //Log\83E\83B\83\93\83h\83E\82©\82ç\8fð\8c\8f\95t\82Å\8cÄ\82Î\82ê\82é
426     procedure LogInsertCue(TestAction: boolean);
427   end;
428
429
430 var
431   frmSender: TfrmSender;
432
433 const
434   PanelConnecting = 0;  //\81u\90Ú\91±\92\86\81v\95\\8e¦\97p
435   PanelBytes      = 1;  //\81\9b\81\9b\83o\83C\83g
436   PanelCount      = 2;  //Local Proxy\81A\8c»\8dÝ\81\9b\8c\8f\91Ò\82¿
437   PanelMembers    = 3;  //\81\9b\81\9b\90l
438   PanelStatus     = 4;  //SSTP Bottle\83T\81[\83o\82É\93o\98^\82³\82ê\82Ä\82¢\82Ü\82·\81c\82È\82Ç
439
440   IconConnected    = 17;
441   IconDisconnected = 47;  //\8b\8c18  \8e¸\94s\8fó\91Ô\82ð\8fí\82É\8eg\97p
442   IconSleep        = 19;
443   IconSleepDisconnected = 47; //\8b\8c20
444
445   WarningColor = clRed;
446
447   SendButtonLongHint = 'Bottle\82Ì\91\97\90M';
448   NewFileTitle       = '\96¼\8fÌ\96¢\92è';     // \90V\8bK\83^\83C\83g\83\8b
449   AutoSaveFile       = 'Script.bak';   // FileCheck\8ew\92è\82Ì\8ag\92£\8eq\82ð\8eg\82¤
450
451 function Token(const Str: String; const Delimiter: char;
452   const Index: integer): String;
453
454 function StringReplaceEx(const Before: String; List: THeadValue): String;
455
456 implementation
457
458 uses SettingForm, LogForm,
459   MessageBox, FMOExplorer, EditorTalkShow;
460 //SendConfirm, ChannelListForm,
461
462 {$R *.DFM}
463
464 // \92P\8f\83\82É\83o\83C\83g\92P\88Ê\82Å\95\8e\9a\97ñ\82ð\8c©\82Ä\82¢\82«\95ª\89ð\82·\82é\83\86\81[\83e\83B\83\8a\83e\83B\8aÖ\90\94
465 function Token(const Str: String; const Delimiter: char;
466   const Index: integer): String;
467 var i, c, len: integer;
468 begin
469   i := 1;
470   c := 0;
471   len := length(Str);
472   Result := '';
473   while i <= len do begin
474     if (Str[i] = Delimiter) and (StrByteType(PChar(Str), i) <> mbTrailByte) then begin
475       Inc(c);
476       if c > Index then Break;
477     end else if c = Index then Result := Result + Str[i];
478     Inc(i);
479   end;
480 end;
481
482 // \95\8e\9a\97ñ\82ð\92u\82«\8a·\82¦\82é\83\86\81[\83e\83B\83\8a\83e\83B\8aÖ\90\94
483 function StringReplaceEx(const Before: String; List: THeadValue): String;
484 var
485   i, MinPos, MinKey, p: integer;
486   Work: String;
487 begin
488   Work := Before;
489   Result := '';
490   MinKey := -1;
491   while Work <> '' do
492   begin
493     MinPos := -1;
494     for i := 0 to List.Count-1 do
495     begin
496       p := Pos(List.KeyAt[i], Work);
497       if (p > 0) and ((p < MinPos) or (MinPos < 0)) then
498       begin
499         MinPos := p;
500         MinKey := i;
501       end;
502     end;
503     if MinPos < 0 then
504     begin
505       Result := Result + Work;
506       Break;
507     end else
508     begin
509       Result := Result + Copy(Work, 1, MinPos-1) + List.ValueAt[MinKey];
510       Delete(Work, 1, (MinPos - 1) + Length(List.KeyAt[MinKey]));
511     end;
512   end;
513 end;
514
515 {TfrmSender}
516
517 procedure TfrmSender.actConfirmExecute(Sender: TObject);
518 var
519   AScript, Err, AGhost: String;
520   Item: TLogItem;
521   Choice: integer;
522 begin
523   // Partial Confirmation
524   if memScript.SelText <> '' then
525   begin
526     Choice := 0;
527     if not Pref.AutoPartialConfirm then
528       if not MultipleChoiceEdit('\8am\94F', ['\91I\91ð\95\94\95ª\82Ì\82Ý', '\83X\83N\83\8a\83v\83g\91S\91Ì'], Choice) then
529         Exit;
530     if Choice = 0 then
531     begin
532       AScript := memScript.SelText;
533       AScript := StringReplace(Pref.PartialConfirmFormat, '|', AScript, []);
534     end else
535       AScript := GetScriptText;
536   end else
537     AScript := GetScriptText;
538   AScript := StringReplace(AScript, #13#10, '', [rfReplaceAll]);
539
540   if Length(AScript) = 0 then Exit;
541   YenETrans;
542   AScript := ScriptTransForSSTP(AScript, Err);
543   if Err <> '' then
544   begin
545     ShowMessage(Err);
546     Exit;
547   end;
548
549   if cbxTargetGhost.ItemIndex > 0 then
550     AGhost := cbxTargetGhost.Text
551\95K\82¸\8ew\92è\82³\82ê\82é\82Í\82¸
552   else if FNowChannel <> '' then
553     AGhost := ChannelList.Channel[FNowChannel].Ghost
554 }
555   else
556     AGhost := '';
557
558   if Pref.IgnoreTimeCritical then
559     AScript := TagReplace(AScript, ['\t'], ['']);
560
561   Item := TLogItem.Create;
562   try
563     with Item do
564     begin
565       LogType := ltBottle;
566       Script := AScript;
567       Channel := '\81y\8am\94F\81z';
568       Ghost := AGhost;
569     end;
570     BottleSstp.Unshift(Item);
571   except
572     Item.Free;
573   end;
574
575 //  FScriptModified := false;
576 end;
577
578 procedure TfrmSender.FormCreate(Sender: TObject);
579 var Str: TStringList;
580 begin
581   FScriptBuffer := TObjectList.Create(true);
582
583   SakuraSeeker.OnDetectResultChanged := SakuraSeekerDetectResultChanged;
584   FConstDir := ExtractFileDir(Application.ExeName)+'\consts';
585   ScriptConstList.LoadFromDir(FConstDir);
586   FSppDir := ExtractFileDir(Application.ExeName)+'\spp';
587   Spps.LoadFromDirectory(FSppDir);
588   ConstructMenu(false);
589   BuildReplaceMenu(mnPresetReplaceRoot);
590
591   Str := TStringList.Create;
592   try
593     try
594       Str.LoadFromFile(ExtractFilePath(Application.ExeName)+'rule.txt');
595       BottleChainRuleList := StringToComponent(Str.Text) as TBottleChainRuleList;
596     except
597       try
598         Str.LoadFromFile(ExtractFilePath(Application.ExeName)+'defrule.txt');
599         BottleChainRuleList := StringToComponent(Str.Text) as TBottleChainRuleList;
600       except
601         ShowMessage('defrule.txt\93Ç\82Ý\8d\9e\82Ý\92\86\82É\92v\96½\93I\83G\83\89\81[\82ª\94­\90\82µ\82Ü\82µ\82½\81Bdefrule.txt\82ð\8dÄ\83C\83\93\83X\83g\81[\83\8b\82µ\82Ä\82­\82¾\82³\82¢\81B');
602         Application.Terminate;
603         Application.ProcessMessages;
604         Exit;
605       end;
606     end;
607   finally
608     Str.Free;
609   end;
610
611   FOriginalCaption := Self.Caption;
612
613   UpdateLayout;
614   mnShowToolBar.Checked := Pref.ShowToolBar;
615   mnShowConstBar.Checked := Pref.ShowConstBar;
616   if Pref.StayOnTop then begin
617     FormStyle := fsStayOnTop;
618     mnStayOnTop.Checked := true;
619   end else begin
620     FormStyle := fsNormal;
621     mnStayOnTop.Checked := false;
622   end;
623
624   // URL\83W\83\83\83\93\83v\90æ\82ð\83q\83\93\83g\95\8e\9a\97ñ\82Æ\82µ\82Ä\90Ý\92è
625   mnGoToHP.Hint := Pref.HomePage;
626   mnGotoVote.Hint := Pref.VotePage;
627   mnGotoHelp.Hint := Pref.HelpPage;
628
629   mnGetNewId.Enabled := (Pref.LUID = '');
630
631   // \82³\82­\82ç\83X\83N\83\8a\83v\83g\89ð\90Í\83p\83^\81[\83\93\82ð\93Ç\82Ý\8d\9e\82Ý
632   try
633     SsParser.TagPattern.LoadFromFile(ExtractFilePath(Application.Exename) + 'tagpat.txt');
634     SsParser.MetaPattern.LoadFromFile(ExtractFilePath(Application.ExeName) + 'metapat.txt');
635   except
636     ShowMessage('tagpat.txt, metapat.txt\82ª\8c©\82Â\82©\82è\82Ü\82¹\82ñ\81B');
637     Application.Terminate;
638   end;
639
640   // \8dÄ\90\8e\9e\8aÔ\90\84\92è\83R\83\93\83|\81[\83l\83\93\83g\82É\83p\83\89\83\81\81[\83^\82ð\8ew\92è
641   SsPlayTime.PlayTimeParams := Pref.PlayTimeParams;
642
643   // \83\81\83C\83\93\83E\83B\83\93\83h\83E\82Ì\88Ê\92u\82Æ\83T\83C\83Y\82ð\95\9c\8bA
644   with Pref.SenderWindowPosition do begin
645     Self.Left   := Left;
646     Self.Top    := Top;
647     Self.Width  := Right - Left + 1;
648     Self.Height := Bottom - Top + 1;
649   end;
650
651   // \83^\83X\83N\83o\81[\82Ì\8dÄ\8bN\93®(Explorer\82ª\97\8e\82¿\82½\82Æ\82«)\82ð\8c\9f\8fo\82·\82é
652   FWM_TaskBarCreated := RegisterWindowMessage('TaskBarCreated');
653
654   // \83X\83N\83\8a\83v\83g\95\8e\9a\97ñ\82Ì\8f\89\8aú\89»
655   actClearExecute(Sender);
656   // \83^\83X\83N\83g\83\8c\83C\82É\83A\83C\83R\83\93\82ð\92Ç\89Á
657   ChangeTaskIcon;
658   // \83`\83\83\83\93\83l\83\8b\8eQ\89Á\8aÖ\8cW\82Ì\83^\83u\82Ì\8f\88\97\9d\82È\82Ç(\83`\83\83\83\93\83l\83\8b\95s\8eQ\89Á\82Å\8f\89\8aú\89»)
659 //  UpdateJoinChannelList(nil);
660   //\8f\89\8aú\89»
661   UpdateJoinChannelList;
662
663   // SSTP\8dÄ\91\97\83I\83u\83W\83F\83N\83g
664   FBottleSstp := TBottleSstp.Create(false);
665   with FBottleSstp do begin
666     OnResendCountChange := BottleSstpResendCountChange;
667     OnResendTrying := BottleSstpResendTrying;
668     OnResendEnd := BottleSstpResendEnd;
669   end;
670 end;
671
672 procedure TfrmSender.FormDestroy(Sender: TObject);
673 begin
674   if FScriptBuffer <> nil then
675     FScriptBuffer.Free;
676
677   if FBottleSstp <> nil then begin
678     FBottleSstp.Terminate;
679     FBottleSstp.Free;
680   end;
681
682   with Pref.SenderWindowPosition do begin
683     Left   := Self.Left;
684     Top    := Self.Top;
685     Right  := Self.Left + Self.Width - 1;
686     Bottom := Self.Top + Self.Height - 1;
687   end;
688
689 //  if JoinChannelsBackup <> nil then JoinChannelsBackup.Free;
690
691   ScriptConstList.Save;
692
693   SaveChainRuleList;
694   BottleChainRuleList.Free;
695
696 end;
697
698
699 {
700 procedure TfrmSender.SetConnecting(const Value: boolean);
701 begin
702   FConnecting := Value;
703   if Value then begin
704     StatusBar.Panels[PanelConnecting].Text := '\92Ê\90M\92\86';
705     actStart.Enabled := false;
706     actStop.Enabled := false;
707     actSend.Enabled := false;
708     actVoteMessage.Enabled := false;
709     actAgreeMessage.Enabled := false;
710     mnGetNewId.Enabled := false;
711     Screen.Cursor := crAppStart;
712   end else begin
713     StatusBar.Panels[PanelConnecting].Text := '';
714     actStart.Enabled := true;
715     actStop.Enabled := true;
716     actSend.Enabled := true;
717     frmLog.lvwLogChange(Self, nil, ctState);
718     mnGetNewId.Enabled := Pref.LUID = '';
719     Screen.Cursor := crDefault;
720   end;
721 end;
722 }
723
724 // \83\81\83b\83Z\81[\83W\91\97\90M
725 procedure TfrmSender.actSendExecute(Sender: TObject);
726 var
727   Talk, AGhost: String;
728 //  Command: TStringList;
729   Err: String;
730 //  F: TextFile;
731   Item: TLogItem;
732 begin
733   //\83t\83\89\83O
734   if not Pref.SendAction then
735   begin
736     ShowHintLabel('\93®\8dì\82ª\96¢\90Ý\92è\82Å\82·');
737     Exit;
738   end;
739   if Length(GetScriptText) = 0 then
740   begin
741     ShowMessage('\83X\83N\83\8a\83v\83g\82ª\8bó\82Å\82·\81B');
742     Exit;
743   end;
744
745 {
746   if Pref.LUID = '' then begin
747     NoLuidError;
748     Exit;
749   end;
750   if tabChannel.TabIndex < 0 then begin
751     ShowMessage('\83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82µ\82Ä\82¢\82Ü\82¹\82ñ\81B'#13#10+
752       '\83\81\83j\83\85\81[\82©\82ç\81u\83`\83\83\83\93\83l\83\8b\8eQ\89Á\81v\82ð\8ds\82Á\82Ä\82­\82¾\82³\82¢\81B');
753     Exit;
754   end;
755   if ChannelList.Channel[FNowChannel].NoPost then begin
756     Beep;
757     ShowMessage(FNowChannel + ' \82Í\8eó\90M\90ê\97p\82Å\82·');
758     Exit;
759   end;
760 }
761
762   YenETrans;
763   Talk := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
764   Err := DoTrans(Talk, [toWarnMessySurface, toWarnCheck]);
765   if Err <> '' then
766   begin
767     MessageDlg(Err, mtWarning, [mbOk], 0);
768     Exit;
769   end;
770
771 {
772   if Pref.NeedConfirmBeforeSend and FScriptModified then
773   begin
774     MessageDlg('\91\97\90M\91O\82É\83\8d\81[\83J\83\8b\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B', mtError, [mbOk], 0);
775     Exit;
776   end;
777
778   if not Pref.NoConfirm then begin
779     if not SendConfirmDialog(FNowChannel, cbxTargetGhost.Text) then Exit;
780   end;
781 }
782
783   AGhost := '';
784   if cbxTargetGhost.ItemIndex > 0 then AGhost := cbxTargetGhost.Text;
785   //\92P\91Ì\83A\83N\83V\83\87\83\93
786   Item := TLogItem.Create;
787   try
788     with Item do
789     begin
790       MID := '';
791       Channel := 'local';
792       LogTime := now();
793       Script := Talk;
794       Ghost := AGhost;
795       Votes := 0;
796       Agrees := 0;
797     end;
798     BottleCnv(Item);
799   except
800     Item.Free;
801   end;
802   ShowHintLabel('[local]\82Ö\91\97\90M\82µ\82Ü\82µ\82½');
803
804 {
805   Command := TStringList.Create;
806   try
807     with Command do begin
808       Add('Command: sendBroadcast');
809       Add('Channel: ' + FNowChannel);
810       Add('LUID: ' + Pref.LUID);
811       Add('Agent: ' + VersionString);
812       if Ghost <> '' then Add('Ghost: ' + Ghost);
813       Add('Talk: ' + Talk);
814     end;
815     PostCommand(Command);
816   finally
817     Command.Free;
818   end;
819
820   //\91\97\90M\83\8d\83O\95Û\91
821   AssignFile(F, ExtractFilePath(Application.ExeName) + SentLogFile);
822   if FileExists(ExtractFilePath(Application.ExeName) + SentLogFile) then
823     Append(F)
824   else
825     Rewrite(F);
826   WriteLn(F, Format('%s,%s,%s,%s', [FNowChannel, Ghost, FormatDateTime('yy/mm/dd hh:nn:ss', Now), Talk]));
827   Flush(F);
828   CloseFile(F);
829 }
830 end;
831
832 {
833 procedure TfrmSender.BeginConnect;
834 begin
835   if Pref.LUID = '' then begin
836     NoLuidError;
837     Exit;
838   end;
839   IdSlpp20.LUID := Pref.LUID;
840   self.Cursor := crHourGlass;
841   if IdSlpp20.Connected then IdSlpp20.Disconnect;
842   if Pref.UseHttpProxy then begin
843     IdSlpp20.Host := Pref.ProxyAddress;
844     IdSlpp20.Port := Pref.ProxyPort;
845     IdSlpp20.ProxyMode := true;
846   end else begin
847     IdSlpp20.Host := Pref.BottleServer;
848     IdSlpp20.Port := Pref.BottleServerPort;
849     IdSlpp20.ProxyMode := false;
850   end;
851   IdSlpp20.ConnectServer;
852   self.Cursor := crDefault;
853 end;
854 }
855
856 {
857 procedure TfrmSender.EndConnect;
858 begin
859   IdSlpp20.OnDisconnect := nil;
860   IdSlpp20.Disconnect;
861 end;
862 }
863
864 {
865 procedure TfrmSender.SetAdded(const Value: boolean);
866 begin
867   if FAdded = Value then Exit;
868   FAdded := Value;
869   if Value then begin
870     StatusText := 'SSTP Bottle \83T\81[\83o\82É\90Ú\91±\82³\82ê\82Ä\82¢\82Ü\82·';
871     ChangeTaskIcon;
872   end else begin
873     StatusText := '\83T\81[\83o\82Æ\82Ì\90Ú\91±\82ª\90Ø\82ê\82Ä\82¢\82Ü\82·!';
874     ChangeTaskIcon;
875     ShowHintLabel('SSTP Bottle\83T\81[\83o\82©\82ç\90Ø\92f\82³\82ê\82Ü\82µ\82½!', WarningColor);
876   end;
877 end;
878 }
879
880 {
881 procedure TfrmSender.HTTPSuccess(Sender: TObject);
882 var Str, ResStr, Command: String;
883     HeadValue: THeadValue;
884     i: integer;
885     SetChannel: TStringList;
886 begin
887   Connecting := false;
888   Str := (Sender as THttpDownloadThread).RecvString;
889   HeadValue := nil;
890   try
891     try
892       HeadValue := THeadValue.Create(Str);
893     except
894       Beep;
895       frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82ª\89ð\90Í\82Å\82«\82È\82¢\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½\81B');
896       Exit;
897     end;
898     Command := HeadValue['Command'];
899     ResStr  := HeadValue['Result'];
900     if ResStr = 'Err' then begin
901       if HeadValue['ExtraMessage'] <> '' then begin
902         Beep;
903         frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82ª\8e\9f\82Ì\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½:'#13#10 +
904                      HeadValue['ExtraMessage']);
905       end else begin
906         Beep;
907         frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82ª\89½\82ç\82©\82Ì\83G\83\89\81[\82ð\95Ô\82µ\82Ü\82µ\82½\81B');
908       end;
909     end;
910     if (Command = 'sendBroadcast') and (ResStr = 'OK') then begin
911       ShowHintLabel(HeadValue['Channel'] + ' \82Ì ' + HeadValue['SentNum'] +
912                     '\90l\82É\91\97\90M\82µ\82Ü\82µ\82½');
913       //\83S\81[\83X\83g\82ð\83f\83t\83H\83\8b\83g\82É\96ß\82·
914       if Pref.ResetIfGhostAfterSend then begin
915         actResetGhostExecute(Self);
916       end;
917       //\83X\83N\83\8a\83v\83g\82ð\83N\83\8a\83A
918       if Pref.ClearAfterSend then begin
919         actClear.Execute;
920       end;
921     end else if (Command = 'sendBroadcast') and (ResStr <> 'OK') then begin
922       ShowHintLabel('\83\81\83b\83Z\81[\83W\82ð\91\97\90M\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½', WarningColor);
923     end;
924     if (Command = 'getNewId') then begin
925       if ResStr = 'OK' then begin
926         Pref.LUID := HeadValue['NewID'];
927         ShowHintLabel('LUID\8eæ\93¾\8a®\97¹\81B');
928         frmMessageBox.ShowMessage('\8f\89\89ñ\8bN\93®\82Ì\82½\82ß\81A' +
929           'SSTP Bottle\83T\81[\83o\90Ú\91±\97p\82ÌID(LUID)\82ð\90V\8bK\8eæ\93¾\82µ\82Ü\82µ\82½\81B'#13#10 +
930           'LUID: ' + Pref.LUID +  #13#10 +
931           '\90Ý\92è\83t\83@\83C\83\8b\82ð\8dí\8f\9c\82·\82é\82±\82Æ\82Å\81ALUID\82Í\8e©\97R\82É\8eæ\93¾\82Å\82«\82Ü\82·\82ª\81A' +
932           'LUID\82Ì\8eg\97p\8eÀ\90Ñ\82É\89\9e\82\82Ä\93Á\93T\82ª\82 \82é\82©\82à\82µ\82ê\82Ü\82¹\82ñ\82Ì\82Å\81A' +
933           '\8fo\97\88\82é\82¾\82¯\93¯\82\82à\82Ì\82ð\8eg\82Á\82Ä\82­\82¾\82³\82¢\81B\8fÚ\8d×\82Í\83w\83\8b\83v\82ð\82²\97\97\82­\82¾\82³\82¢\81B');
934         mnGetNewId.Enabled := false;
935         BeginConnect;
936       end else begin
937         ShowHintLabel('LUID\8eæ\93¾\82É\8e¸\94s\82µ\82Ü\82µ\82½');
938       end;
939     end;
940     if (Command = 'voteMessage') then begin
941       if ResStr = 'OK' then begin
942         ShowHintLabel('\83\81\83b\83Z\81[\83W\82É\93\8a\95[/\93¯\88Ó\82µ\82Ü\82µ\82½\81B\95[\90\94: ' + HeadValue['Votes']);
943       end;
944     end;
945     if (Command = 'getChannels') and (ResStr = 'OK') then begin
946       UpdateChannelInfo(HeadValue);
947       SetChannel := nil;
948       try
949         if FAutoAddAfterGetChannel then begin
950           SetChannel := TStringList.Create;
951           if JoinChannelsBackup <> nil then begin
952             //\88ê\92U\83`\83\83\83\93\83l\83\8b\8eQ\89Á\82É\90¬\8c÷\82µ\82½\8cã\82È\82ç\8dÅ\8cã\82É\8eQ\89Á\82µ\82Ä\82¢\82½\83`\83\83\83\93\83l\83\8b
953             SetChannel.Assign(JoinChannelsBackup);
954           end else begin
955             //\8a®\91S\82É\8f\89\89ñ\8bN\93®\82Ì\8fê\8d\87\82Í\83v\83\8c\83t\83@\83\8c\83\93\83X\82©\82ç\93o\98^\95ª\82ð\8eæ\93¾
956             for i := 0 to Pref.AutoJoinChannels.Count-1 do begin
957               if ChannelList.Channel[Pref.AutoJoinChannels[i]] <> nil then
958                 SetChannel.Add(Pref.AutoJoinChannels[i]);
959             end;
960           end;
961         end else begin
962           Application.CreateForm(TfrmChannelList, frmChannelList);
963           try
964             if frmChannelList.Execute(ChannelList, JoinChannels) then begin
965               SetChannel := TStringList.Create;
966               SetChannel.Assign(frmChannelList.JoinList);
967             end;
968           finally
969             frmChannelList.Release;
970           end;
971         end;
972         if SetChannel <> nil then PostSetChannel(SetChannel);
973       finally
974         if SetChannel <> nil then FreeAndNil(SetChannel);
975       end;
976     end;
977     if (Command = 'setChannels') then begin
978       if ResStr <> 'OK' then begin
979         Beep;
980         frmMessageBox.ShowMessage('\83`\83\83\83\93\83l\83\8b\90Ý\92è\82É\8e¸\94s\82µ\82Ü\82µ\82½\81B\82à\82¤\88ê\93x\93o\98^\82µ\82È\82¨\82µ\82Ä\82­\82¾\82³\82¢');
981         ShowHintLabel('\83`\83\83\83\93\83l\83\8b\90Ý\92è\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
982       end;
983     end;
984     if HeadValue['ExtraTip'] <> '' then ShowHintLabel(HeadValue['ExtraTip']);
985   finally
986     HeadValue.Free;
987   end;
988 end;
989 }
990
991 procedure TfrmSender.actStartClick(Sender: TObject);
992 begin
993   ShowHintLabel('SSTP Bottle\83T\81[\83o\82É\82Í\90Ú\91±\82Å\82«\82Ü\82¹\82ñ', WarningColor);
994 {
995   if Pref.LUID = '' then begin
996     NoLuidError;
997     Exit;
998   end;
999   if not IdSlpp20.Connected then begin
1000     FBeginConnectFailCount := 0; // \8e©\93®\8dÄ\90Ú\91±\83J\83E\83\93\83^\83\8a\83Z\83b\83g
1001     BeginConnect;
1002   end;
1003   if Added then begin
1004     FAutoAddAfterGetChannel := false;
1005     PostCommand(['Command: getChannels']);
1006   end;
1007 }
1008 end;
1009
1010 procedure TfrmSender.actStopExecute(Sender: TObject);
1011 begin
1012   ShowHintLabel('SSTP Bottle\83T\81[\83o\82É\82Í\90Ú\91±\82Å\82«\82Ü\82¹\82ñ', WarningColor);
1013 {
1014   // \8b­\90§\8dÄ\90Ú\91±\82ð\8ds\82¤
1015   IdSlpp20.OnDisconnect := nil;
1016   if IdSlpp20.Connected then IdSlpp20.Disconnect;
1017   FAutoAddAfterGetChannel := true;
1018   BeginConnect;
1019   IdSlpp20.OnDisconnect := Slpp20Disconnect;
1020 }
1021 end;
1022
1023 procedure TfrmSender.FormShow(Sender: TObject);
1024 begin
1025   if FBooted or Application.Terminated then Exit;
1026 {
1027   //LUID\82ª\8eæ\93¾\82³\82ê\82Ä\82¢\82ê\82Î\91\81\91¬\93o\98^\81B\82»\82¤\82Å\82È\82¯\82ê\82ÎLUID\8eæ\93¾\81B
1028   if Pref.LUID <> '' then BeginConnect
1029   else mnGetNewIdClick(Self);
1030   FAutoAddAfterGetChannel := Pref.AutoStart;
1031 }
1032   FBooted := true;
1033   if NOT Pref.NotShowLog then frmLog.Show;
1034   frmSurfacePreview.Show;
1035   Self.Show;
1036   SakuraSeeker.BeginDetect;
1037   SakuraSeekerDetectResultChanged(self);
1038   //\8e©\93®\95Û\91\90Ý\92è\82Ì\83\8d\81[\83h
1039   SetScriptAutoBackUp;
1040 {
1041   if SakuraSeeker.Count = 0 then
1042     frmMessageBox.ShowMessage('\83S\81[\83X\83g(SSTP\83T\81[\83o)\82ª1\82Â\82à\8bN\93®\82µ\82Ä\82¢\82Ü\82¹\82ñ\81B'#13#10 +
1043       'SSTP Bottle\82ð\97\98\97p\82·\82é\82½\82ß\82É\82Í\81A\83S\81[\83X\83g\82ð\93¯\8e\9e\82É\8bN\93®\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
1044       '\8fÚ\8d×\82Í\83w\83\8b\83v\82ð\82²\97\97\89º\82³\82¢\81B');
1045 }
1046 end;
1047
1048 procedure TfrmSender.actAboutClick(Sender: TObject);
1049 var Str: String;
1050 begin
1051   Str := VersionString + #13#10 + BottleDisclaimer + #13#10#13#10;
1052   Str := Str + Format('Compiler Version: %f', [CompilerVersion]);
1053   frmMessageBox.ShowMessage(Str);
1054 end;
1055
1056 procedure TfrmSender.actExitClientExecute(Sender: TObject);
1057 begin
1058   Close;
1059 end;
1060
1061 procedure TfrmSender.actClearExecute(Sender: TObject);
1062 var
1063   Script, Default: String;
1064 begin
1065   Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
1066   Default := StringReplace(Pref.DefaultScript, '|', '', [rfReplaceAll]);
1067   Default := StringReplace(Default, #13#10, '', [rfReplaceAll]);
1068
1069   if (Pref.AutoClip) and (Length(GetScriptText) > 0) and (Script <> Default) then
1070     actSendToLogWindow.Execute
1071   else
1072     ClearEditor;
1073 end;
1074
1075 procedure TfrmSender.memScriptChange(Sender: TObject);
1076 begin
1077   //\83G\83f\83B\83^\93à\97e\82ª\95Ï\8dX\82³\82ê\82½\82Æ\82«
1078   EditerStatusChange;
1079   FScriptBackModified := true; //\8e©\93®\95Û\91\8dÄ\8aJ
1080   SetFileModified(true);       //\83t\83@\83C\83\8b\95Ï\8dX\83t\83\89\83O
1081 end;
1082
1083 procedure TfrmSender.EditerStatusChange;
1084 var
1085   Script: String;
1086   Text: String;
1087   Len: integer;
1088 begin
1089   // \83X\83e\81[\83^\83X\95Ï\8dX\82¾\82¯
1090   // \93à\97e\82ª\83h\83\89\83b\83O\82³\82ê\82½\82Æ\82«\82à\8cÄ\82Ñ\8fo\82³\82ê\82é
1091   Script := GetScriptText;
1092   Len := Length(Script);
1093   // \94»\92è\82·\82é\95ª\8fd\82¢\82©\82à\81H
1094   if Pref.NotScriptTime AND (Len > Pref.NotScriptTimeLen) then
1095     Text := Format('%d\83o\83C\83g/?', [Len])
1096   else
1097   begin
1098     Script := StringReplace(Script, #13#10, '', [rfReplaceAll]);
1099     Text := Format('%d\83o\83C\83g/%d\95b', [Length(Script), SsPlayTime.PlayTime(Script) div 1000])
1100   end;
1101   StatusBar.Panels[PanelBytes].Text := Text;
1102 //  FScriptModified := true;
1103   EditorPreview;
1104 end;
1105
1106 procedure TfrmSender.mnStayOnTopClick(Sender: TObject);
1107 begin
1108   Pref.StayOnTop := not Pref.StayOnTop;
1109   mnStayOnTop.Checked := Pref.StayOnTop;
1110   if Pref.StayOnTop then begin
1111     FormStyle := fsStayOnTop;
1112   end else begin
1113     FormStyle := fsNormal;
1114   end;
1115   Show;
1116 end;
1117
1118 function TfrmSender.GetScriptText: String;
1119 begin
1120   Result := memScript.Lines.Text;
1121 end;
1122
1123 procedure TfrmSender.mnConstClick(Sender: TObject);
1124 var i: integer;
1125 begin
1126   i := (Sender as TMenuItem).Tag;
1127   memScript.SelText := ScriptConstList.GetConstByID(i).ConstText;
1128 end;
1129
1130 procedure TfrmSender.actEditConstExecute(Sender: TObject);
1131 begin
1132   ScriptConstList.LoadFromDir(FConstDir);
1133   try
1134     Application.CreateForm(TfrmConstEditor, frmConstEditor);
1135     frmConstEditor.Execute;
1136     ScriptConstList.Save;
1137   finally
1138     frmConstEditor.Release;
1139   end;
1140   ConstructMenu(false);
1141 end;
1142
1143 procedure TfrmSender.mnTaskBarClick(Sender: TObject);
1144 begin
1145   Application.Minimize;
1146   WindowState := wsNormal;
1147 end;
1148
1149 procedure TfrmSender.FormClose(Sender: TObject; var Action: TCloseAction);
1150 begin
1151 //  EndConnect;
1152   TaskTray.Registered := false;
1153 end;
1154
1155 procedure TfrmSender.ApplicationEventsMinimize(Sender: TObject);
1156 begin
1157   Visible := false;
1158   Application.ShowMainForm := false;
1159   ShowWindow(Application.Handle, SW_HIDE);
1160 end;
1161
1162 procedure TfrmSender.ApplicationEventsRestore(Sender: TObject);
1163 begin
1164   Application.ShowMainForm := true;
1165   Visible := true;
1166 end;
1167
1168 procedure TfrmSender.mnTaskRestoreClick(Sender: TObject);
1169 begin
1170   Application.Restore;
1171 end;
1172
1173 procedure TfrmSender.TaskTrayDblClick(Seft: TObject; Button: TMouseButton);
1174 begin
1175   Application.Restore;
1176 end;
1177
1178 procedure TfrmSender.FormActivate(Sender: TObject);
1179 begin
1180   memScript.SetFocus;
1181 end;
1182
1183 procedure TfrmSender.mnTaskNewMessageClick(Sender: TObject);
1184 begin
1185   Application.Restore;
1186   actClearExecute(Sender);
1187 end;
1188
1189 procedure TfrmSender.ChangeTaskIcon;
1190 var Ico: TIcon;
1191     IcoNum: integer;
1192 begin
1193 {
1194   if Added then begin
1195     if Sleeping then IcoNum := IconSleep else IcoNum := IconConnected;
1196   end else begin
1197     if Sleeping then IcoNum := IconSleepDisconnected
1198     else IcoNum := IconDisconnected;
1199   end;
1200 }
1201   //\83^\83X\83N\83A\83C\83R\83\93\82Ì\8fó\91Ô\81i\8e¸\94s\8fó\91Ô\8eg\97p\81j
1202   if Sleeping then IcoNum := IconSleepDisconnected
1203     else IcoNum := IconDisconnected;
1204   try
1205     Ico := TIcon.Create;
1206     try
1207       imgIcon.GetIcon(IcoNum, Ico);
1208       TaskTray.Icon := Ico;
1209       TaskTray.Registered := true;
1210     finally
1211       Ico.Free;
1212     end;
1213   except
1214     ; // PC\82Ì\95\89\89×\82ª\8d\82\82¢\82Æ4\95b\88È\93à\82É\83^\83X\83N\83g\83\8c\83C\93o\98^\82Å\82«\82¸\81A
1215       // \83V\83F\83\8b\82ª\83n\83\93\83O\82µ\82Ä\82¢\82é\82Æ\94»\92f\82³\82ê\82Ä\97á\8aO\82ª\94­\90\82·\82é\81B
1216       // \82»\82Ì\8fê\8d\87\82Í\83G\83\89\81[\82ð\96³\8e\8b\82·\82é
1217   end;
1218 end;
1219
1220 {
1221 procedure TfrmSender.SetStatusText(const Value: String);
1222 begin
1223   FStatusText := Value;
1224   StatusBar.Panels[PanelStatus].Text := Value;
1225 end;
1226 }
1227
1228 procedure TfrmSender.ApplicationEventsHint(Sender: TObject);
1229 var id: integer;
1230 begin
1231   if Length(Application.Hint) > 0 then
1232   begin
1233     StatusBar.Panels[PanelStatus].Text := GetLongHint(Application.Hint);
1234     Application.HintColor := clInfoBk;
1235\91\97\90M\83{\83^\83\93\8aÖ\98A
1236     if (Application.Hint = SendButtonLongHint)
1237     and (FNowChannel <> '') then
1238     begin
1239       //\91\97\90M\83{\83^\83\93\82Ì\8fê\8d\87\82Í\91¬\8dU\8fo\82·
1240       Application.HintColor := clYellow;
1241       Application.ActivateHint(Mouse.CursorPos);
1242     end;
1243 }
1244     if IsSurfaceTag(Application.Hint, id) and Pref.SurfacePreviewOnHint then
1245     begin
1246       // \83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[
1247       DoSurfacePreview(id, spHint);
1248     end;
1249   end else
1250   begin
1251     StatusBar.Panels[PanelStatus].Text := FStatusText;
1252     frmSurfacePreview.HideAway;
1253   end;
1254 end;
1255
1256 procedure TfrmSender.ConstructMenu(Simple: boolean);
1257 begin
1258   BuildMenu(mnPopConst, Simple);
1259   BuildMenu(mnPopUpConst.Items, Simple);
1260   BuildMenu(ConstBarMenu.Items, Simple);
1261   //\96\88\89ñ\8f\89\8aú\89»?
1262   if Pref.EConstBar then ConstMenuBar.Menu := nil;
1263   ConstMenuBar.AutoSize := false;
1264   ConstMenuBar.Width := 1000;
1265   ConstMenuBar.Menu := ConstBarMenu;
1266   ConstMenuBar.AutoSize := true;
1267 end;
1268
1269 procedure TfrmSender.memScriptKeyDown(Sender: TObject; var Key: Word;
1270   Shift: TShiftState);
1271 var Pos: TPoint;
1272     Func: TReturnKeyFunction;
1273 begin
1274   if (Key = VK_RETURN) then begin
1275     if (ssShift in Shift) then
1276       Func := Pref.WhenShiftReturn
1277     else if (ssCtrl in Shift) then
1278       Func := Pref.WhenCtrlReturn
1279     else
1280       Func := Pref.WhenReturn;
1281     case Func of
1282       kfConstText: begin
1283         with tbtnInsertConst do
1284           Pos := tbtnInsertConst.ClientToScreen(Point(0, Height));
1285         mnPopUpConst.Popup(Pos.X, Pos.Y);
1286       end;
1287       kfYenN: begin
1288         memScript.SelText := '\n';
1289         Key := 0;
1290       end;
1291       kfYenNReturn: begin
1292         memScript.SelText := '\n'#13#10;
1293       end;
1294       kfReturn: begin
1295         memScript.SelText := #13#10
1296       end;
1297     end;
1298   end;
1299 end;
1300
1301 procedure TfrmSender.mnShowToolBarClick(Sender: TObject);
1302 begin
1303   mnShowToolBar.Checked := not mnShowToolBar.Checked;
1304   Pref.ShowToolBar := mnShowToolBar.Checked;
1305   UpdateLayout;
1306 end;
1307
1308 procedure TfrmSender.mnShowConstBarClick(Sender: TObject);
1309 begin
1310   mnShowConstBar.Checked := not mnShowConstBar.Checked;
1311   Pref.ShowConstBar := mnShowConstBar.Checked;
1312   UpdateLayout;
1313 end;
1314
1315 procedure TfrmSender.UpdateLayout;
1316 begin
1317   with SakuraScriptFountain do begin
1318     TagColor.Color := Pref.MarkUpColor;
1319     TagErrorColor.Color := Pref.MarkErrorColor;
1320     Scope0Color.Color := Pref.TalkColorH;
1321     Scope1Color.Color := Pref.TalkColorU;
1322     SynchronizedColor.Color := Pref.TalkColorS;
1323   end;
1324   memScript.Ruler.Visible := Pref.ShowRuler;
1325   memScript.Ruler.Color := Pref.TextColor;
1326   memScript.Color := Pref.BgColor;
1327
1328   ToolBar.Visible := Pref.ShowToolBar;
1329   ConstMenuBar.Visible := Pref.ShowConstBar;
1330   ToolBar.Top := 0;
1331   //
1332   with tabChannel do begin
1333     TabPosition := Pref.TabPosition;
1334     case Pref.TabPosition of
1335       tpTop:    Align  := alTop;
1336       tpBottom: Align := alBottom;
1337     end;
1338     TabWidth := Pref.TabWidth;
1339   end;
1340 end;
1341
1342 function TfrmSender.DoTrans(var Script: String;
1343   Options: TScriptTransOptions; out FoundURL: boolean): String;
1344 var UrlCancel, Mark: String;
1345     Url, UrlName: array[0..6] of String;
1346     i, j, u, UrlCount: integer;
1347     LastSurfaceH, LastSurfaceU: integer;
1348     UnyuTalking: boolean;
1349     QuickSection, Synchronize: boolean;
1350     Warnings: TStringList;
1351 begin
1352   UrlCount := 0;
1353   LastSurfaceH := 0;
1354   LastSurfaceU := 10;
1355   UnyuTalking := false;
1356   QuickSection := false;
1357   Synchronize := false;
1358   SsParser.LeaveEscape := true;
1359   SsParser.EscapeInvalidMeta := false;
1360   SsParser.InputString := Script;
1361   Script := '';
1362   Warnings := TStringList.Create;
1363   try
1364     for i := 0 to SsParser.Count-1 do begin
1365       if SsParser[i] = '\t' then begin
1366         if not(toIgnoreTimeCritical in Options) then
1367           Script := Script + '\t';
1368       end else if SsParser[i] = '\e' then begin
1369         Continue;
1370       end else if (SsParser.Match(SsParser[i], '\URL%b') > 0) then begin
1371         if toConvertURL in Options then begin
1372           UrlCount := 0; //\91O\82ÌURL\83^\83O\82Ì\89e\8b¿\82ð\96³\8e\8b\81B
1373           for u := 7 downto 1 do begin
1374             if (SsParser.Match(SsParser[i],
1375                 '\URL%b'+StringReplace(StringOfChar('-', u*2),
1376                 '-', '%b', [rfReplaceAll]))) > 0 then begin
1377               for j := 1 to u do begin
1378                 Url[UrlCount] := SsParser.GetParam(SsParser[i], UrlCount*2+2);
1379                 UrlName[UrlCount] := SsParser.GetParam(SsParser[i], UrlCount*2+3);
1380                 if UrlName[UrlCount] = '' then UrlName[UrlCount] := Url[UrlCount];
1381                 if Pos('http://', Url[UrlCount]) > 0 then Inc(UrlCount);
1382               end;
1383             end;
1384             if UrlCount > 0 then UrlCancel := SsParser.GetParam(SsParser[i], 1);
1385             if UrlCancel = '' then UrlCancel := '\8ds\82©\82È\82¢\81@\81@\81@\81@';
1386           end;
1387           if SsParser.Match(SsParser[i], '\URL%b%b') = 0 then begin //\8aÈ\88Õ\94ÅURL\95Ï\8a·
1388             //\8aÈ\88Õ\8c`\8e®\URL\83^\83O\95Ï\8a·
1389             Url[0] := SsParser.GetParam(SsParser[i], 1);
1390             UrlName[0] := '\8ds\82­\81@\81@\81@\81@\81@\81@';
1391             UrlCancel  := '\8ds\82©\82È\82¢\81@\81@\81@\81@';
1392             if Pos('http://', Url[0]) > 0 then begin
1393               UrlCount := 1;
1394               if not QuickSection then
1395                 Script := Script + '\_q' + Url[0] + '\_q'
1396               else
1397                 Script := Script + Url[0];
1398             end;
1399           end;
1400         end else Script := Script + SsParser[i];
1401       end else begin
1402         Mark := SsParser[i];
1403         if Mark = '\h' then begin
1404           UnyuTalking := false;
1405           if toHUTagTo01Tag in Options then Mark := '\0';
1406           if Synchronize and Pref.WarnScopeChangeInSynchronize then
1407             Warnings.Add('\83V\83\93\83N\83\8d\83i\83C\83Y\83h\83Z\83N\83V\83\87\83\93\92\86\82É\h\82ª\82 \82è\82Ü\82·\81B');
1408         end else if Mark = '\u' then begin
1409           UnyuTalking := true;
1410           if toHUTagTo01Tag in Options then Mark := '\1';
1411           if Synchronize and Pref.WarnScopeChangeInSynchronize then
1412             Warnings.Add('\83V\83\93\83N\83\8d\83i\83C\83Y\83h\83Z\83N\83V\83\87\83\93\92\86\82É\u\82ª\82 \82è\82Ü\82·\81B');
1413         end else if Mark = '\_q' then begin
1414           QuickSection := not QuickSection;
1415         end else if Mark = '\_s' then begin
1416           Synchronize := not Synchronize;
1417         end else if SsParser.Match(Mark, '\s%b') > 0 then begin
1418           if UnyuTalking then begin
1419             LastSurfaceU := StrToIntDef(SsParser.GetParam(Mark, 1),
1420                                         LastSurfaceU);
1421           end else begin
1422             LastSurfaceH := StrToIntDef(SsParser.GetParam(Mark, 1),
1423                                         LastSurfaceH);
1424           end;
1425         end else if SsParser.Match(Mark, '\s%d') > 0 then begin
1426           if UnyuTalking then begin
1427             LastSurfaceU := StrToIntDef(Mark[3], LastSurfaceU);
1428           end else begin
1429             LastSurfaceH := StrToIntDef(Mark[3], LastSurfaceH);
1430           end;
1431         end;
1432         Script := Script + Mark;
1433       end;
1434     end;
1435     if UrlCount > 0 then begin
1436       FoundUrl := true;
1437       Script := Script + '\h\n';
1438       if not (toNoChoice in Options) then begin
1439         for i := 0 to UrlCount-1 do begin
1440           Script := Script + Format('\q%d[%s][%s]',
1441                       [i, SsParser.EscapeParam(Url[i]), UrlName[i]]);
1442         end;
1443         Script := Script + Format('\q%d[#cancel][%s]', [UrlCount, UrlCancel]);
1444         //Script := Script + '\z'; //\8dÅ\90Vphase\82Å\82Í\8dí\8f\9c
1445       end else begin
1446         Script := Script + '\h';
1447         for i := 0 to UrlCount-1 do begin
1448           Script := Script + Format('\n{%s}(%s)', [UrlName[i], Url[i]]);
1449         end;
1450         Script := Script + Format('\n{%s}', [UrlCancel]);
1451       end;
1452     end else
1453       FoundUrl := false;
1454     //\83X\83N\83\8a\83v\83g\82Ì\8dÅ\8cã\82É\83E\83F\83C\83g\91}\93ü
1455     if toWaitScriptEnd in Options then begin
1456       i := Pref.WaitScriptEnd;
1457       while i > 0 do begin
1458         if i > 9 then begin
1459           Script := Script + '\w9';
1460           Dec(i, 9);
1461         end else begin
1462           Script := Script + '\w' + IntToStr(i);
1463           i := 0;
1464         end;
1465       end;
1466     end;
1467
1468     Script := Script + '\e';
1469     RegExp.Subst('s/\r\n//gk', Script);
1470
1471     //\83^\83O\83`\83F\83b\83N\8aÖ\98A
1472     for i := 0 to SsParser.Count-1 do begin
1473       if SsParser.MarkUpType[i] = mtTagErr then begin
1474         Result := '"' + SsParser[i] + '"'#13#10 +
1475                   '\82Í\81ASSTP Bottle\82Å\94F\82ß\82ç\82ê\82È\82¢\82©\81A\94F\8e¯\82Å\82«\82È\82¢\83^\83O\82Å\82·\81B';
1476         Exit;
1477       end;
1478     end;
1479     if (SsParser[0] <> '\t') and Pref.WarnYenTNotExist then begin
1480       Warnings.Add('\83X\83N\83\8a\83v\83g\82ª\t\82©\82ç\8en\82Ü\82Á\82Ä\82¢\82Ü\82¹\82ñ\81B');
1481     end;
1482
1483     //\83`\83F\83b\83N
1484     if (Warnings.Count > 0) and (toWarnCheck in Options) then begin
1485       if MessageDlg(Warnings.Text + #13#10 + '\91\97\90M\82µ\82Ü\82·\82©?', mtWarning,
1486                     mbOkCancel, 0) = mrCancel then
1487         Result := Warnings.Text;
1488     end;
1489   finally
1490     Warnings.Free;
1491   end;
1492 end;
1493
1494 function TfrmSender.DoTrans(var Script: String;
1495   Options: TScriptTransOptions): String;
1496 var dum: boolean;
1497 begin
1498   Result := DoTrans(Script, Options, dum);
1499 end;
1500
1501 procedure TfrmSender.mnGoToHPClick(Sender: TObject);
1502 begin
1503   OpenBrowser(Pref.HomePage);
1504 end;
1505
1506 procedure TfrmSender.ShowHintLabel(const Mes: String; Col: TColor);
1507 begin
1508   lblMessage.Caption := Mes;
1509   lblMessage.Font.Color := Col;
1510   lblMessage.Visible := true;
1511   LabelTimer.Enabled := false;
1512   LabelTimer.Enabled := true;
1513 end;
1514
1515 procedure TfrmSender.LabelTimerTimer(Sender: TObject);
1516 begin
1517   LabelTimer.Enabled := false;
1518   lblmessage.Visible := false;
1519 end;
1520
1521 procedure TfrmSender.actCopyAllExecute(Sender: TObject);
1522 var Str: String;
1523     Clip: TClipBoard;
1524 begin
1525   Str := memScript.Lines.Text;
1526   Clip := ClipBoard();
1527   Clip.SetTextBuf(PChar(Str));
1528 end;
1529
1530 procedure TfrmSender.actCopyAllNoReturnExecute(Sender: TObject);
1531 var Str: String;
1532     Clip: TClipBoard;
1533 begin
1534   Str := memScript.Lines.Text;
1535   RegExp.Subst('s/\r\n//gk', Str);
1536   Clip := ClipBoard();
1537   Clip.SetTextBuf(PChar(Str));
1538 end;
1539
1540 {
1541 procedure TfrmSender.Slpp20SlppEvent(Sender: TObject; EventType: TIdSlppEventType;
1542   const Param: String);
1543 var HeadValue: THeadValue;
1544 begin
1545   HeadValue := THeadValue.Create(Param);
1546   try
1547     case EventType of
1548       etScript, etForceBroadcast, etUnicast: begin
1549         //\83\81\83b\83Z\81[\83W\8eó\90M
1550         DispatchBottle(EventType, HeadValue);
1551       end;
1552       etMemberCount: begin
1553         StatusBar.Panels[PanelMembers].Text := HeadValue['Num'] + '\90l'
1554       end;
1555       etChannelCount: begin
1556         try
1557           ChannelList.Channel[HeadValue['Channel']].Members := StrToInt(HeadValue['Num']);
1558         except
1559         end;
1560       end;
1561       etConnectOk: begin
1562         ShowHintLabel('SSTP Bottle\83T\81[\83o\82Æ\92Ê\90M\8am\97§\81B');
1563         Added := true;
1564         FBeginConnectFailCount := 0;
1565         //\83`\83\83\83\93\83l\83\8b\8e©\93®\93o\98^
1566         if not Connecting then
1567           PostCommand(['Command: getChannels']);
1568         SakuraSeeker.BeginDetect;
1569       end;
1570       etChannelList: begin
1571         UpdateJoinChannelList(HeadValue);
1572         // \8dÅ\8cã\82É\8eQ\89Á\82µ\82Ä\82¢\82½\83`\83\83\83\93\83l\83\8b\82ð\8bL\98^\82·\82é
1573         if JoinChannelsBackup = nil then JoinChannelsBackup := TStringList.Create;
1574         JoinChannelsBackup.Assign(JoinChannels);
1575       end;
1576       etCloseChannel: begin
1577         with JoinChannels do
1578           if IndexOf(HeadValue['Channel']) >= 0 then
1579             Delete(IndexOf(HeadValue['Channel']));
1580         with tabChannel do begin
1581           if Tabs.IndexOf(HeadValue['Channel']) >= 0 then
1582             Tabs.Delete(Tabs.IndexOf(HeadValue['Channel']));
1583           if Tabs.Count > 0 then TabIndex := 0 else TabIndex := -1;
1584           tabChannelChange(self);
1585         end;
1586         ShowHintLabel(HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½',
1587                       WarningColor);
1588         frmLog.AddCurrentSystemLog('SYSTEM', HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½');
1589         frmMessageBox.ShowMessage(HeadValue['Channel'] + '\83`\83\83\83\93\83l\83\8b\82Í\94p\8e~\82³\82ê\82Ü\82µ\82½');
1590       end;
1591       etForceBroadcastInformation: begin
1592         if HeadValue['Type'] = 'Vote' then begin
1593           frmLog.VoteLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0));
1594         end else if HeadValue['Type'] = 'Agree' then begin
1595           frmLog.AgreeLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0));
1596         end;
1597       end;
1598     end;
1599   finally
1600     HeadValue.Free;
1601   end;
1602 end;
1603 }
1604
1605 procedure TfrmSender.BottleSstpResendCountChange(Sender: TObject);
1606 begin
1607   StatusBar.Panels[PanelCount].Text := IntToStr(FBottleSstp.CueCount) + '\8c\8f';
1608   try
1609     TaskTray.TipString := 'Yasagure Client (' +
1610                           IntToStr(FBottleSstp.CueCount) + '\8c\8f)';
1611   except
1612     ; // \83^\83X\83N\83g\83\8c\83C\93o\98^\8e¸\94s\82ð\96³\8e\8b\82·\82é
1613   end;
1614   actClearBottles.Enabled := (FBottleSstp.CueCount > 0);
1615 end;
1616
1617 procedure TfrmSender.actSettingExecute(Sender: TObject);
1618 begin
1619   Application.CreateForm(TfrmSetting, frmSetting);
1620   try
1621     frmSetting.Execute;
1622     Pref.SaveSettings;
1623     SaveChainRuleList;
1624   finally
1625     frmSetting.Release;
1626     frmSetting := nil;
1627   end;
1628   //
1629   BuildReplaceMenu(mnPresetReplaceRoot);
1630   UpdateLayout;
1631   tabChannel.Repaint;
1632   frmLog.UpdateWindow;
1633   SetScriptAutoBackUp;  //\83X\83N\83\8a\83v\83g\8e©\93®\95Û\91\90Ý\92è\8dX\90V
1634   UpdateChannelList;    //\83`\83\83\83\93\83l\83\8b\83S\81[\83X\83g\8dÄ\83\8d\81[\83h
1635 end;
1636
1637 procedure TfrmSender.memScriptKeyPress(Sender: TObject; var Key: Char);
1638 begin
1639   if (Key = #13) or (Key = #10) then Key := Char(0);
1640 end;
1641
1642 {
1643 procedure TfrmSender.Slpp20Disconnect(Sender: TObject);
1644 begin
1645   Added := false;
1646   UpdateJoinChannelList(nil);
1647   frmLog.AddCurrentSystemLog('SYSTEM', '\83T\81[\83o\82©\82ç\90Ø\92f\82³\82ê\82Ü\82µ\82½');
1648   if not Application.Terminated then RetryBeginConnect;
1649 end;
1650 }
1651
1652 procedure TfrmSender.SetSleeping(const Value: boolean);
1653 begin
1654   FSleeping := Value;
1655   FBottleSstp.ResendSleep := Value;
1656   ChangeTaskIcon;
1657 end;
1658
1659 procedure TfrmSender.actClearBottlesExecute(Sender: TObject);
1660 var Re: integer;
1661 begin
1662   Re := MessageDlg(Format('\96¢\94z\91\97\82Ì%d\8c\8f\82ÌBottle\82ð\91S\95\94\83N\83\8a\83A\82µ\82Ü\82·', [FBottleSstp.CueCount]),
1663                    mtWarning, mbOkCancel, 0);
1664   if Re = mrOk then begin
1665     FBottleSstp.Clear;
1666     frmLog.AllBottleOpened;
1667     frmLog.UpdateWindow;
1668   end;
1669 end;
1670
1671 procedure TfrmSender.SakuraSeekerDetectResultChanged(Sender: TObject);
1672 begin
1673   UpdateIfGhostBox; // \83h\83\8d\83b\83v\83_\83E\83\93\82Ì\92\86\90g\82ð\8f\91\82«\8a·\82¦\82é
1674 end;
1675
1676 {
1677 procedure TfrmSender.UpdateChannelInfo(Dat: THeadValue);
1678 var i: integer;
1679     Ch: TChannelListItem;
1680 begin
1681   ChannelList.Clear;
1682   for i := 1 to Dat.IntData['Count'] do begin
1683     Ch := TChannelListItem.Create;
1684     Ch.Name    := Dat[Format('CH%d_name', [i])];
1685     Ch.Ghost   := Dat[Format('CH%d_ghost', [i])];
1686     Ch.Info    := Dat[Format('CH%d_info', [i])];
1687     Ch.NoPost  := Dat[Format('CH%d_nopost', [i])] = '1';
1688     Ch.Members := Dat.IntData[Format('CH%d_count', [i])];
1689     Ch.WarnPost:= Dat[Format('CH%d_warnpost', [i])] = '1';
1690     ChannelList.Add(Ch);
1691   end;
1692   UpdateLayout;
1693 end;
1694 }
1695
1696 procedure TfrmSender.mnGetNewIdClick(Sender: TObject);
1697 begin
1698   ShowHintLabel('LUID\82Ì\8eæ\93¾\82Í\82Å\82«\82Ü\82¹\82ñ', WarningColor);
1699 //  PostCommand(['Command: getNewId', 'Agent: ' + VersionString]);
1700 end;
1701
1702 {
1703 procedure TfrmSender.NoLuidError;
1704 begin
1705   Beep;
1706   ShowMessage('SSTP Bottle ID\82Ì\8eæ\93¾\82ª\82Ü\82¾\8a®\97¹\82µ\82Ä\82¢\82Ü\82¹\82ñ\81B'#13#10+
1707               '\83w\83\8b\83v\83\81\83j\83\85\81[\82Ì[LUID\8eæ\93¾]\82©\82çID\82ð\8eæ\93¾\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10+
1708               '\82±\82Ì\91\80\8dì\82ÍClient\8f\89\89ñ\8bN\93®\8e\9e\82É1\89ñ\82¾\82¯\95K\97v\82Å\82·\81B');
1709 end;
1710 }
1711
1712 procedure TfrmSender.tabChannelChange(Sender: TObject);
1713 begin
1714 {
1715   if tabChannel.TabIndex >= 0 then begin
1716     FNowChannel := tabChannel.Tabs[tabChannel.TabIndex];
1717     actSend.Hint := Format('\81u%s\81v\82É\91\97\90M|%s', [FNowChannel, SendButtonLongHint]);
1718   end else begin
1719     FNowChannel := '';
1720     actSend.Hint := '';
1721   end;
1722   tabChannel.Repaint; //\82±\82ê\82ª\82È\82¢\82Æ\90F\82ª\95Ï\82í\82ç\82È\82¢\82±\82Æ\82ª\82 \82é
1723   ConstructMenu(true);
1724 }
1725 end;
1726
1727 procedure TfrmSender.actPrevChannelExecute(Sender: TObject);
1728 begin
1729 {
1730   with tabChannel do begin
1731     if Tabs.Count = 0 then Exit;
1732     if TabIndex=0 then TabIndex := Tabs.Count-1
1733     else TabIndex := TabIndex-1;
1734   end;
1735   tabChannelChange(Self);
1736 }
1737 end;
1738
1739 procedure TfrmSender.actNextChannelExecute(Sender: TObject);
1740 begin
1741 {
1742   with tabChannel do begin
1743     if Tabs.Count = 0 then Exit;
1744     if TabIndex=Tabs.Count-1 then TabIndex := 0
1745     else TabIndex := TabIndex+1;
1746   end;
1747   tabChannelChange(Self);
1748 }
1749 end;
1750
1751 {
1752 procedure TfrmSender.UpdateJoinChannelList(Dat: THeadValue);
1753 var i: integer;
1754     nodat: boolean;
1755 begin
1756   nodat := Dat = nil; //nil\82È\82ç\83`\83\83\83\93\83l\83\8b\91S\89ð\8f\9c
1757   if nodat then Dat := THeadValue.Create('');
1758   JoinChannels.Clear;
1759   for i := 0 to Dat.Count-1 do
1760     if Dat.KeyAt[i] = 'Entry' then begin
1761       if RegExp.Match('m/^(.+?) \((\d+?)\)$/', Dat.ValueAt[i]) then
1762         JoinChannels.Add(RegExp[1]);
1763     end;
1764   with tabChannel do begin
1765     OnChange := nil;
1766     JoinChannels.Sort;
1767     Tabs.BeginUpdate;
1768     Tabs.Clear;
1769     for i := 0 to JoinChannels.Count-1 do begin
1770       //\8eó\90M\90ê\97p\83`\83\83\83\93\83l\83\8b\82Í\95\\8e¦\82µ\82È\82¢
1771       if not ChannelList.Channel[JoinChannels[i]].NoPost then
1772         Tabs.Add(JoinChannels[i]);
1773     end;
1774     Tabs.EndUpdate;
1775     // \8c³\82©\82ç\83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82µ\82Ä\82¢\82½\8fê\8d\87\82Í
1776     // \91I\91ð\82³\82ê\82Ä\82¢\82½\83`\83\83\83\93\83l\83\8b\82ª\95Ï\82í\82ç\82È\82¢\82æ\82¤\82É\82·\82é(\83^\83u\82ª\82¸\82ê\82È\82¢\8f\88\97\9d)
1777     TabIndex := 0;
1778     for i := 0 to Tabs.Count-1 do
1779       if Tabs[i] = FNowChannel then TabIndex := i;
1780     if Tabs.Count > 0 then begin
1781       FNowChannel := Tabs[TabIndex];
1782       actSend.Hint := Format('\81u%s\81v\82É\91\97\90M|%s', [FNowChannel, SendButtonLongHint]);
1783     end else begin
1784       FNowChannel := '';
1785       actSend.Hint := Format('\91\97\90M|%s', [SendButtonLongHint]);
1786     end;
1787     Visible := Tabs.Count > 0;
1788     if Tabs.Count > 1 then begin
1789       actNextChannel.Enabled := true;
1790       actPrevChannel.Enabled := true;
1791     end else begin
1792       actNextChannel.Enabled := false;
1793       actPrevChannel.Enabled := false;
1794     end;
1795     OnChange := tabChannelChange;
1796   end;
1797   if nodat then Dat.Free;
1798   if JoinChannels.Count = 0 then begin
1799     Self.Caption := FOriginalCaption + ' - \83`\83\83\83\93\83l\83\8b\82É\8eQ\89Á\82µ\82Ä\82¢\82Ü\82¹\82ñ';
1800     actSend.Enabled := false;
1801   end else begin
1802     Self.Caption := FOriginalCaption;
1803     actSend.Enabled := true;
1804   end;
1805 end;
1806 }
1807
1808 procedure TfrmSender.cbxTargetGhostDropDown(Sender: TObject);
1809 begin
1810   SakuraSeeker.BeginDetect;
1811   UpdateIfGhostBox;
1812 end;
1813
1814 procedure TfrmSender.actShowLogExecute(Sender: TObject);
1815 begin
1816   frmLog.Show;
1817   if frmLog.WindowState = wsMinimized then frmLog.WindowState := wsNormal;
1818 end;
1819
1820 procedure TfrmSender.actSleepExecute(Sender: TObject);
1821 begin
1822   if actSleep.Checked then begin
1823     actSleep.Checked := false;
1824     ShowHintLabel('\83X\83\8a\81[\83v\82ð\89ð\8f\9c\82µ\82Ü\82µ\82½');
1825   end else begin
1826     actSleep.Checked := true;
1827     ShowHintLabel('\83X\83\8a\81[\83v\82ð\90Ý\92è\82µ\82Ü\82µ\82½');
1828   end;
1829   Sleeping := actSleep.Checked;
1830   ChangeTaskIcon;
1831 end;
1832
1833
1834 procedure TfrmSender.DispatchBottle(Dat: THeadValue; LogTime: TDateTime;
1835   Vote, Agree: integer);
1836 //procedure TfrmSender.DispatchBottle(EventType: TIdSlppEventType;
1837 //  Dat: THeadValue);
1838 var Opt: TSstpSendOptions;
1839     Event: TBottleChainBottleEvent;
1840     Script, Sender, Ghost, Channel, ErrorMes: String;
1841     BreakFlag, NoDispatch: boolean;
1842     Sound, LogName: String;
1843     i, j, k, SkipCount: integer;
1844     Rule: TBottleChainRule;
1845     Action: TBottleChainAction;
1846     LogNameList: TStringList;
1847     CueItem: TLogItem;
1848     ReplaceHash: THeadValue;
1849 begin
1850   Opt := [];
1851   if Pref.NoTranslate then Opt := Opt + [soNoTranslate];
1852   if Pref.NoDescript  then Opt := Opt + [soNoDescript];
1853   Channel := Dat['Channel'];
1854 {
1855   case EventType of
1856     etScript: Sender := Channel;
1857     etForceBroadcast: Sender := '\81y\82¨\92m\82ç\82¹\81z';
1858     etUnicast: Sender := Dat['SenderUID'];
1859   end;
1860 }
1861   Sender := Channel; //\92Ê\8fí
1862
1863   //\96Ú\95W\83S\81[\83X\83g(\83I\81[\83o\81[\83\89\83C\83h\88È\91O)\8c\88\92è
1864   if Dat['IfGhost'] <> '' then begin
1865     Ghost := Dat['IfGhost'];
1866   end else begin
1867     if ChannelList.Channel[Channel] <> nil then
1868       Ghost := ChannelList.Channel[Channel].Ghost
1869     else
1870       Ghost := '';
1871   end;
1872   Dat['TargetGhost'] := Ghost;
1873
1874   // \83\81\83^\95\8e\9a\8f\80\94õ
1875   ReplaceHash := THeadValue.Create;
1876   ReplaceHash['%channel%'] := SafeFileName(Dat['Channel']);
1877   ReplaceHash['%ghost%'] := SafeFileName(Dat['IfGhost']);
1878   ReplaceHash['%date%'] := FormatDateTime('yy-mm-dd', Now());
1879   ReplaceHash['%year%'] := FormatDateTime('yyyy', Now());
1880   ReplaceHash['%yy%'] := FormatDateTime('yy', Now());
1881   ReplaceHash['%month%'] := FormatDateTime('mm', Now());
1882   ReplaceHash['%day%'] := FormatDateTime('dd', Now());
1883   ReplaceHash['%hour%'] := FormatDateTime('hh', Now());
1884   ReplaceHash['%minute%'] := FormatDateTime('nn', Now());
1885
1886   Event := TBottleChainBottleEvent.Create;
1887   try
1888     Event.Data := Dat;
1889 {
1890     if EventType = etScript then Event.LogType := ltBottle
1891     else Event.LogType := ltSystemLog;
1892 }
1893     Event.LogType := ltBottle; //\92Ê\8fí
1894
1895     //\83X\83N\83\8a\83v\83g\95Ï\8a·
1896     Script := ScriptTransForSSTP(Dat['Script'], ErrorMes);
1897     //\96â\91è\82Ì\97L\82é\95r\82É\91Î\82·\82é\93®\8dì
1898     if (ErrorMes <> '') AND (NOT Pref.ErrScript) then
1899     begin
1900       frmLog.AddCurrentSystemLog('SYSTEM', '\96â\91è\82Ì\82 \82é\89Â\94\\90«\82Ì\82 \82é\83X\83N\83\8a\83v\83g\82ª\93Í\82¢\82½\82½\82ß\81A'+
1901                     '\94z\91\97\82³\82ê\82Ü\82¹\82ñ\82Å\82µ\82½\81@\81c '+Dat['Script']);
1902       Exit;
1903     end;
1904
1905     BreakFlag := false;
1906     NoDispatch := false;
1907     Sound := '';
1908     LogNameList := TStringList.Create;
1909     SkipCount := 0;
1910     try
1911       for i := 0 to BottleChainRuleList.Count-1 do begin
1912         if SkipCount > 0 then begin
1913           Dec(SkipCount);
1914           Continue;
1915         end;
1916         Rule := BottleChainRuleList[i];
1917         if not Rule.Enabled then Continue;
1918         if not Rule.Check(Event) then Continue;
1919         for j := 0 to Rule.Actions.Count-1 do begin
1920           Action := (Rule.Actions[j] as TBottleChainAction);
1921           if Action is TBottleChainAbortRuleAction then
1922             BreakFlag := true;
1923           if Action is TBottleChainSkipRuleAction then
1924             SkipCount := (Action as TBottleChainSkipRuleAction).SkipCount;
1925           if (Action is TBottleChainSoundAction) and (Sound = '') then
1926           begin
1927             Sound := (Action as TBottleChainSoundAction).SoundFile;
1928             Sound := StringReplaceEx(Sound, ReplaceHash);
1929           end;
1930           if Action is TBottleChainNoDispatchAction then
1931             NoDispatch := true;
1932           if Action is TBottleChainLogAction then
1933           begin
1934             for k := 0 to (Action as TBottleChainLogAction).LogNames.Count-1 do begin
1935               LogName := (Action as TBottleChainLogAction).LogNames[k];
1936               LogName := StringReplaceEx(LogName, ReplaceHash);
1937               LogNameList.Add(LogName);
1938             end;
1939           end;
1940           if Action is TBottleChainOverrideGhostAction then
1941           begin
1942             Dat['TargetGhost'] := (Action as TBottleChainOverrideGhostAction).TargetGhost;
1943           end;
1944           if Action is TBottleChainQuitAction then
1945             Application.Terminate;
1946           if Action is TBottleChainSaveTextLogAction then
1947             AppendTextLog(StringReplaceEx((Action as TBottleChainSaveTextLogAction).FileName, ReplaceHash),
1948               Format('%s,%s,%s,%s', [Dat['Channel'], Dat['IfGhost'],
1949                 FormatDateTime('yy/mm/dd hh:nn:ss', Now), Dat['Script']]), true);
1950           if Action is TBottleChainSaveXMLLogAction then
1951             AppendXMLLog(StringReplaceEx((Action as TBottleChainSaveXMLLogAction).FileName, ReplaceHash),
1952               Dat);
1953           if Action is TBottleChainSurfaceReplaceAction then
1954             Script := ReplaceSurface(Script, (Action as TBottleChainSurfaceReplaceAction).Params);
1955         end;
1956         if BreakFlag then Break;
1957       end;
1958
1959       if Dat['Script'] <> '' then begin
1960         for i := 0 to LogNameList.Count-1 do
1961           frmLog.AddCurrentScriptLog(LogNameList[i], Dat['Script'], Sender, Dat['MID'], Dat['IfGhost'],
1962             LogTime, Vote, Agree);
1963         if NoDispatch or Pref.NotSSTP then begin
1964           frmLog.SetBottleState(Dat['MID'], lsOpened);
1965         end else begin
1966           Ghost := Dat['TargetGhost']; // \83I\81[\83o\81[\83\89\83C\83h\82³\82ê\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82é
1967           CueItem := TLogItem.Create(ltBottle, Dat['MID'], Dat['Channel'],
1968             Script, Ghost, Now());
1969           try
1970             FBottleSstp.Push(CueItem);
1971           except
1972             CueItem.Free;
1973           end;
1974         end;
1975       end;
1976
1977 {$IFDEF PASS}
1978       if Dat['DialogMessage'] <> '' then begin
1979         Beep;
1980         frmMessageBox.ShowMessage(
1981           DateTimeToStr(Now) + #13#10 +
1982           'SSTP Bottle\83T\81[\83o\82©\82ç\82¨\92m\82ç\82¹'#13#10+Dat['DialogMessage']);
1983         for i := 0 to LogNameList.Count-1 do
1984           frmLog.AddCurrentSystemLog(LogNameList[i], Dat['DialogMessage']);
1985       end;
1986 {$ENDIF}
1987
1988       //\89¹\82Ì\8dÄ\90
1989       if (Sound <> '') then PlaySound(Sound);
1990     finally
1991       LogNameList.Free;
1992     end;
1993   finally
1994     Event.Free;
1995     ReplaceHash.Free;
1996   end;
1997 end;
1998
1999 procedure TfrmSender.YenETrans;
2000 var St, Le, i: integer;
2001     Orig, Text: String;
2002 begin
2003   if Pref.NotYenETrans then exit; // \e\83`\83F\83b\83N\82µ\82È\82¢
2004   St := memScript.SelStart;
2005   Le := memScript.SelLength;
2006   Orig := GetScriptText;
2007   RegExp.Subst('s/(\r\n)+$//kg', Orig);
2008
2009   with SsParser do begin
2010     LeaveEscape := true;
2011     EscapeInvalidMeta := false;
2012     InputString := Orig;
2013   end;
2014   for i := 0 to SsParser.Count-1 do begin
2015     if SsParser[i] <> '\e' then Text := Text + SsParser[i];
2016   end;
2017
2018   Text := Text + '\e';
2019
2020   if Orig <> Text then memScript.Lines.Text := Text;
2021   SsParser.InputString := Text;
2022
2023   RegExp.Subst('s/\r\n//kg', Text);
2024   memScript.SetFocus;
2025   memScript.SelStart := St;
2026   memScript.SelLength := Le;
2027 end;
2028
2029 {
2030 procedure TfrmSender.PostCommand(const Command: array of String);
2031 var PostStr: TStringList;
2032     i: integer;
2033 begin
2034   PostStr := nil;
2035   try
2036     PostStr := TStringList.Create;
2037     for i := Low(Command) to High(Command) do begin
2038       PostStr.Add(Command[i]);
2039     end;
2040     PostCommand(PostStr);
2041   finally
2042     PostStr.Free;
2043   end;
2044 end;
2045 }
2046
2047 {
2048 procedure TfrmSender.PostCommand(Command: TStrings);
2049 var PostStr: String;
2050 begin
2051   Connecting := true;
2052   PostStr := Command.Text;
2053   PostStr := ParamsEncode(PostStr);
2054   try
2055     FHttp := THTTPDownloadThread.Create(Pref.BottleServer, Pref.CgiName, PostStr);
2056     if Pref.UseHttpProxy then begin
2057       FHttp.ProxyServer := Pref.ProxyAddress;
2058       FHttp.ProxyPort   := Pref.ProxyPort;
2059     end;
2060     FHttp.OnSuccess := HttpSuccess;
2061     FHttp.OnConnectionFailed := HttpFailure;
2062     FHttp.FreeOnTerminate := true; // \8f\9f\8eè\82É\8e©\95ª\82ÅFree\82µ\82Ä\82­\82¾\82³\82¢
2063     FHTTP.Resume;
2064   except
2065     on EHeapException do begin
2066       Connecting := false;
2067       FHttp.Free;
2068     end;
2069   end;
2070 end;
2071 }
2072
2073 procedure TfrmSender.actVoteMessageExecute(Sender: TObject);
2074 //var Log: TLogItem;
2075 begin
2076   ShowHintLabel('\93\8a\95[\82Å\82«\82Ü\82¹\82ñ', WarningColor);
2077 {
2078   if frmLog.lvwLog.Selected = nil then Exit;
2079   Log := frmLog.SelectedBottleLog[frmLog.lvwLog.Selected.Index] as TLogItem;
2080   if Log = nil then Exit;
2081   if Log.LogType <> ltBottle then Exit;
2082   PostCommand([
2083     'Command: voteMessage',
2084     'VoteType: Vote',
2085     'LUID: ' + Pref.LUID,
2086     'MID: ' + Log.MID
2087   ]);
2088 }
2089 end;
2090
2091
2092 procedure TfrmSender.actAgreeMessageExecute(Sender: TObject);
2093 //var Log: TLogItem;
2094 begin
2095   ShowHintLabel('\93¯\88Ó\82Å\82«\82Ü\82¹\82ñ', WarningColor);
2096 {
2097   if frmLog.lvwLog.Selected = nil then Exit;
2098   Log := frmLog.SelectedBottleLog[frmLog.lvwLog.Selected.Index] as TLogItem;
2099   if Log = nil then Exit;
2100   if Log.LogType <> ltBottle then Exit;
2101   PostCommand([
2102     'Command: voteMessage',
2103     'VoteType: Agree',
2104     'LUID: ' + Pref.LUID,
2105     'MID: ' + Log.MID
2106   ]);
2107 }
2108 end;
2109
2110
2111 function TfrmSender.GhostNameToSetName(const Ghost: String): String;
2112 begin
2113   if SakuraSeeker.ProcessByName[Ghost] <> nil then
2114     Result := SakuraSeeker.ProcessByName[Ghost].SetName
2115   else
2116     Result := '';
2117 end;
2118
2119 procedure TfrmSender.tabChannelContextPopup(Sender: TObject;
2120   MousePos: TPoint; var Handled: Boolean);
2121 //var Ch: String;
2122 begin
2123 {
2124   with tabChannel do begin
2125     Tag := IndexOfTabAt(MousePos.X, MousePos.Y);
2126     if Tag < 0 then Handled := true;
2127     Ch := Tabs[Tag];
2128   end;
2129 }
2130 end;
2131
2132 {
2133 procedure TfrmSender.PostSetChannel(Channels: TStrings);
2134 var PostStr: TStringList;
2135     i: integer;
2136 begin
2137   PostStr := TStringList.Create;
2138   try
2139     with PostStr do begin
2140       Add('Command: setChannels');
2141       Add('Agent: ' + VersionString);
2142       Add('LUID: ' + Pref.LUID);
2143       if Channels <> nil then
2144         for i := 0 to Channels.Count-1 do begin
2145           Add(Format('Ch%d: %s'#13#10, [i+1, Channels[i]]));
2146         end;
2147     end;
2148     PostCommand(PostStr);
2149   finally
2150     PostStr.Free;
2151   end;
2152 end;
2153 }
2154
2155 procedure TfrmSender.mnLeaveThisChannelClick(Sender: TObject);
2156 //var Ch: String;
2157 //    Chs: TStringList;
2158 begin
2159 {
2160   // \8ew\92è\82µ\82½\83`\83\83\83\93\83l\83\8b\82©\82ç\94²\82¯\82é
2161   with tabChannel do
2162     Ch := Tabs[Tag]; // \94²\82¯\82½\82¢\83`\83\83\83\93\83l\83\8b\96¼
2163   Chs := TStringList.Create;
2164
2165   // \8c»\8dÝ\8eQ\89Á\92\86\82Ì\83`\83\83\83\93\83l\83\8b\82©\82ç\81A\94²\82¯\82½\82¢\83`\83\83\83\93\83l\83\8b\82ð
2166   // \8aO\82µ\82½\83\8a\83X\83g\82Å\81A\90V\82½\82É\83`\83\83\83\93\83l\83\8b\8eQ\89Á\83R\83}\83\93\83h\82ð\91\97\82é
2167   try
2168     Chs.Assign(JoinChannels);
2169     while Chs.IndexOf(Ch) >= 0 do
2170       Chs.Delete(Chs.IndexOf(Ch));
2171     PostSetChannel(Chs);
2172   finally
2173     Chs.Free;
2174   end;
2175 }
2176 end;
2177
2178 procedure TfrmSender.mnGotoVoteClick(Sender: TObject);
2179 begin
2180   OpenBrowser(Pref.VotePage);
2181 end;
2182
2183 procedure TfrmSender.tabChannelMouseMove(Sender: TObject;
2184   Shift: TShiftState; X, Y: Integer);
2185 //var Index: integer;
2186 //    Ch: String;
2187 begin
2188 {
2189   with tabChannel do begin
2190     Index := IndexOfTabAt(X, Y);
2191     Ch := Tabs[Index];
2192     Hint := Ch + ': ' + IntToStr(ChannelList.Channel[Ch].Members) + '\90l';
2193   end;
2194 }
2195 end;
2196
2197 procedure TfrmSender.mnGoToHelpClick(Sender: TObject);
2198 begin
2199   OpenBrowser(Pref.HelpPage);
2200 end;
2201
2202 procedure TfrmSender.tabChannelMouseDown(Sender: TObject;
2203   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
2204 //var Index: integer;
2205 begin
2206 {
2207   with tabChannel do begin
2208     Index := IndexOfTabAt(X, Y);
2209     if Index = -1 then Exit; //\83^\83u\82ª\82È\82¢\82Ì\82Å\83h\83\89\83b\83O\82Å\82«\82È\82¢
2210     if Button = mbLeft then begin
2211       FDragTabIndex := Index; //\83h\83\89\83b\83O\82·\82é\83^\83u\82Ì\83C\83\93\83f\83b\83N\83X\82ð\95Û\91
2212       BeginDrag(False);
2213       FDragTabDest := -1;     //\83h\83\89\83b\83O\98g\90ü\95`\89æ\83t\83\89\83O\83N\83\8a\83A\82Ì\82½\82ß
2214     end;
2215   end;
2216 }
2217 end;
2218
2219 procedure TfrmSender.tabChannelDragOver(Sender, Source: TObject; X,
2220   Y: Integer; State: TDragState; var Accept: Boolean);
2221 //var TargetRect: TRect;
2222 //    OldDest: integer;
2223 begin
2224 {
2225   Accept := Source = tabChannel;
2226   if not Accept then Exit;
2227   with tabChannel do begin
2228     OldDest := FDragTabDest;
2229     FDragTabDest := IndexOfTabAt(X, Y);
2230     if FDragTabDest = -1 then begin
2231       Accept := false; //\82±\82Ì\8fê\8d\87\82Í\83h\83\8d\83b\83v\82ð\94F\82ß\82È\82¢
2232       Exit;
2233     end;
2234     with Canvas do begin
2235       Pen.Mode := pmNot;
2236       Pen.Width := 3;
2237     end;
2238     if (OldDest <> FDragTabDest) and (OldDest >= 0) then begin
2239       //\88È\91O\82Ì\98g\90ü\8fÁ\8b\8e
2240       TargetRect := TabRect(OldDest);
2241       with Canvas do begin
2242         Brush.Style := bsClear;
2243         Rectangle(TargetRect.Left, TargetRect.Top,
2244                   TargetRect.Right, TargetRect.Bottom);
2245       end;
2246     end;
2247     if (OldDest <> FDragTabDest) then begin
2248       //\90V\82µ\82¢\98g\90ü\95`\89æ
2249       TargetRect := TabRect(FDragTabDest);
2250       with Canvas do begin
2251         Brush.Style := bsClear;
2252         Rectangle(TargetRect.Left, TargetRect.Top,
2253                   TargetRect.Right, TargetRect.Bottom);
2254       end;
2255     end;
2256   end;
2257 }
2258 end;
2259
2260 procedure TfrmSender.tabChannelDragDrop(Sender, Source: TObject; X,
2261   Y: Integer);
2262 //var DestIndex: integer;
2263 begin
2264 {
2265   with tabChannel do begin
2266     DestIndex := IndexOfTabAt(X, Y);
2267     Tabs.Move(FDragTabIndex, DestIndex);
2268   end;
2269 }
2270 end;
2271
2272 procedure TfrmSender.tabChannelEndDrag(Sender, Target: TObject; X,
2273   Y: Integer);
2274 begin
2275 {
2276   //\8b­\90§\93I\82É\83^\83u\82ð\8dÄ\95`\89æ\82³\82¹\82é\81B\98g\90ü\8fÁ\82µ\91Î\8dô
2277   tabChannel.Tabs.BeginUpdate;
2278   tabChannel.Tabs.EndUpdate;
2279 }
2280 end;
2281
2282 procedure TfrmSender.cbxTargetGhostDrawItem(Control: TWinControl;
2283   Index: Integer; Rect: TRect; State: TOwnerDrawState);
2284 var AlignRight: boolean;
2285     w: integer;
2286 begin
2287   //\83S\81[\83X\83g\91I\91ð\83{\83b\83N\83X\82Ì\83I\81[\83i\81[\83h\83\8d\81[
2288   with cbxTargetGhost do begin
2289     AlignRight := false;
2290     if Pref.HideGhosts and not FTargetGhostExpand and
2291        (Index = Items.Count-1) and (Index > 0) then
2292     begin
2293       // \81u\82·\82×\82Ä\95\\8e¦\81v
2294       Canvas.Font.Color := clWindowText;
2295       Canvas.Font.Style := [];
2296       AlignRight := true;
2297     end else if (Index > 0) then
2298     begin
2299       // \83S\81[\83X\83g\96¼\82ð\91I\91ð
2300       if SakuraSeeker.ProcessByName[Items[Index]] = nil then
2301         Canvas.Font.Color := clRed // \91\8dÝ\82µ\82È\82¢\83S\81[\83X\83g
2302       else
2303         Canvas.Font.Color := clBlue; // \91\8dÝ\82·\82é\83S\81[\83X\83g
2304       Canvas.Font.Style := [fsBold];
2305     end else
2306     begin
2307       Canvas.Font.Color := clWindowText;
2308       Canvas.Font.Style := [];
2309     end;
2310     if odSelected in State then
2311       Canvas.Font.Color := clHighlightText;
2312     // \95`\89æ
2313     if AlignRight then
2314     begin
2315       w := Canvas.TextWidth(cbxTargetGhost.Items[Index]);
2316       Canvas.TextRect(Rect, Rect.Right - w, Rect.Top,
2317         cbxTargetGhost.Items[Index]);
2318     end else
2319       Canvas.TextRect(Rect, Rect.Left, Rect.Top,
2320         cbxTargetGhost.Items[Index]);
2321   end;
2322 end;
2323
2324 procedure TfrmSender.FormCloseQuery(Sender: TObject;
2325   var CanClose: Boolean);
2326 begin
2327   //\83t\83@\83C\83\8b\82Ì\8dX\90V\83`\83F\83b\83N\81i\83G\83f\83B\83^\95\94\81j
2328   if CheckFileModified(Self) = idCancel then
2329   begin
2330     CanClose := false;
2331     exit;
2332   end;
2333   //\83\8d\83O\81i\83^\83u\81j\93à\97e\82Ì\95Ï\8dX\83`\83F\83b\83N
2334   if frmLog.CheckLog(Self) = idCancel then
2335   begin
2336     CanClose := false;
2337     exit;
2338   end;
2339   if (not Pref.ConfirmOnExit) or FEndSession then
2340     Exit;
2341   if MessageDlg('Yasagure Client\82ð\8fI\97¹\82µ\82Ü\82·', mtConfirmation,
2342                 mbOkCancel, 0) = mrCancel then
2343     CanClose := false;
2344 end;
2345
2346 procedure TfrmSender.UpdateIfGhostBox;
2347 var
2348   Selected: String;
2349   i: integer;
2350   HiddenCount: integer;
2351 begin
2352   cbxTargetGhost.DropDownCount := Pref.GhostDropDownCount;
2353   Selected := cbxTargetGhost.Text;
2354   HiddenCount := 0;
2355   with cbxTargetGhost do begin
2356     Items.BeginUpdate;
2357     Items.Clear;
2358     Items.Add(ChannelDefault);
2359     for i := 0 to SakuraSeeker.Count-1 do begin
2360       // \94j\91¹FMO\91Î\8dô\81BHWND\82Ì\92f\95Ð\82ª\8ec\82Á\82Ä\82¢\82é\82ªName\82ª\8fÁ\82¦\82Ä\82¢\82é\8fê\8d\87\82ª\82 \82é
2361       if Length(SakuraSeeker[i].Name) = 0 then Continue;
2362       if Pref.HideGhosts and not FTargetGhostExpand then
2363         if Pref.VisibleGhostsList.IndexOf(SakuraSeeker[i].Name) < 0 then
2364         begin
2365           Inc(HiddenCount);
2366           Continue;
2367         end;
2368       if cbxTargetGhost.Items.IndexOf(SakuraSeeker[i].Name) < 0 then
2369         cbxTargetGhost.Items.Add(SakuraSeeker[i].Name);
2370     end;
2371     cbxTargetGhost.ItemIndex := 0;
2372     if (Length(Selected) > 0) and (Selected <> ChannelDefault) then begin
2373       with cbxTargetGhost do begin
2374         for i := 1 to Items.Count-1 do begin
2375           if Items[i] = Selected then
2376             ItemIndex := i;
2377         end;
2378         //\83S\81[\83X\83g\82ª\93Ë\91R\91\8dÝ\82µ\82È\82­\82È\82Á\82½\8fê\8d\87\91Î\8dô
2379         if ItemIndex = 0 then begin
2380           Items.Add(Selected);
2381           ItemIndex := Items.Count - 1;
2382         end;
2383       end;
2384     end;
2385     if Pref.HideGhosts and not FTargetGhostExpand then
2386       Items.Add(Format('\82·\82×\82Ä(%d)...', [HiddenCount]));
2387     Items.EndUpdate;
2388   end;
2389 end;
2390
2391 {
2392 procedure TfrmSender.HTTPFailure(Sender: TObject);
2393 begin
2394   SysUtils.Beep;
2395   Beep;
2396   ShowHintLabel('SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
2397   frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½'#13#10 +
2398     (Sender as THTTPDownloadThread).LastErrorMessage);
2399   Connecting := false;
2400 end;
2401 }
2402
2403 procedure TfrmSender.actPrevGhostExecute(Sender: TObject);
2404 var i: integer;
2405 begin
2406   SakuraSeeker.BeginDetect;
2407   UpdateIfGhostBox;
2408   i := cbxTargetGhost.ItemIndex;
2409   Dec(i);
2410   if i <= -1 then
2411   begin
2412     i := cbxTargetGhost.Items.Count-1;
2413     if Pref.HideGhosts and not FTargetGhostExpand then
2414       i := i - 1;
2415   end;
2416   cbxTargetGhost.ItemIndex := i;
2417   cbxTargetGhostChange(self);
2418 end;
2419
2420 procedure TfrmSender.actNextGhostExecute(Sender: TObject);
2421 var i: integer;
2422 begin
2423   SakuraSeeker.BeginDetect;
2424   UpdateIfGhostBox;
2425   i := cbxTargetGhost.ItemIndex;
2426   Inc(i);
2427   if Pref.HideGhosts and not FTargetGhostExpand then
2428   begin
2429     if  i > cbxTargetGhost.Items.Count-2 then i := 0;
2430   end else
2431   begin
2432     if  i > cbxTargetGhost.Items.Count-1 then i := 0;
2433   end;
2434   cbxTargetGhost.ItemIndex := i;
2435   cbxTargetGhostChange(self);
2436 end;
2437
2438 procedure TfrmSender.actResetGhostExecute(Sender: TObject);
2439 begin
2440   cbxTargetGhost.ItemIndex := 0; // (CH\90\84\8f§)\82É\96ß\82·
2441   FTargetGhostExpand := false;
2442   if Visible then memScript.SetFocus;
2443   cbxTargetGhostChange(self);
2444 end;
2445
2446 {
2447 procedure TfrmSender.timDisconnectCheckTimerTimer(Sender: TObject);
2448 begin
2449   if (IdSlpp20.LastReadTimeInterval > Pref.ReconnectWait * 60000) then begin
2450     SysUtils.Beep;
2451     frmLog.AddCurrentSystemLog('SYSTEM', 'SSTP Bottle\83T\81[\83o\82Æ\82Ì\90Ú\91±\82ª\83^\83C\83\80\83A\83E\83g\82µ\82Ü\82µ\82½');
2452     if IdSlpp20.Connected then IdSlpp20.Disconnect;
2453   end;
2454   if not IdSlpp20.Connected then begin
2455     if Added then begin
2456       Slpp20Disconnect(self); //\82È\82º\82©Disconnect\83C\83x\83\93\83g\82ª\8bN\82±\82ç\82¸\82É\90Ø\92f\82µ\82½\8fê\8d\87
2457     end else begin
2458       //\90Ø\92f\82µ\82½\82Ü\82Ü\8dÄ\90Ú\91±\82Å\82«\82¸\95ú\92u\82³\82ê\82Ä\82¢\82é\8fê\8d\87\82à\88ê\92è\8e\9e\8aÔ\92u\82«\82É\8dÄ\90Ú\91±\83g\83\89\83C
2459       //\82½\82¾\82µ\89ñ\90\94\90§\8cÀ\82 \82è
2460       RetryBeginConnect;
2461     end;
2462   end;
2463 end;
2464 }
2465
2466 {
2467 procedure TfrmSender.RetryBeginConnect;
2468 begin
2469   if FBeginConnectFailCount < 3 then begin
2470     // \90Ø\92f\82³\82ê\82Ä\82¢\82ê\82Î\8dÄ\90Ú\91±
2471     FAutoAddAfterGetChannel := true;
2472     BeginConnect;
2473   end else if FBeginConnectFailCount = 3 then begin
2474     frmLog.AddCurrentSystemLog('SYSTEM', '\8dÄ\90Ú\91±\8e©\93®\83\8a\83g\83\89\83C\82ð\92\86\8e~\82µ\82Ü\82·');
2475     frmMessageBox.ShowMessage(
2476       'SSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\81B'#13#10+
2477       '\83l\83b\83g\83\8f\81[\83N\82É\90Ú\91±\82µ\82Ä\82¢\82é\82±\82Æ\82ð\8am\94F\82µ\82½\8cã\82Å\81A\83`\83\83\83\93\83l\83\8b\8eQ\89Á\83{\83^\83\93\82ð\89\9f\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10+
2478       'SSTP Bottle\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\8fê\8d\87\82Í\81A\82µ\82Î\82ç\82­\82µ\82Ä\82©\82ç\8dÄ\90Ú\91±\82µ\82Ä\82­\82¾\82³\82¢\81B'
2479     );
2480     Inc(FBeginConnectFailCount);
2481   end;
2482 end;
2483 }
2484
2485 procedure TfrmSender.actDownloadLogExecute(Sender: TObject);
2486 {
2487 var BottleLog: TBottleLogList;
2488     Title: String;
2489     Cond: TBottleLogDownloadCondition;
2490     NewIndex: integer;
2491   function TimeStr(Mins: integer): String;
2492   var day, hour, min: integer;
2493   begin
2494     day := Mins div (60 * 24);
2495     hour := (Mins div 60) mod 24;
2496     min := Mins mod 60;
2497     Result := '';
2498     if day  > 0 then Result := Result + Format('%d\93ú', [day]);
2499     if hour > 0 then Result := Result + Format('%d\8e\9e\8aÔ', [hour]);
2500     if (min  > 0) or (Result = '') then Result := Result + Format('%d\95ª', [min]);
2501   end;
2502 }
2503 begin
2504   ShowHintLabel('\83\8d\83O\82Ì\83_\83E\83\93\83\8d\81[\83h\82Í\82Å\82«\82Ü\82¹\82ñ', WarningColor);
2505 {
2506   Application.CreateForm(TfrmLogDownload, frmLogDownload);
2507   try
2508     if frmLogDownload.Execute then begin
2509       with frmLogDownload do begin
2510         if IsRange then begin
2511           if CompareDate(DateLo, DateHi) = 0 then
2512             Title := FormatDateTime('yy-mm-dd', DateLo)
2513           else
2514             Title := FormatDateTime('yy-mm-dd', DateLo) + ' - ' + FormatdateTime('yy-mm-dd', DateHi);
2515         end else begin
2516           Title := Format('\89ß\8b\8e%s', [TimeStr(RecentCount)]);
2517         end;
2518         if Channel <> '' then Title := Title + '(' + Channel + ')';
2519       end;
2520       BottleLog := TBottleLogList.Create(Title);
2521       try
2522         BottleLog.OnLoaded := frmLog.LogLoaded;
2523         BottleLog.OnLoadFailure := frmLog.LogLoadFailure;
2524         BottleLog.OnLoadWork := frmLog.LogLoadWork;
2525         with frmLogDownload do begin
2526           Cond.IsRange := IsRange;
2527           Cond.RecentCount := RecentCount;
2528           Cond.DateLo := DateLo;
2529           Cond.DateHi := DateHi;
2530           Cond.MinVote := MinVote;
2531           Cond.MinAgree := MinAgree;
2532           Cond.Channel := Channel;
2533         end;
2534         BottleLog.LoadFromWeb(Cond);
2535       except
2536         FreeAndNil(BottleLog);
2537       end;
2538       if BottleLog <> nil then begin
2539         NewIndex := frmLog.BottleLogList.Add(BottleLog);
2540         frmLog.UpdateTab;
2541         frmLog.tabBottleLog.TabIndex := NewIndex;
2542         frmLog.UpdateWindow;
2543       end;
2544     end;
2545   finally
2546     frmLogDownload.Release;
2547   end;
2548 }
2549 end;
2550
2551 function TfrmSender.BuildMenuConditionCheck(const IfGhost,
2552   Ghost: String): boolean;
2553 var i: integer;
2554     Cond: String;
2555 begin
2556   i := 0;
2557   Result := true;
2558   repeat
2559     Cond := Token(IfGhost, ',', i);
2560     if Cond <> '' then begin
2561       if Cond[1] = '!' then begin
2562         Cond := Copy(Cond, 2, High(integer));
2563         if Cond = Ghost then Result := false;
2564       end else begin
2565         if Cond <> Ghost then Result := false;
2566       end;
2567     end;
2568     Inc(i);
2569   until Cond = '';
2570 end;
2571
2572 procedure TfrmSender.BuildMenu(Root: TMenuItem; Simple: boolean);
2573 var i, j, k, count: integer;
2574     ConstData: TScriptConst;
2575     Menu1, Menu2: TMenuItem;
2576     Ghost: String;
2577 begin
2578   // Simple = false \82Ì\8fê\8d\87\82Í\83\81\83j\83\85\81[\82ð\8a®\91S\82É\8dÄ\8d\\92z\82·\82é\81B
2579   // Simple = true \82Ì\8fê\8d\87\82Í\83S\81[\83X\83g\8aÖ\8cW\82Ì\82Ý\8dÄ\8d\\92z\82·\82é\82Ì\82Å\8d\82\91¬\81B
2580   if cbxTargetGhost.ItemIndex > 0 then Ghost := cbxTargetGhost.Text
2581 //  else if FNowChannel <> '' then Ghost := ChannelList.Channel[FNowChannel].Ghost;
2582   else
2583     Ghost := '';
2584
2585   // \8aù\91\82Ì\83\81\83j\83\85\81[\8dí\8f\9c
2586   if Simple then begin
2587     // IfGhost\8fð\8c\8f\95t\82«\83\81\83j\83\85\81[\82Ì\82Ý\8dí\8f\9c
2588     for i := Root.Count-1 downto 0 do begin
2589       if ScriptConstList.GetMenuByID(Root.Items[i].Tag).IfGhost <> '' then
2590         Root.Items[i].Free;
2591     end;
2592   end else
2593     // \91S\95\94\8dí\8f\9c
2594     Root.Clear;
2595
2596   count := -1;
2597   for i := 0 to ScriptConstList.Count-1 do begin
2598     for j := 0 to ScriptConstList[i].Count-1 do begin
2599       // \83S\81[\83X\83g\88á\82¢\82Ì\8fê\8d\87\82Í\83X\83L\83b\83v
2600       if not BuildMenuConditionCheck(ScriptConstList[i][j].IfGhost, Ghost) then Continue;
2601       Inc(count);
2602       // Simple\82Ì\8fê\8d\87\82Í\8aù\82É\8aY\93\96\83\81\83j\83\85\81[\82ª\91\8dÝ\82·\82é\82±\82Æ\82ª\82 \82é\82Ì\82Å\83X\83L\83b\83v
2603       if Simple and (count < Root.Count) then
2604         if (Root.Items[count].Tag = ScriptConstList[i][j].ID) then begin
2605           Continue;
2606         end;
2607
2608       Menu1 := TMenuItem.Create(Root);
2609       with Menu1 do
2610       begin
2611         Caption := ScriptConstList[i][j].Caption;
2612         Hint    := ScriptConstList[i][j].Caption;
2613         AutoHotkeys := maManual;
2614         Tag := ScriptConstList[i][j].ID;
2615         OnClick := mnConstGroupClick;
2616       end;
2617
2618       if not Simple then begin
2619         Root.Add(Menu1);
2620       end else begin
2621         if count < Root.Count-1 then
2622           Root.Insert(count, Menu1)
2623         else
2624           Root.Add(Menu1);
2625       end;
2626
2627       Menu1.Enabled := ScriptConstList[i][j].Count > 0;
2628       for k := 0 to ScriptConstList[i][j].Count-1 do begin
2629         ConstData := ScriptConstList[i][j][k];
2630         Menu2 := TMenuItem.Create(Root);
2631         Menu2.Caption := ConstData.Caption;
2632         Menu2.Hint := ConstData.ConstText;
2633         // if ConstData.ShortCut <> 0 then Menu2.Hint := Menu2.Hint
2634         //   + ' (' + ShortCutToText(ConstData.ShortCut) + ')';
2635         // \83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\8eÀ\8c»\82Ì\82½\82ß\8fã\8dí\8f\9c
2636         Menu2.ShortCut := ConstData.ShortCut;
2637         Menu2.OnClick := mnConstClick;
2638         Menu2.AutoHotkeys := maManual;
2639         Menu2.Tag := ConstData.ID;
2640         if (k mod 15 = 0) and (k > 0) then Menu2.Break := mbBarBreak;
2641         Menu1.Add(Menu2);
2642       end;
2643     end;
2644   end;
2645 end;
2646
2647 procedure TfrmSender.cbxTargetGhostChange(Sender: TObject);
2648 begin
2649   // \81u\82·\82×\82Ä\95\\8e¦\81v\82ð\91I\91ð\82³\82ê\82½\8fê\8d\87\82Í\83S\81[\83X\83g\91I\91ð\83{\83b\83N\83X\82ð\8dÄ\8d\\92z
2650   if Pref.HideGhosts and not FTargetGhostExpand then
2651   begin
2652     with cbxTargetGhost do
2653     begin
2654       // \88ê\94Ô\89º\82Ì\83A\83C\83e\83\80\82ª\91I\91ð\82³\82ê\82½\82Æ\82«\81B
2655       // \82½\82¾\82µItemIndex=0\82Ì\8fê\8d\87(\83S\81[\83X\83g\82ª\8bN\93®\82µ\82Ä\82¢\82È\82¢\8fê\8d\87)\82Í\97á\8aO
2656       if (ItemIndex = Items.Count-1) and (ItemIndex > 0) then
2657       begin
2658         FTargetGhostExpand := true;
2659         UpdateIfGhostBox;
2660         ItemIndex := 0;
2661         DroppedDown := true;
2662       end;
2663     end;
2664   end;
2665   // \92è\8c^\8bå\83\81\83j\83\85\81[\82ð\8dÄ\8d\\92z
2666   ConstructMenu(true);
2667   // \83v\83\8c\83r\83\85\81[\82ª\82 \82é\8fê\8d\87\82Í\83v\83\8c\83r\83\85\81[
2668   EditorPreview;
2669 end;
2670
2671 procedure TfrmSender.PlaySound(const FileName: String);
2672 begin
2673   if Pref.SilentWhenHidden and not Application.ShowMainForm then Exit;
2674   try
2675     MediaPlayer.FileName := FileName;
2676     MediaPlayer.Open;
2677     MediaPlayer.Play;
2678   except
2679     on E: EMCIDeviceError do begin
2680       ShowMessage('\83T\83E\83\93\83h\8dÄ\90\83G\83\89\81[:'#13#10 + FileName + #13#10#13#10 + E.Message);
2681     end;
2682   end;
2683 end;
2684
2685 procedure TfrmSender.actFMOExplorerExecute(Sender: TObject);
2686 begin
2687   try
2688     if not Assigned(frmFMOExplorer) then
2689       Application.CreateForm(TfrmFMOExplorer, frmFMOExplorer);
2690   except
2691     on E: Exception do
2692       ShowMessage('FMO\83G\83N\83X\83v\83\8d\81[\83\89\82ð\95\\8e¦\82Å\82«\82Ü\82¹\82ñ\81B'#13#10#13#10 +
2693         E.Message);
2694   end;
2695   frmFMOExplorer.Show;
2696 end;
2697
2698 procedure TfrmSender.SaveChainRuleList;
2699 var Str: TStringList;
2700 begin
2701   Str := TStringList.Create;
2702   try
2703     Str.Text := ComponentToString(BottleChainRuleList);
2704     Str.SaveToFile(ExtractFileDir(Application.ExeName)+'\rule.txt');
2705   finally
2706     Str.Free;
2707   end;
2708 end;
2709
2710 procedure TfrmSender.BottleSstpResendEnd(Sender: TObject; MID: String);
2711 begin
2712   frmLog.SetBottleState(MID, lsOpened);
2713 end;
2714
2715 procedure TfrmSender.BottleSstpResendTrying(Sender: TObject; MID: String);
2716 begin
2717   frmLog.SetBottleState(MID, lsPlaying);
2718 end;
2719
2720 procedure TfrmSender.LogInsertCue(TestAction: boolean);
2721 var InsertItem: TLogItem;
2722     i, errCount, Res: integer;
2723     Log: TBottleLogList;
2724     ErrorMes: String; // \83X\83N\83\8a\83v\83g\82Ì\83G\83\89\81[\82Ì\93à\97e
2725 begin
2726   if FBottleSstp.CueCount > 0 then begin
2727     if MessageDlg(Format('\8c»\8dÝ\8dÄ\91\97\83L\83\85\81[\82É\93ü\82Á\82Ä\82¢\82é%d\8c\8f\82Ì\96¢\94z\91\97\83{\83g\83\8b\82ð\83N\83\8a\83A\82µ\82Ä\81A'+
2728       '\83\8d\83O\83E\83B\83\93\83h\83E\82É\82 \82é\83{\83g\83\8b\82ð\98A\91±\8dÄ\90\82µ\82Ü\82·\81B'#13#10+
2729       '\90V\92\85\83\81\83b\83Z\81[\83W\82Í\82»\82Ì\8cã\82É\8dÄ\90\82³\82ê\82Ü\82·\81B', [FBottleSstp.CueCount]),
2730       mtWarning, mbOkCancel, 0) = mrCancel then Exit;
2731   end;
2732   FBottleSstp.Clear;
2733   frmLog.AllBottleOpened;
2734   if frmLog.lvwLog.Selected = nil then Exit;
2735   Log := frmLog.SelectedBottleLog;
2736   if Log = nil then Exit;
2737   FBottleSSTP.OnResendCountChange := nil;
2738   errCount := 0;
2739   for i := frmLog.lvwLog.Selected.Index downto 0 do begin
2740     if (Log[i] as TLogItem).LogType <> ltBottle then Continue;
2741     InsertItem := TLogItem.Create(Log[i] as TLogItem);
2742     try
2743       //\83A\83N\83V\83\87\83\93\82ª\97L\8cø\82Å\82 \82ê\82Î\83X\83N\83\8a\83v\83g\82Ì\95Ï\8a·\82µ\82È\82¢
2744       if TestAction then
2745         ErrorMes := ''
2746       else
2747         InsertItem.Script := ScriptTransForSSTP(InsertItem.Script, ErrorMes);
2748
2749       if ErrorMes <> '' then
2750       begin
2751         Res := MessageDlg('\83X\83N\83\8a\83v\83g\82É\96â\91è\82ª\82 \82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B' +
2752           '\8dÄ\90\82µ\82Ü\82·\82©?'#13#10 + ErrorMes, mtWarning,
2753           mbYesNoCancel, 0);
2754         if Res = mrNo then
2755           raise Exception.Create('Script Syntax Error')
2756         else if Res = mrCancel then
2757         begin
2758           InsertItem.Free;
2759           FBottleSstp.Clear;
2760           frmLog.AllBottleOpened;
2761           Break;
2762         end;
2763       end;
2764       //\83A\83N\83V\83\87\83\93\82ª\97L\8cø\82Å\82 \82ê\82Î\92Ê\8fí\8f\88\97\9d\8fÈ\97ª
2765       if TestAction then
2766         //\8c^\95Ï\8a·\82Æ\8eó\90M
2767         BottleCnv(InsertItem)
2768       else
2769       begin
2770         //\83`\83\83\83\93\83l\83\8b\83S\81[\83X\83g\91Î\8dô
2771         if InsertItem.Ghost = '' then
2772           if ChannelList.Channel[InsertItem.Channel] <> nil then
2773             InsertItem.Ghost := ChannelList.Channel[InsertItem.Channel].Ghost;
2774         FBottleSSTP.Push(InsertItem);
2775         frmLog.SetBottleState(InsertItem.MID, lsUnopened);
2776       end;
2777     except
2778       InsertItem.Free;
2779       Inc(errCount);
2780     end;
2781   end;
2782   if errCount > 0 then
2783     ShowMessage(Format('%d\8c\8f\82Ì\83{\83g\83\8b\82É\96â\91è\82ª\82 \82Á\82½\82½\82ß\8dÄ\90\82Å\82«\82Ü\82¹\82ñ\81B', [errCount]));
2784   FBottleSSTP.OnResendCountChange := BottleSstpResendCountChange;
2785   BottleSstpResendCountChange(self);
2786   frmLog.lvwLog.Invalidate;
2787 end;
2788
2789 procedure TfrmSender.actInsertCueExecute(Sender: TObject);
2790 begin
2791   LogInsertCue(false); // \92Ê\8fí\82Ì\98A\91±\8dÄ\90\82ð\82·\82é
2792 end;
2793
2794 function TfrmSender.ScriptTransForSSTP(const Script: String;
2795   out Error: String): String;
2796 var TransOpt: TScriptTransOptions;
2797 begin
2798   if Pref.NoTransURL then
2799     TransOpt := [toConvertURL, toNoChoice, toWaitScriptEnd]
2800   else
2801     TransOpt := [toConvertURL, toWaitScriptEnd];
2802   if Pref.IgnoreFrequentYenS then TransOpt := TransOpt + [toIgnoreFrequentYenS];
2803   if Pref.FixMessySurface then TransOpt := TransOpt + [toFixMessySurface];
2804   if Pref.HUTagTo01Tag then TransOpt := TransOpt + [toHUTagTo01Tag];
2805   Result := Script;
2806   Error := DoTrans(Result, TransOpt);
2807 end;
2808
2809 procedure TfrmSender.FormResize(Sender: TObject);
2810 var w: integer;
2811 begin
2812   // \83G\83f\83B\83^\81[\95\94\95ª\82Ì\83\8f\81[\83h\83\89\83b\83v\95\9d\82ð\92²\90®\82·\82é
2813   if memScript.ColWidth <> 0 then
2814   begin
2815     with memScript do
2816     begin
2817       w := Width - LeftMargin - ColWidth div 2;
2818       if ScrollBars in [ssVertical, ssBoth] then
2819         w := w - GetSystemMetrics(SM_CYVSCROLL);
2820       WrapOption.WrapByte := w div ColWidth;
2821     end;
2822   end;
2823 end;
2824
2825 procedure TfrmSender.actCopyExecute(Sender: TObject);
2826 begin
2827   memScript.CopyToClipboard;
2828 end;
2829
2830 procedure TfrmSender.actPasteExecute(Sender: TObject);
2831 begin
2832   memScript.PasteFromClipboard;
2833 end;
2834
2835 procedure TfrmSender.actCutExecute(Sender: TObject);
2836 begin
2837   memScript.CutToClipboard;
2838 end;
2839
2840 procedure TfrmSender.actSelectAllExecute(Sender: TObject);
2841 begin
2842   memScript.SelectAll;
2843 end;
2844
2845 procedure TfrmSender.actUndoExecute(Sender: TObject);
2846 begin
2847   memScript.Undo;
2848 end;
2849
2850 procedure TfrmSender.actRedoExecute(Sender: TObject);
2851 begin
2852   memScript.Redo;
2853 end;
2854
2855 function TfrmSender.IsSurfaceTag(const Script: String;
2856   var ID: integer): boolean;
2857 begin
2858   Result := false;
2859   if SsParser.Match(Script, '\s%d') = 3 then
2860   begin
2861     Result := true;
2862     ID := Ord(Script[3]) - Ord('0')
2863   end
2864   else if (Length(Script) > 0) and (SsParser.Match(Script, '\s[%D]') = Length(Script)) then
2865   begin
2866     Result := true;
2867     ID := StrToIntDef(SsParser.GetParam(Script, 1), 0);
2868   end;
2869 end;
2870
2871 procedure TfrmSender.memScriptMouseMove(Sender: TObject;
2872   Shift: TShiftState; X, Y: Integer);
2873 var id: integer;
2874     token: String;
2875 begin
2876   // \95Ò\8fW\83E\83B\83\93\83h\83E\82Å\83}\83E\83X\83|\83C\83\93\83g\82·\82é\82Æ\83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[
2877   if not Pref.SurfacePreviewOnScriptPoint then
2878     Exit;
2879   token := memScript.TokenStringFromPos(Point(X, Y));
2880   if IsSurfaceTag(token, id) then
2881   begin
2882     DoSurfacePreview(id, spEditor);
2883   end else
2884   begin
2885     frmSurfacePreview.HideAway;
2886   end;
2887 end;
2888
2889 procedure TfrmSender.DoSurfacePreview(Surface: integer;
2890   const Kind: TSurfacePreviewType);
2891 var Ghost: String;
2892     Bmp: TBitmap;
2893     CPos: TPoint;
2894 begin
2895   if cbxTargetGhost.ItemIndex > 0 then
2896     ghost := cbxTargetGhost.Text
2897   else
2898     ghost := '';
2899 {  \8eè\93®\82Ì\82Í\82¸
2900   else if FNowChannel <> '' then
2901     ghost := ChannelList.Channel[FNowChannel].Ghost;
2902 }
2903
2904   // \93ñ\8fd\95\\8e¦\82Ì\97}\90§
2905   if (FVisiblePreviewGhost = Ghost) and (FVisiblePreviewSurface = Surface) and
2906     not (frmSurfacePreview.IsHidden) then
2907   begin
2908     Exit;
2909   end;
2910
2911   if ghost <> '' then
2912   begin
2913     Bmp := TBitmap.Create;
2914     try
2915       if Spps.TryGetImage(ghost, Surface, Bmp) then
2916       begin
2917         case Kind of
2918           spHint:
2919             CPos := GetSurfacePreviewPositionHint(Bmp.Width, Bmp.Height);
2920           spEditor:
2921             CPos := GetSurfacePreviewPositionScriptPoint(Bmp.Width, Bmp.Height);
2922           else
2923             CPos := Point(0, 0);
2924         end;
2925         frmSurfacePreview.ShowPreview(Bmp, CPos.X, CPos.Y);
2926         FVisiblePreviewGhost := Ghost;
2927         FVisiblePreviewSurface := Surface;
2928       end else
2929         frmSurfacePreview.HideAway;
2930     finally
2931       Bmp.Free;
2932     end;
2933   end;
2934 end;
2935
2936 function TfrmSender.GetSurfacePreviewPositionHint(w, h: integer): TPoint;
2937 {var MousePoint: TPoint;
2938     MenuRect: TRect;}
2939 begin
2940   // \83T\81[\83t\83B\83X\83v\83\8c\83r\83\85\81[\83E\83B\83\93\83h\83E\82Ì\95\\8e¦\88Ê\92u\82ð\8c\88\92è\82·\82é
2941   // \91\97\90M\83E\83B\83\93\83h\83E\82Ì\88Ê\92u\82É\82æ\82Á\82Ä\82Í\96­\82È\82Æ\82±\82ë\82É\83\81\83j\83\85\81[\82ª\95\\8e¦\82³\82ê\82Ä\82¢\82é\82Ì\82Å
2942   // \88Ä\8aO\82â\82â\82±\82µ\82¢
2943   {GetCursorPos(MousePoint);
2944   OutputDebugString(PChar(IntToStr(FVisibleMenuItem.Count)));
2945   //if GetMenuItemRect(Self.Handle, FVisibleMenuItem.Items[0].Handle, 1, MenuRect) then ;
2946   Result := Point(MenuRect.Left-10, MenuRect.Top-10);}
2947   Result := GetSurfacePreviewPositionScriptPoint(w, h);
2948 end;
2949
2950 function TfrmSender.GetSurfacePreviewPositionScriptPoint(w, h: integer): TPoint;
2951 var MousePoint: TPoint;
2952 begin
2953   GetCursorPos(MousePoint);
2954   case Pref.SurfacePreviewOnScriptPointPosition of
2955     spspMainWindowRight:
2956       Result := Point(Self.Left + Self.Width, MousePoint.Y);
2957   else
2958       Result := Point(Self.Left - w, MousePoint.Y);
2959   end;
2960 end;
2961
2962 procedure TfrmSender.mnConstGroupClick(Sender: TObject);
2963 begin
2964   if (Sender is TMenuItem) then
2965     FVisibleMenuItem := Sender as TMenuItem;
2966 end;
2967
2968 procedure TfrmSender.actRecallScriptBufferExecute(Sender: TObject);
2969 begin
2970   if FScriptBuffer.Count = 0 then
2971     Exit;
2972   memScript.Lines.Assign(FScriptBuffer[0] as TStringList);
2973   EditerStatusChange;
2974   ShowHintLabel('\83X\83N\83\8a\83v\83g\82ð\8cÄ\82Ñ\8fo\82µ\82Ü\82µ\82½');
2975 end;
2976
2977 procedure TfrmSender.EditorPreview;
2978 var Ghost, Script: String;
2979 begin
2980   if frmEditorTalkShow <> nil then
2981     if frmEditorTalkShow.Visible then
2982     begin
2983       Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
2984       Ghost := '';
2985       if cbxTargetGhost.ItemIndex > 0 then
2986         Ghost := cbxTargetGhost.Text;
2987\8eè\93®\82Å\8ew\92è\82³\82ê\82é
2988       else if FNowChannel <> '' then
2989         Ghost := ChannelList.Channel[FNowChannel].Ghost;
2990 }
2991       frmEditorTalkShow.TalkShowFrame.View(Script, Ghost);
2992     end;
2993 end;
2994
2995 procedure TfrmSender.actEditorPreviewExecute(Sender: TObject);
2996 begin
2997   if frmEditorTalkShow <> nil then
2998     frmEditorTalkShow.Show
2999   else
3000   begin
3001     Application.CreateForm(TfrmEditorTalkShow, frmEditorTalkShow);
3002     frmEditorTalkShow.Show;
3003   end;
3004   EditorPreview;
3005 end;
3006
3007 // \83v\83\89\83O\83C\83\93\83\8a\83Z\83b\83g
3008 procedure TfrmSender.actResetPluginsExecute(Sender: TObject);
3009 begin
3010   Spps.ClearImagePool;
3011   Spps.LoadFromDirectory(FSppDir);
3012 end;
3013
3014 {
3015 procedure TfrmSender.IdSLPP20Connect(Sender: TObject);
3016 begin
3017   ShowHintLabel('SSTP Bottle\83T\81[\83o\82ª\8c©\82Â\82©\82è\82Ü\82µ\82½');
3018 end;
3019 }
3020
3021 // \83X\83N\83\8a\83v\83g\92\86\82Ì\83^\83O\82ð\92u\8a·\82·\82é
3022 // \83T\83C\83Y\89Â\95Ï\82Ì\94z\97ñ\83p\83\89\83\81\81[\83^\94Å
3023 function TfrmSender.TagReplace(Script: String; Before,
3024   After: array of String): String;
3025 var BeforeList, AfterList: TStringList;
3026     i: integer;
3027 begin
3028   BeforeList := TStringList.Create;
3029   AfterList  := TStringList.Create;
3030   try
3031     for i := Low(Before) to High(Before) do
3032       BeforeList.Add(Before[i]);
3033     for i := Low(After) to High(After) do
3034       AfterList.Add(After[i]);
3035     Result := TagReplace(Script, BeforeList, AfterList);
3036   finally
3037     BeforeList.Free;
3038     AfterList.Free;
3039   end;
3040 end;
3041
3042 // \83X\83N\83\8a\83v\83g\92\86\82Ì\83^\83O\82ð\92u\8a·\82·\82é
3043 // StringReplace\82Æ\88á\82Á\82Ä\90³\8am\82É\83^\83O\82É\83}\83b\83`\82µ\81A
3044 // \82Ü\82½\83p\83^\81[\83\93\82ð\95¡\90\94\8ew\92è\82Å\82«\82é(\92u\8a·\8cã\82Ì\8c\8b\89Ê\82ª\82Ü\82½\92u\8a·\82³\82ê\82½\82è\82µ\82È\82¢)
3045 function TfrmSender.TagReplace(Script: String; Before,
3046   After: TStrings): String;
3047 var i, j: integer;
3048     Flag, OldLeaveEscape, OldEscapeInvalidMeta: boolean;
3049     OldStr: String;
3050 begin
3051   Result := '';
3052   with SsParser do
3053   begin
3054     OldStr := InputString;
3055     OldLeaveEscape := LeaveEscape;
3056     OldEscapeInvalidMeta := EscapeInvalidMeta;
3057     LeaveEscape := true;
3058     EscapeInvalidMeta := false;
3059     InputString := Script;
3060   end;
3061   for i := 0 to SsParser.Count-1 do
3062   begin
3063     Flag := false;
3064     for j := 0 to Before.Count-1 do
3065     begin
3066       if (SsParser.MarkUpType[i] = mtTag) and (SsParser[i] = Before[j]) then
3067       begin
3068         Flag := true;
3069         Result := Result + After[j];
3070       end;
3071     end;
3072     if not Flag then
3073       Result := Result + SsParser[i];
3074   end;
3075   with SsParser do
3076   begin
3077     LeaveEscape := OldLeaveEscape;
3078     EscapeInvalidMeta := OldEscapeInvalidMeta;
3079     InputString := OldStr;
3080   end;
3081 end;
3082
3083 // WndProc\82ð\83I\81[\83o\81[\83\89\83C\83h\82µ\82Ä\81AFWM_TaskBarCraeted\82É
3084 // \91Î\89\9e\82·\82é
3085 procedure TfrmSender.WndProc(var Message: TMessage);
3086 begin
3087   if (Message.Msg = FWM_TaskBarCreated) and (FWM_TaskBarCreated <> 0) then
3088   begin
3089     TaskTray.Registered := false; // TTaskTray\82É\83^\83X\83N\83g\83\8c\83C\82ª\8fÁ\82¦\82½\82±\82Æ\82ð
3090                                   // \8bC\82Ã\82©\82¹\82é
3091     ChangeTaskIcon;
3092   end
3093   else
3094     inherited;
3095 end;
3096
3097 // \92u\8a·
3098 procedure TfrmSender.actReplaceExecute(Sender: TObject);
3099 var
3100   Form: TfrmStrReplaceDialog;
3101   Lines: String;
3102   Options: TReplaceFlags;
3103 begin
3104   Application.CreateForm(TfrmStrReplaceDialog, Form);
3105   try
3106     if Form.Execute then
3107     begin
3108       with Form.Pair do
3109       begin
3110         Lines := memScript.Lines.Text;
3111         Options := [rfReplaceAll];
3112         if IgnoreCase then
3113           Options := Options + [rfIgnoreCase];
3114         if UseRegExp then
3115           Lines := StringReplaceRegExp(Lines, BeforeStr, AfterStr, Options)
3116         else
3117           Lines := StringReplace(Lines, BeforeStr, AfterStr, Options);
3118       end;
3119       if Lines <> memScript.Lines.Text then
3120       begin
3121         memScript.SelectAll;
3122         memScript.SelText := Lines;
3123       end;
3124     end;
3125   finally
3126     Form.Release;
3127   end;
3128 end;
3129
3130 procedure TfrmSender.actSendToEditorExecute(Sender: TObject);
3131 var Log: TLogItem;
3132 begin
3133   if frmLog.lvwLog.Selected = nil then Exit;
3134   Log := frmLog.SelectedBottleLog[frmLog.lvwLog.Selected.Index] as TLogItem;
3135   if Log = nil then Exit;
3136   CopyFromLogToEditor(Log);
3137 end;
3138
3139 procedure TfrmSender.actSendToLogWindowExecute(Sender: TObject);
3140 var Ghost, Script: String;
3141 begin
3142   YenETrans;
3143   Script := StringReplace(GetScriptText, #13#10, '', [rfReplaceAll]);
3144   if cbxTargetGhost.ItemIndex > 0 then
3145     Ghost := cbxTargetGhost.Text
3146   else
3147     Ghost := '';
3148   frmLog.AddCurrentScriptLog('\83N\83\8a\83b\83v', Script, ClipChannel, '', Ghost, Now(), 0, 0);
3149   ClearEditor;
3150 end;
3151
3152 procedure TfrmSender.memScriptDragOver(Sender, Source: TObject; X,
3153   Y: Integer; State: TDragState; var Accept: Boolean);
3154 begin
3155   // \83\8d\83O\83E\83B\83\93\83h\83E\82©\82ç\82Ì\83\8d\83O\83A\83C\83e\83\80\82Ì\92¼\90ÚD&D\82ð\8b\96\89Â\82·\82é
3156   if Source is TBottleLogDragObject then
3157     Accept := (Source as TBottleLogDragObject).LogItem.LogType = ltBottle
3158 end;
3159
3160 procedure TfrmSender.memScriptDragDrop(Sender, Source: TObject; X,
3161   Y: Integer);
3162 var Src: TBottleLogDragObject;
3163     Log: TLogItem;
3164 begin
3165   // \83\8d\83O\83E\83B\83\93\83h\83E\82©\82ç\83\8d\83O\83A\83C\83e\83\80\82ðD&D\82µ\82Ä\82­\82é
3166   if not (Source is TBottleLogDragObject) then
3167     Exit;
3168   if (Source as TBottleLogDragObject).LogItem.LogType <> ltBottle then
3169     Exit;
3170   Src := Source as TBottleLogDragObject;
3171   Log := Src.LogItem;
3172   CopyFromLogToEditor(Log);
3173 end;
3174
3175 procedure TfrmSender.CopyFromLogToEditor(Log: TLogItem);
3176 var
3177   Ghost: string;
3178 begin
3179   if Log.LogType <> ltBottle then Exit;
3180   frmSender.actClear.Execute; // \8c»\8dÝ\82Ì\83X\83N\83\8a\83v\83g\82ð\83N\83\8a\83b\83v\82·\82é(\90Ý\92è\82É\82æ\82Á\82Ä)
3181   memScript.Lines.Clear;
3182   memScript.Lines.Add(Log.Script);
3183   SetFileName(Log.MID, false);  //\83^\83C\83g\83\8b\82¾\82¯\95Ï\8dX
3184   SetFileModified(false);       //\95Ï\8dX\96³\82µ\82É
3185   FScriptBackModified := false; //\8e©\93®\95Û\91\88ê\8e\9e\92â\8e~
3186   Ghost := Log.Ghost;
3187   //\83`\83\83\83\93\83l\83\8b\83S\81[\83X\83g\91Î\8dô
3188   if Ghost = '' then
3189     if ChannelList.Channel[Log.Channel] <> nil then
3190       Ghost := ChannelList.Channel[Log.Channel].Ghost;
3191   if Ghost <> '' then
3192   begin
3193     // \83S\81[\83X\83g\96¼\82ð\83{\83b\83N\83X\82É\93ü\82ê\82é
3194     // \96³\97\9d\96î\97\9d\83S\81[\83X\83g\96¼\82ð\92Ç\89Á\82µ\82Ä\82©\82ç\8dÄ\8d\\92z\82·\82é\82±\82Æ\82Å
3195     // \96³\97\9d\96î\97\9d\83S\81[\83X\83g\96¼\82ª\83{\83b\83N\83X\82É\93ü\82é
3196     cbxTargetGhost.Items.Add(Ghost);
3197     cbxTargetGhost.ItemIndex := cbxTargetGhost.Items.Count-1;
3198     UpdateIfGhostBox;
3199     cbxTargetGhost.Invalidate;
3200   end else
3201     cbxTargetGhost.ItemIndex := 0; // 'CH\90\84\8f§'\82É\82·\82é
3202   memScript.SetFocus;
3203 end;
3204
3205 procedure TfrmSender.actDeleteLogItemExecute(Sender: TObject);
3206 begin
3207   // \83\8d\83O\83E\83B\83\93\83h\83E\82Ì\8cÂ\95Ê\83\8d\83O\82ð\8dí\8f\9c\82·\82é
3208   if frmLog.SelectedBottleLog = nil then
3209     Exit;
3210   if frmLog.lvwLog.Selected = nil then
3211     Exit;
3212   frmLog.SelectedBottleLog.Delete(frmLog.lvwLog.Selected.Index);
3213   frmLog.UpdateWindow;
3214   frmLog.lvwLogChange(Self, nil, ctState);
3215   frmLog.SelectedBottleLog.LogModified := true; // \95Ï\8dX\82³\82ê\82½
3216 end;
3217
3218 procedure TfrmSender.ClearEditor;
3219 var TmpScript: String;
3220     Position: Integer;
3221     DoSaveBuffer: boolean;
3222     SavedScript: TStringList;
3223 begin
3224   // \90Ý\92è\82É\82æ\82è\83N\83\8a\83A\8e\9e\82É\83t\83@\83C\83\8b\83Z\81[\83u\82·\82é\82©\8am\94F\82·\82é
3225   // \8e©\93®\83N\83\8a\83b\83v\82ª\97L\8cø\82Å\82 \82ê\82Î\83X\83L\83b\83v\82·\82é
3226   if (NOT Pref.NotCheckClear) AND (NOT Pref.AutoClip) then
3227     if CheckFileModified(Self) = idCancel then abort;
3228   // \83X\83N\83\8a\83v\83g\82Ì\83N\83\8a\83A
3229   // \82Ü\82¸\81A\83X\83N\83\8a\83v\83g\83N\83\8a\83A\83o\83b\83t\83@\82É\8c»\8dÝ\82Ì\83X\83N\83\8a\83v\83g\82ð\95Û\91\82·\82é
3230   DoSaveBuffer := false;
3231   if FScriptBuffer.Count = 0 then
3232     DoSaveBuffer := true
3233   else if (FScriptBuffer[0] as TStringList).Text <> GetScriptText then
3234     DoSaveBuffer := true;
3235   if (GetScriptText = Pref.DefaultScript) or (GetScriptText = '') then
3236     DoSaveBuffer := false;
3237   if DoSaveBuffer then
3238   begin
3239     SavedScript := TStringList.Create;
3240     SavedScript.Text := GetScriptText;
3241     FScriptBuffer.Insert(0, SavedScript);
3242   end;
3243   if FScriptBuffer.Count >= 4 then
3244     FScriptBuffer.Delete(FScriptBuffer.Count-1);
3245   actRecallScriptBuffer.Enabled := FScriptBuffer.Count > 0;
3246
3247   TmpScript := Pref.DefaultScript;
3248   Position := Pos('|', TmpScript);
3249   if Position < 1 then Position := 1;
3250   TmpScript := StringReplace(TmpScript, '|', '', []);
3251   memScript.Lines.Text := TmpScript;
3252   Sendmessage(memScript.Handle, WM_VSCROLL, SB_LINEUP, 0);
3253   memScript.SelStart := Position-1;
3254
3255   if Visible then memScript.SetFocus;
3256 //  FScriptModified := false;
3257   FScriptBackModified := false;     // \8e©\93®\95Û\91\88ê\8e\9e\92â\8e~
3258   SetFileName(NewFileTitle, true);  // \83t\83@\83C\83\8b\82ð\90V\8bK\88µ\82¢\82É\82·\82é
3259   SetFileModified(false);           // \95Ï\8dX\96³\82µ
3260   EditerStatusChange;               // \83X\83e\81[\83^\83X\8dX\90V
3261 end;
3262
3263 procedure TfrmSender.AppendTextLog(const FileName, Line: String; FAppend: boolean);
3264 var
3265   F: TextFile;
3266 begin
3267   //\91\97\90M\83\8d\83O\95Û\91
3268   try
3269     ForceDirectories(ExtractFileDir(FileName));
3270     AssignFile(F, FileName);
3271     if FileExists(FileName) AND FAppend then  // \92Ç\8bL\82©\8fã\8f\91\82«\94»\92è
3272       Append(F)
3273     else
3274       Rewrite(F);
3275     WriteLn(F, Line);
3276     Flush(F);
3277     CloseFile(F);
3278   except
3279     on E: Exception do
3280       frmLog.AddCurrentSystemLog('SYSTEM', '\83e\83L\83X\83g\83\8d\83O\95Û\91\82É\8e¸\94s\81F'+E.Message);
3281   end;
3282 end;
3283
3284 procedure TfrmSender.AppendXMLLog(const FileName: String; Args: THeadValue);
3285 var
3286   F: TFileStream;
3287   Buf: String;
3288   P: integer;
3289   Impl: TDomImplementation;
3290   Parser: TXmlToDomParser;
3291   DOM: TdomDocument;
3292 begin
3293   try // Long try block to handle all kinds of exception in this method
3294     if not FileExists(FileName) then
3295     begin
3296       // Create empty XML log file
3297       Impl := TDomImplementation.create(nil);
3298       try
3299         ForceDirectories(ExtractFileDir(FileName));
3300         Parser := TXmlToDomParser.create(nil);
3301         Parser.DOMImpl := Impl;
3302         try
3303           try
3304             DOM := Parser.fileToDom(ExtractFilePath(Application.ExeName)+'xbtl.dat');
3305             with DOM do
3306             begin
3307               documentElement.setAttribute('saved',
3308                 FormatDateTime('yy/mm/dd hh:nn:ss', Now));
3309               documentElement.setAttribute('generator', VersionString);
3310               documentElement.setAttribute('version', '1.0');
3311             end;
3312             // \82±\82ê\82Í\96¾\8e¦\93I\82ÉFree\82µ\82È\82­\82Ä\82æ\82¢
3313             F := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
3314             try
3315               DOM.writeCodeAsShiftJIS(F);
3316             finally
3317               F.Free;
3318             end;
3319           except
3320             frmLog.AddCurrentSystemLog('SYSTEM', 'XML\83\8d\83O\95Û\91\82É\8e¸\94s\82µ\82Ü\82µ\82½');
3321           end;
3322         finally
3323           Parser.DOMImpl.freeDocument(DOM);
3324           Parser.Free;
3325         end;
3326       finally;
3327         Impl.Free;
3328       end;
3329     end;
3330     F := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
3331     try
3332       P := -11;
3333       SetLength(Buf, 12);
3334       while P > -100 do
3335       begin
3336         F.Seek(P, soFromEnd);
3337         F.Read(Buf[1], 12);
3338         if Buf = '</bottlelog>' then
3339           Break;
3340         Dec(P);
3341       end;
3342       if P = -100 then
3343         raise Exception.Create(FileName + ' is not a valid XML bottle log file')
3344       else
3345       begin
3346         F.Seek(P, soFromEnd);
3347         Buf := Format('<message mid="%s">', [Args['MID']]);
3348         Buf := Buf + Format('<date>%s</date>', [FormatDateTime('yy/mm/dd hh:nn:ss', Now)]);
3349         Buf := Buf + Format('<channel>%s</channel>', [XMLEntity(Args['Channel'])]);
3350         Buf := Buf + Format('<script>%s</script>', [XMLEntity(Args['Script'])]);
3351         Buf := Buf + '<votes>0</votes><agrees>0</agrees>';
3352         Buf := Buf + Format('<ghost>%s</ghost>', [XMLEntity(Args['IfGhost'])]);
3353         Buf := Buf + '</message>';
3354         Buf := Buf + '</bottlelog>';
3355         F.Write(Buf[1], Length(Buf));
3356       end;
3357     finally
3358       F.Free;
3359     end;
3360   except
3361     on E: Exception do
3362       frmLog.AddCurrentSystemLog('SYSTEM', 'XML\83\8d\83O\95Û\91\82É\8e¸\94s\82µ\82Ü\82µ\82½:'+E.Message);
3363   end;
3364 end;
3365
3366 procedure TfrmSender.memScriptSelectionChange(Sender: TObject;
3367   Selected: Boolean);
3368 var
3369   SelText: String;
3370 begin
3371   SelText := memScript.SelText;
3372   if SelText <> '' then
3373   begin
3374     StatusBar.Panels[PanelBytes].Text := Format('(%d\83o\83C\83g)', [Length(SelText)]);
3375   end else
3376   begin
3377     EditerStatusChange;
3378   end;
3379 end;
3380
3381 function TfrmSender.ReplaceSurface(Script: String;
3382   Params: TCollection): String;
3383 var
3384   Flag, OldLeaveEscape, OldEscapeInvalidMeta: boolean;
3385   OldStr, Tag: String;
3386   i, j, k, Cur: integer;
3387   Item: TSurfaceReplaceItem;
3388   Before: TSurfaceReplaceBeforeItem;
3389 begin
3390   Result := '';
3391   Cur := 0;
3392   with SsParser do
3393   begin
3394     OldStr := InputString;
3395     OldLeaveEscape := LeaveEscape;
3396     OldEscapeInvalidMeta := EscapeInvalidMeta;
3397     LeaveEscape := true;
3398     EscapeInvalidMeta := false;
3399     InputString := Script;
3400   end;
3401   for i := 0 to SsParser.Count-1 do
3402   begin
3403     if SsParser.MarkUpType[i] <> mtTag then
3404     begin
3405       Result := Result + SsParser.Str[i];
3406       Continue;
3407     end;
3408     Tag := SsParser.Str[i];
3409     if SsParser.Match(Tag, '\s%d') = 2 then
3410       Cur := Ord(Tag[3]) - Ord('0')
3411     else if SsParser.Match(Tag, '\s[%D]') > 0 then
3412       Cur := StrToInt(SsParser.GetParam(Tag, 1))
3413     else
3414     begin
3415       Result := Result + Tag;
3416       Continue;
3417     end;
3418     Flag := false;
3419     for j := 0 to Params.Count-1 do
3420     begin
3421       Item := Params.Items[j] as TSurfaceReplaceItem;
3422       for k := 0 to Item.Before.Count-1 do
3423       begin
3424         Before := Item.Before.Items[k] as TSurfaceReplaceBeforeItem;
3425         if (Cur >= Before.FromNo) and (Cur <= Before.ToNo) then
3426         begin
3427           Flag := true;
3428           Result := Result + Format('\s[%d]', [Item.After]);
3429           Break;
3430         end;
3431       end;
3432       if Flag then
3433         Break;
3434     end;
3435     if not Flag then
3436       Result := Result + Tag;
3437   end;
3438   with SsParser do
3439   begin
3440     LeaveEscape := OldLeaveEscape;
3441     EscapeInvalidMeta := OldEscapeInvalidMeta;
3442     InputString := OldStr;
3443   end;
3444 end;
3445
3446 procedure TfrmSender.WMQueryEndSession(var msg: TWMQueryEndSession);
3447 begin
3448   // Windows\82ª\8fI\97¹\82µ\82æ\82¤\82Æ\82µ\82Ä\82¢\82é\82Ì\82ð\8a´\92m\82·\82é
3449   FEndSession := true;
3450   inherited;
3451 end;
3452
3453 {
3454 procedure TfrmSender.IdSLPP20ConnectFailed(Sender: TObject);
3455 begin
3456   Added := false;
3457   if FBeginConnectFailCount = 0 then
3458   begin
3459     Beep;
3460     if Pref.UseHttpProxy then
3461       frmMessageBox.ShowMessage('HTTP Proxy\82ð\92Ê\82\82ÄSSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B'#13#10 +
3462                   '\83l\83b\83g\83\8f\81[\83N\82Ì\8fó\91Ô\81EProxy\82Ì\8fó\91Ô\82ð\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
3463                   '\82 \82é\82¢\82Í\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B')
3464     else
3465       frmMessageBox.ShowMessage('SSTP Bottle\83T\81[\83o\82É\90Ú\91±\82Å\82«\82Ü\82¹\82ñ\82Å\82µ\82½\81B'#13#10 +
3466                   '\83l\83b\83g\83\8f\81[\83N\82É\8cq\82ª\82Á\82Ä\82¢\82é\82©\8am\94F\82µ\82Ä\82­\82¾\82³\82¢\81B'#13#10 +
3467                   '\82 \82é\82¢\82Í\83T\81[\83o\82ª\83_\83E\83\93\82µ\82Ä\82¢\82é\89Â\94\\90«\82ª\82 \82è\82Ü\82·\81B');
3468   end;
3469   ShowHintLabel('SSTP Bottle Server\90Ú\91±\82É\8e¸\94s\82µ\82Ü\82µ\82½', WarningColor);
3470   Inc(FBeginConnectFailCount);
3471 end;
3472 }
3473
3474 procedure TfrmSender.BuildReplaceMenu(Root: TMenuItem);
3475 var
3476   i: integer;
3477   Presets: TReplacePresetCollection;
3478   NewItem: TMenuItem;
3479 begin
3480   Root.Clear;
3481   Presets := Pref.ReplacePresets.Presets;
3482   for i := 0 to Presets.Count-1 do
3483   begin
3484     NewItem := TMenuItem.Create(Root);
3485     with NewItem do
3486     begin
3487       Caption := Presets[i].Title;
3488       ShortCut := Presets[i].ShortCut;
3489       AutoHotkeys := maManual;
3490       Hint := Presets[i].Pairs.StringExpression;
3491       Tag := i;
3492       OnClick := mnPresetReplaceClick;
3493     end;
3494     Root.Add(NewItem);
3495   end;
3496   Root.Enabled := Presets.Count > 0;
3497 end;
3498
3499 procedure TfrmSender.mnPresetReplaceClick(Sender: TObject);
3500 var
3501   Preset: TReplacePreset;
3502   Lines, New: string;
3503 begin
3504   // \83v\83\8a\83Z\83b\83g\92u\8a·\82ð\8eÀ\8ds
3505   Preset := Pref.ReplacePresets.Presets[(Sender as TMenuItem).Tag];
3506   Lines := memScript.Lines.Text;
3507   New := Preset.Pairs.ExecuteReplace(Lines);
3508   if New <> Lines then
3509   begin
3510     memScript.SelectAll;
3511     memScript.SelText := New;
3512   end;
3513   if Preset.ConfirmAfterReplace then
3514   begin
3515     btnConfirm.Click;
3516   end;
3517 end;
3518
3519 procedure TfrmSender.BottleCnv(Log: TLogItem);
3520 var
3521   HeadValue: THeadValue;
3522 begin
3523   //HeadValue\8c^\82Ö
3524   HeadValue := THeadValue.Create;
3525   HeadValue['MID'] := Log.MID;
3526   HeadValue['Channel'] := Log.Channel;
3527 //  HeadValue['SEND'] := 'SSTP/1.4';
3528 //  HeadValue['Sender'] := 'SSTP Bottle ' + Log.Channel;
3529   HeadValue['IfGhost'] := Log.Ghost;
3530   HeadValue['Script'] := Log.Script;
3531 //  HeadValue['Charset'] := 'Shift_JIS';
3532 //  HeadValue['DialogMessage'] := Log.Script;
3533   try
3534     //\83\81\83b\83Z\81[\83W\8eó\90M\8f\88\97\9d\82Ö
3535     DispatchBottle(HeadValue, Log.LogTime, Log.Votes, Log.Agrees);
3536   finally
3537     HeadValue.Free;
3538   end;
3539 end;
3540
3541 procedure TfrmSender.SetScriptAutoBackUp;
3542 begin
3543   //\83o\83b\83N\83A\83b\83v\83^\83C\83}\81[\82Ö\92l\82Ì\83Z\83b\83g
3544   frmSender.ScriptBackUp.Enabled := Pref.ScriptBackUp;
3545   frmSender.ScriptBackUp.Interval := Pref.ScriptBackUpTime * 60000;
3546 end;
3547
3548 procedure TfrmSender.ScriptBackUpTimer(Sender: TObject);
3549 var
3550   Script: string;
3551 begin
3552   //\83X\83N\83\8a\83v\83g\82Ì\8e©\93®\83o\83b\83N\83A\83b\83v
3553   if FScriptBackModified then
3554   begin
3555     Script := FormatDateTime('yy/mm/dd hh:nn:ss', Now) + #13#10 + GetScriptText;
3556     AppendTextLog(ExtractFilePath(Application.ExeName) + AutoSaveFile,
3557       Script, Pref.ScriptBackUpMode);
3558     ShowHintLabel('\83o\83b\83N\83A\83b\83v\8eÀ\8ds');
3559     FScriptBackModified := False;
3560   end;
3561 end;
3562
3563 procedure TfrmSender.UpdateChannelList;
3564 var
3565   Ch: TChannelListItem;
3566   i: integer;
3567 begin
3568   // \83`\83\83\83\93\83l\83\8b\83S\81[\83X\83g\92è\8b`
3569   ChannelList.Clear;
3570   // \83t\83\89\83O\82ð\8c©\82Ä\94»\92f
3571   if NOT Pref.GhostCh then exit;
3572   if (Pref.GhostChList.Count mod 2) = 1 then
3573   begin
3574     Pref.GhostChList.Add(''); // \95s\91«\82µ\82Ä\82¢\82é\82Ì\82Å\93K\93\96\82É\92Ç\89Á
3575     ShowMessage('\83`\83\83\83\93\83l\83\8b\82ð\8dÄ\90Ý\92è\82µ\82Ä\82­\82¾\82³\82¢');
3576     exit;
3577   end;
3578   i := 0;
3579   while i < Pref.GhostChList.Count-1 do
3580   begin
3581     Ch := TChannelListItem.Create;
3582     Ch.Name    := Pref.GhostChList.Strings[i];
3583     Ch.Ghost   := Pref.GhostChList.Strings[i+1];
3584     Ch.Info    := '';
3585     Ch.NoPost  := false;
3586     Ch.Members := 0;
3587     Ch.WarnPost:= false;
3588     ChannelList.Add(Ch);
3589     i := i + 2;
3590   end;
3591 end;
3592
3593 procedure TfrmSender.UpdateJoinChannelList;
3594 begin
3595   UpdateChannelList;  // \83`\83\83\83\93\83l\83\8b\90Ý\92è
3596   with tabChannel do  // \96¢\8eg\97p
3597   begin
3598     OnChange := nil;
3599     Tabs.BeginUpdate;
3600     Tabs.Clear;
3601     Tabs.EndUpdate;
3602     actSend.Hint := Format('\91\97\90M|%s', [SendButtonLongHint]);
3603     actNextChannel.Enabled := false;
3604     actPrevChannel.Enabled := false;
3605     OnChange := tabChannelChange;
3606   end;
3607 end;
3608
3609 procedure TfrmSender.PerformFileOpen(const AFileName: string);
3610 begin
3611   // \8eÀ\8dÛ\82É\83t\83@\83C\83\8b\82ð\8aJ\82­
3612   Screen.Cursor := crHourGlass;
3613   try
3614     memScript.Lines.LoadFromFile(AFileName);
3615     SetFileModified(false);
3616     SetFileName(AFileName, true);
3617     Pref.TextDir := ExtractFileDir(AFileName);
3618   except
3619     on E: Exception do
3620     begin
3621       ShowMessage('\83G\83\89\81[:'#13#10#13#10 + E.Message);
3622       SetFileName(NewFileTitle, true);  // \8e¸\94s\82µ\82½\8e\9e\82Í\83^\83C\83g\83\8b\8f\89\8aú\89»\81B
3623     end;
3624   end;
3625   Screen.Cursor := crDefault;
3626   memScript.SetFocus;
3627   EditerStatusChange;
3628 end;
3629
3630 procedure TfrmSender.PerformFileSave(const AFileName: string);
3631 begin
3632   // \8eÀ\8dÛ\82É\95Û\91\82·\82é
3633   Screen.Cursor := crHourGlass;
3634   try
3635     memScript.Lines.SaveToFile(AFileName);
3636     SetFileModified(false);
3637     Pref.TextDir := ExtractFileDir(AFileName);
3638   except
3639     on E: Exception do
3640       ShowMessage('\83G\83\89\81[:'#13#10#13#10 + E.Message);
3641   end;
3642   Screen.Cursor := crDefault;
3643 end;
3644
3645 procedure TfrmSender.actFileOpenExecute(Sender: TObject);
3646 begin
3647   // \8aJ\82­
3648   if CheckFileModified(Self) = idCancel then exit;
3649   OpenDialog.InitialDir := Pref.TextDir;
3650   if OpenDialog.Execute then
3651     if CheckFileExt(OpenDialog.FileName) then // \8ag\92£\8eq\82Ì\83`\83F\83b\83N
3652       PerformFileOpen(OpenDialog.FileName);
3653 end;
3654
3655 procedure TfrmSender.SetFileName(const FileName: String; const Value: boolean);
3656 begin
3657   // \83^\83C\83g\83\8b\95Ï\8dX\82Æ\83t\83@\83C\83\8b\83p\83X\83Z\83b\83g
3658   // \82à\82µ\81A\91æ\93ñ\88ø\90\94\82ªfalse\82È\82ç\83^\83C\83g\83\8b\82¾\82¯\95Ï\8dX
3659   if Value then FFileName := FileName;
3660   Self.Caption := Format('%s - %s', [ExtractFileName(FileName), FOriginalCaption]);
3661 end;
3662
3663 function TfrmSender.CheckFileModified(Sender: TObject): integer;
3664 var
3665   Res: integer;
3666 begin
3667   // \83t\83@\83C\83\8b\82Ì\95Ï\8dX\82ð\8am\94F
3668   // Result := idCancel\82Å\8fI\97¹\91j\8e~
3669   if FFileModified then
3670   begin
3671     Res := MessageDlg(Format('\83t\83@\83C\83\8b %s \82Í\95Ï\8dX\82³\82ê\82Ä\82¢\82Ü\82·\81B'#13#10#13#10 +
3672       '\95Û\91\82µ\82Ü\82·\82©\81H', [FFileName]), mtConfirmation, mbYesNoCancel, 0);
3673     if Res = idYes then Res := FileSave(Self);
3674   end else
3675     Res := idNo;
3676   Result := Res;
3677 end;
3678
3679 function TfrmSender.FileSave(Sender: TObject): integer;
3680 var
3681   Res: integer;
3682 begin
3683   // \8fã\8f\91\82«
3684   if FFileName = NewFileTitle then
3685     Res := FileSaveAs(Sender) //\83p\83X\96¼\82ª\8ew\92è\82³\82ê\82Ä\82¢\81¨\90V\8bK
3686   else
3687   begin
3688     PerformFileSave(FFileName);
3689     Res := idNo;
3690   end;
3691   Result := Res;
3692 end;
3693
3694 function TfrmSender.FileSaveAs(Sender: TObject): integer;
3695 var
3696   Res: integer;
3697 begin
3698   // \96¼\91O\82ð\95t\82¯\82Ä\95Û\91
3699   Res := idYes;
3700   SaveDialog.FileName := ExtractFileName(FFileName);
3701   SaveDialog.InitialDir := Pref.TextDir;
3702   if SaveDialog.Execute then
3703   begin
3704     if CheckFileExt(SaveDialog.FileName) = false then // \8ag\92£\8eq\83`\83F\83b\83N
3705     begin
3706       Res := idCancel;
3707       abort;
3708     end;
3709     if FileExists(SaveDialog.FileName) then
3710       Res := MessageDlg(Format('%s \82Í\8aù\82É\91\8dÝ\82µ\82Ä\82¢\82Ü\82·\81B'#13#10 + '\8fã\8f\91\82«\82µ\82Ü\82·\82©\81H',
3711         [SaveDialog.FileName]), mtConfirmation, mbYesNoCancel, 0);
3712     if Res = idYes then
3713     begin
3714       PerformFileSave(SaveDialog.FileName);
3715       SetFileName(SaveDialog.FileName, true);
3716     end;
3717   end else
3718     Res := idCancel;
3719   Result := Res;
3720 end;
3721
3722 procedure TfrmSender.actFileSaveAsExecute(Sender: TObject);
3723 begin
3724   // \96¼\91O\82ð\95t\82¯\82Ä\95Û\91\8cÄ\82Ñ\8fo\82µ
3725   FileSaveAs(Self);
3726 end;
3727
3728 procedure TfrmSender.actFileSaveExecute(Sender: TObject);
3729 begin
3730   // \8fã\8f\91\82«\95Û\91\8cÄ\82Ñ\8fo\82µ
3731   FileSave(Self);
3732 end;
3733
3734 procedure TfrmSender.SetFileModified(const Value: boolean);
3735 begin
3736   // \83t\83@\83C\83\8b\95Ï\8dX\83t\83\89\83O\82Æ\95\\8e¦\95Ï\8dX
3737   if Value then
3738     StatusBar.Panels[PanelConnecting].Text := '\95Ï\8dX'
3739   else
3740     StatusBar.Panels[PanelConnecting].Text := '';
3741   FFileModified := Value;
3742 end;
3743
3744 procedure TfrmSender.OpenBrowser(const Url: string);
3745 var
3746   Command: string;
3747 begin
3748   if Pref.BrowserExeName = '' then
3749   begin
3750     ShellExecute(Handle, 'open', PChar(Url), nil, nil, SW_SHOW);
3751   end else
3752   begin
3753     Command := Pref.BrowserExeName + ' ' + Url;
3754     WinExec(PChar(Command), SW_SHOW);
3755   end;
3756 end;
3757
3758 function TfrmSender.CheckFileExt(const AFileName: string): boolean;
3759 var
3760   Res: boolean;
3761 begin
3762   // \8ag\92£\8eq.bak\82Ì\83t\83@\83C\83\8b\82Í\93Ç\8f\91\82«\82µ\82È\82¢\81B
3763   Res := true;
3764   if LowerCase(ExtractFileExt(AFileName)) = '.bak' then
3765   begin
3766     beep;
3767     ShowMessage('\8ag\92£\8eqbak\82Í\88µ\82¦\82Ü\82¹\82ñ\81B'#13#10 + '\91¼\82Ì\83G\83f\83B\83^\82ð\8eg\97p\82µ\82Ä\82­\82¾\82³\82¢\81B');
3768     Res := false;
3769   end;
3770   Result := Res;
3771 end;
3772
3773 {$IFDEF PASS}
3774 procedure TfrmSender.CopyDataMessage(var WMCopyData: TWMCopyData);
3775 var
3776   Param: string;
3777   HeadValue: THeadValue;
3778 begin
3779   // \83e\83X\83g\97p
3780   if WMCopyData.CopyDataStruct.dwData = 1 then
3781   begin
3782     Param := PChar(WMCopyData.CopyDataStruct.lpData);
3783     HeadValue := THeadValue.Create(Param);
3784     try
3785       if HeadValue['Script'] <> '' then
3786         DispatchBottle(HeadValue, Now(), 0, 0)
3787       else if HeadValue['Type'] = 'Vote' then
3788         frmLog.VoteLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0))
3789       else if HeadValue['Type'] = 'Agree' then
3790         frmLog.AgreeLog(HeadValue['MID'], StrToIntDef(HeadValue['Num'], 0))
3791       else if (HeadValue['Num'] <> '') AND (HeadValue['Channel'] = '') AND
3792         (HeadValue['Entry'] = '') then
3793           StatusBar.Panels[PanelMembers].Text := HeadValue['Num'] + '\90l';
3794     finally
3795       HeadValue.Free;
3796     end;
3797   end;
3798 end;
3799 {$ENDIF}
3800
3801 end.