OSDN Git Service

PosをAnsiPosに変更(2バイト文字対策)
[gikonavigoeson/gikonavi.git] / res / ExternalBoardPlugIn / MachiBBSPlugIn.dpr
1 library MachiBBSPlugIn;
2
3 {
4         MachiBBSBoardPlugIn
5         \82Ü\82¿BBS\8f\88\97\9d\83\86\83j\83b\83g
6 }
7
8 uses
9         Windows, SysUtils, Classes, Math, DateUtils,
10         IdURI,MojuUtils,
11         PlugInMain in 'PlugInMain.pas',
12         ThreadItem in 'ThreadItem.pas',
13         BoardItem in 'BoardItem.pas',
14         FilePath in 'FilePath.pas';
15
16 {$R *.res}
17
18 type
19         // =========================================================================
20         // TMachiBBSThreadItem
21         // =========================================================================
22         TMachiBBSThreadItem = class(TThreadItem)
23         private
24                 FIsTemporary    : Boolean;
25                 FDat                                    : TStringList;
26
27         public
28                 constructor     Create( inInstance : DWORD );
29                 destructor      Destroy; override;
30
31         private
32                 function        Download : TDownloadState;
33                 function        Write( inName : string; inMail : string; inMessage : string ) : TDownloadState;
34                 function        GetRes( inNo : Integer ) : string;
35                 function        GetHeader( inOptionalHeader : string ) : string;
36                 function        GetFooter( inOptionalFooter : string ) : string;
37                 function        GetBoardURL : string;
38
39                 procedure       To2chDat( ioHTML : TStringList; inStartNo : Integer = 1 );
40                 procedure       LoadDat;
41                 procedure       FreeDat;
42         end;
43
44         // =========================================================================
45         // TMachiBBSBoardItem
46         // =========================================================================
47         TMachiBBSBoardItem = class(TBoardItem)
48         private
49                 FIsTemporary    : Boolean;
50                 FDat                                    : TStringList;
51
52         public
53                 constructor     Create( inInstance : DWORD );
54                 destructor      Destroy; override;
55
56         private
57                 function        Download : TDownloadState;
58                 function        CreateThread( inSubject : string; inName : string; inMail : string; inMessage : string ) : TDownloadState;
59                 function        ToThreadURL( inFileName : string ) : string;
60                 procedure       EnumThread( inCallBack : TBoardItemEnumThreadCallBack );
61
62                 function        SubjectURL : string;
63         end;
64
65         // =========================================================================
66         // \83T\83u\83W\83F\83N\83g\83\8c\83R\81[\83h
67         // =========================================================================
68         TSubjectRec = record
69                 FFileName: string;
70                 FTitle: string;
71                 FCount: Integer;
72         end;
73
74 const
75         LOG_DIR                                         = 'MachiBBS\';
76         SUBJECT_NAME                    = 'subject.txt';
77
78         PLUGIN_NAME                             = 'MachiBBSPlugIn';
79         MAJOR_VERSION                   = 1;
80         MINOR_VERSION                   = 0;
81         RELEASE_VERSION         = 'beta';
82         REVISION_VERSION        = 11;
83
84 // =========================================================================
85 // \8eG\97p\8aÖ\90\94
86 // =========================================================================
87
88 // *************************************************************************
89 // \83e\83\93\83|\83\89\83\8a\82È\83p\83X\82Ì\8eæ\93¾
90 // *************************************************************************
91 function TemporaryFile : string;
92 var
93         tempPath : array [0..MAX_PATH] of       char;
94 begin
95
96         GetTempPath( SizeOf(tempPath), tempPath );
97         repeat
98                 Result := tempPath + IntToStr( Random( $7fffffff ) );
99         until not FileExists( Result );
100
101 end;
102
103 // *************************************************************************
104 // \82Ü\82¿BBS\97p\83\8d\83O\83t\83H\83\8b\83_\8eæ\93¾
105 // *************************************************************************
106 function MyLogFolder : string;
107 var
108         folder : string;
109 begin
110
111         folder := LogFolder;
112         if Length( folder ) = 0 then
113                 Result := ''
114         else
115                 Result := folder + LOG_DIR;
116
117 end;
118
119 (*************************************************************************
120  *\83f\83B\83\8c\83N\83g\83\8a\82ª\91\8dÝ\82·\82é\82©\83`\83F\83b\83N
121  *************************************************************************)
122 function DirectoryExistsEx(const Name: string): Boolean;
123 var
124         Code: Integer;
125 begin
126         Code := GetFileAttributes(PChar(Name));
127         Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
128 end;
129
130 (*************************************************************************
131  *\83f\83B\83\8c\83N\83g\83\8a\8dì\90¬\81i\95¡\90\94\8aK\91w\91Î\89\9e\81j
132  *************************************************************************)
133 function ForceDirectoriesEx(Dir: string): Boolean;
134 begin
135         Result := True;
136         if Length(Dir) = 0 then
137                 raise Exception.Create('\83t\83H\83\8b\83_\82ª\8dì\90¬\8fo\97\88\82Ü\82¹\82ñ');
138         Dir := ExcludeTrailingPathDelimiter(Dir);
139         if (Length(Dir) < 3) or DirectoryExistsEx(Dir)
140                 or (ExtractFilePath(Dir) = Dir) then Exit; // avoid 'xyz:\' problem.
141         Result := ForceDirectoriesEx(ExtractFilePath(Dir)) and CreateDir(Dir);
142 end;
143
144 // \82Æ\82è\82 \82¦\82¸\82Ì\91ã\97p\95i\82È\82Ì\82Å chrWhite \82ð\8dl\97\82µ\82Ä\82¢\82È\82¢\82±\82Æ\82É\92\8d\88Ó\81I\81I\81I
145 procedure ExtractHttpFields(
146         const chrSep : TSysCharSet;
147         const chrWhite : TSysCharSet;
148         const strValue : string;
149         var strResult : TStringList;
150         unknownFlag : boolean = false
151 );
152 var
153         last, p, strLen : Integer;
154 begin
155
156         strLen := Length( strValue );
157         p := 1;
158         last := 1;
159
160         while p <= strLen do
161         begin
162
163                 if strValue[ p ] in chrSep then
164                 begin
165                         strResult.Add( Copy( strValue, last, p - last ) );
166                         last := p + 1;
167                 end;
168
169                 p := p + 1;
170
171         end;
172
173         if last <> p then
174                 strResult.Add( Copy( strValue, last, strLen - last + 1 ) );
175
176 end;
177
178 \rfunction HttpEncode(
179 \r       const strValue : string
180 ) : string;
181 var
182         i : Integer;
183         strLen : Integer;
184         strResult : string;
185         b : Integer;
186 const
187         kHexCode : array [0..15] of char = (
188                                 '0', '1', '2', '3', '4', '5', '6', '7',
189                                 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' );
190 begin
191
192         strLen := Length( strValue );
193         i := 1;
194
195         while i <= strLen do
196         begin
197
198                 case strValue[ i ] of
199                 '0' .. '9', 'a' .. 'z', 'A' .. 'Z', '*', '-', '.', '@', '_':
200                         begin
201                                 strResult := strResult + strValue[ i ];
202                         end;
203                 else
204                         begin
205                                 b := Integer( strValue[ i ] );
206                                 strResult := strResult + '%'
207                                                                 + kHexCode[ b div $10 ]
208                                                                 + kHexCode[ b mod $10 ];
209                         end;
210                 end;
211
212                 i := i + 1;
213
214         end;
215
216         Result := strResult;
217
218 end;
219
220
221
222 // =========================================================================
223 // PlugIn
224 // =========================================================================
225
226 // *************************************************************************
227 // \83v\83\89\83O\83C\83\93\82Ì\83o\81[\83W\83\87\83\93\82ð\97v\8b\81\82³\82ê\82½
228 // *************************************************************************
229 procedure OnVersionInfo(
230         var outAgent            : PChar;        // \83o\81[\83W\83\87\83\93\82ð\88ê\90Ø\8aÜ\82Ü\82È\82¢\8f\83\90\88\82È\96¼\8fÌ
231         var outMajor            : DWORD;        // \83\81\83W\83\83\81[\83o\81[\83W\83\87\83\93
232         var outMinor            : DWORD;        // \83}\83C\83i\81[\83o\81[\83W\83\87\83\93
233         var outRelease  : PChar;        // \83\8a\83\8a\81[\83X\92i\8aK\96¼
234         var outRevision : DWORD         // \83\8a\83r\83W\83\87\83\93\83i\83\93\83o\81[
235 ); stdcall;
236 begin
237
238         try
239                 outAgent                := CreateResultString( PChar( PLUGIN_NAME ) );
240                 outMajor                := MAJOR_VERSION;
241                 outMinor                := MINOR_VERSION;
242                 outRelease      := CreateResultString( PChar( RELEASE_VERSION ) );
243                 outRevision     := REVISION_VERSION;
244         except
245                 outAgent                := nil;
246                 outMajor                := 0;
247                 outMinor                := 0;
248                 outRelease      := nil;
249                 outRevision     := 0;
250         end;
251
252 end;
253
254 // *************************************************************************
255 // \8ew\92è\82µ\82½ URL \82ð\82±\82Ì\83v\83\89\83O\83C\83\93\82Å\8eó\82¯\95t\82¯\82é\82©\82Ç\82¤\82©
256 // *************************************************************************
257 function OnAcceptURL(
258         inURL                   : PChar                         // \94»\92f\82ð\8bÂ\82¢\82Å\82¢\82é URL
259 ): TAcceptType; stdcall;        // URL \82Ì\8eí\97Þ
260 var
261         uri                             : TIdURI;
262         uriList         : TStringList;
263         foundPos        : Integer;
264 const
265         BBS_HOST                = 'machi.to';
266         THREAD_MARK     = '/bbs/read.pl';
267 begin
268
269         try
270                 // \83z\83X\83g\96¼\82ª machi.to \82Å\8fI\82í\82é\8fê\8d\87\82Í\8eó\82¯\95t\82¯\82é\82æ\82¤\82É\82µ\82Ä\82¢\82é
271                 uri                     := TIdURI.Create( inURL );
272                 uriList := TStringList.Create;
273                 try
274                         ExtractHttpFields( ['/'], [], uri.Path, uriList );
275                         foundPos := AnsiPos( BBS_HOST, uri.Host );
276                         if (foundPos > 0) and (Length( uri.Host ) - foundPos + 1 = Length( BBS_HOST )) then begin
277                                 foundPos := Pos( THREAD_MARK, inURL );
278                                 if foundPos > 0 then
279                                         Result := atThread
280                                 else if (uriList.Count > 1) and (uri.Path <> '/') then  // \8dÅ\8cã\82ª '/' \82Å\95Â\82ß\82ç\82ê\82Ä\82é\82È\82ç 3
281                                         Result := atBoard
282                                 else
283                                         Result := atBBS;
284                         end else begin
285                                 Result := atNoAccept;
286                         end;
287                 finally
288                         uri.Free;
289                         uriList.Free;
290                 end;
291         except
292                 Result := atNoAccept;
293         end;
294
295 end;
296
297
298
299 // =========================================================================
300 // TMachiBBSThreadItem
301 // =========================================================================
302
303 // *************************************************************************
304 // \83R\83\93\83X\83g\83\89\83N\83^
305 // *************************************************************************
306 constructor TMachiBBSThreadItem.Create(
307         inInstance      : DWORD
308 );
309 var
310         uri                                     : TIdURI;
311         uriList                 : TStringList;
312 begin
313
314         inherited;
315
316         OnDownload              := Download;
317         OnWrite                         := Write;
318         OnGetRes                        := GetRes;
319         OnGetHeader             := GetHeader;
320         OnGetFooter             := GetFooter;
321         OnGetBoardURL   := GetBoardURL;
322
323         FilePath                        := '';
324         FIsTemporary    := False;
325         FDat                                    := nil;
326
327         uri                     := TIdURI.Create( URL );
328         uriList := TStringList.Create;
329         try
330                 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
331                 ExtractHttpFields(
332                         ['&'], [],
333                         Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
334                 FileName        := uriList.Values[ 'KEY' ] + '.dat';
335                 FilePath        := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
336                 IsLogFile       := FileExists( FilePath );
337         finally
338                 uri.Free;
339                 uriList.Free;
340         end;
341
342 end;
343
344 // *************************************************************************
345 // \83f\83X\83g\83\89\83N\83^
346 // *************************************************************************
347 destructor TMachiBBSThreadItem.Destroy;
348 begin
349
350         FreeDat;
351
352         // \88ê\8e\9e\83t\83@\83C\83\8b\82Ì\8fê\8d\87\82Í\8dí\8f\9c\82·\82é
353         if FIsTemporary then
354                 DeleteFile( FilePath );
355
356         inherited;
357
358 end;
359
360 // *************************************************************************
361 // \8ew\92è\82µ\82½ URL \82Ì\83X\83\8c\83b\83h\82Ì\83_\83E\83\93\83\8d\81[\83h\82ð\8ew\8e¦\82³\82ê\82½
362 // *************************************************************************
363 function TMachiBBSThreadItem.Download : TDownloadState;
364 var
365         modified                        : Double;
366         tmp                                             : PChar;
367         downResult              : TStringList;
368         content                         : TStringList;
369         responseCode    : Longint;
370         logStream                       : TFileStream;
371         uri                                             : TIdURI;
372         uriList                         : TStringList;
373         datURL                          : string;
374         foundPos                        : Integer;
375         procedure       downAndParse;
376         begin
377                 responseCode := InternalDownload( PChar( datURL ), modified, tmp, 0 );
378
379                 try
380                         if responseCode = 200 then begin
381                                 downResult      := TStringList.Create;
382                                 try
383                                         downResult.Text := string( tmp );
384
385                                         // \83^\83C\83g\83\8b\82Ì\8eæ\93¾
386                                         foundPos                                := AnsiPos( '<title>', downResult.Text ) + Length( '<title>' );
387                                         Title                                           := Copy(
388                                                 downResult.Text,
389                                                 foundPos,
390                                                 AnsiPos( '</title>', downResult.Text ) - foundPos );
391
392                                         // \83\8c\83X\82Ì\8aJ\8en\88Ê\92u
393                                         foundPos                                := AnsiPos( '<dt', downResult.Text );
394                                         downResult.Text := Copy( downResult.Text, foundPos, Length( downResult.Text ) );
395                                         if foundPos > 0 then begin
396                                                 // \83\8c\83X\82Ì\8fI\97¹\88Ê\92u
397                                                 foundPos := AnsiPos( '<table', downResult.Text ) - 1;
398                                                 if foundPos > 0 then
399                                                         downResult.Text := Copy( downResult.Text, 1, foundPos );
400
401                                                 // \82Ü\82¿BBS\82Í dat \92¼\93Ç\82Ý\82ª\8fo\97\88\82È\82¢\82µ\81Acgi \88È\8aO\82É\8d·\95ª\93Ç\82Ý\8d\9e\82Ý\82Ì\95û\96@\82ª\82 \82é\82í\82¯\82Å\82à\96³\82¢\82Ì\82Å
402                                                 // \91f\82Ì\82Ü\82Ü\82ð\96³\97\9d\82É\95Û\82Æ\82¤\82Æ\82Í\82¹\82¸\82É 2ch \82Ì dat \8c`\8e®\82É\95Ï\8a·\82µ\82½\82à\82Ì\82ð\95Û\91\82µ\82Ä\82µ\82Ü\82¤
403                                                 To2chDat( downResult, Count + 1 );
404                                                 content.Text := content.Text + downResult.Text;
405                                         end;
406                                 finally
407                                         downResult.Free;
408                                 end;
409                         end else begin
410                                 Result := dsNotModify;
411                                 Exit;
412                         end;
413                 finally
414                         DisposeResultString( tmp );
415                 end;
416         end;
417 begin
418
419         Result := dsError;
420
421         uri                     := TIdURI.Create( URL );
422         uriList := TStringList.Create;
423         content := TStringList.Create;
424         try
425                 ExtractHttpFields(
426                         ['&'], [],
427                         Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
428                 FileName := uriList.Values[ 'KEY' ] + '.dat';
429                 if MyLogFolder = '' then begin
430                         // \82Ç\82±\82É\95Û\91\82µ\82Ä\82¢\82¢\82Ì\82©\95ª\82©\82ç\82È\82¢\82Ì\82Å\88ê\8e\9e\83t\83@\83C\83\8b\82É\95Û\91
431                         FilePath                        := TemporaryFile;
432                         FIsTemporary    := True;
433                 end else begin
434                         FilePath        := MyLogFolder + uriList.Values[ 'BBS' ] + '\' + uriList.Values[ 'KEY' ] + '.dat';
435                         FIsTemporary    := False;
436                 end;
437
438                 // \95Û\91\97p\82Ì\83f\83B\83\8c\83N\83g\83\8a\82ð\8c@\82é
439                 ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
440
441                 // \93Æ\8e©\82É\83_\83E\83\93\83\8d\81[\83h\82â\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
442                 // InternalDownload \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
443                 modified        := LastModified;
444                 if Count = 0 then
445                         // 1\81`
446                         datURL          :=
447                                 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
448                                 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
449                                 '&START=' + IntToStr( 1 )
450                 else
451                         // \90V\92\85\82Ì\82Ý
452                         datURL          :=
453                                 uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
454                                 'BBS=' + uriList.Values[ 'BBS' ] + '&KEY=' + uriList.Values[ 'KEY' ] +
455                                 '&START=' + IntToStr( Count + 1 ) + '&NOFIRST=TRUE';
456                 // \83_\83E\83\93\83\8d\81[\83h
457                 downAndParse;
458
459                 if content.Count > 0 then begin
460                         if Count <= 0 then begin
461                                 Result := dsComplete;
462                                 // \90V\8bK\8f\91\82«\8d\9e\82Ý
463                                 content[ 0 ]    := content[ 0 ] + Title;
464                                 logStream                       := TFileStream.Create( FilePath, fmCreate or fmShareDenyWrite );
465                                 try
466                                         logStream.Position      := logStream.Size;
467                                         logStream.Write( PChar( content.Text )^, Length( content.Text ) );
468                                 finally
469                                         logStream.Free;
470                                 end;
471                                 NewReceive      := 1;
472                                 Count                           := content.Count;
473                         end else begin
474                                 Result := dsDiffComplete;
475                                 // \92Ç\8bL
476                                 logStream := TFileStream.Create( FilePath, fmOpenReadWrite or fmShareDenyWrite );
477                                 try
478                                         logStream.Position      := logStream.Size;
479                                         logStream.Write( PChar( content.Text )^, Length( content.Text ) );
480                                 finally
481                                         logStream.Free;
482                                 end;
483                                 NewReceive      := Count + 1;
484                                 Count                           := Count + content.Count;
485                         end;
486
487                         // CGI \82©\82ç\82Í\90³\82µ\82¢\93ú\95t\82ª\93¾\82ç\82ê\82È\82¢\82Ì\82Å\8c»\8dÝ\82É\90Ý\92è
488                         LastModified    := Now;
489                         NewResCount             := content.Count;
490                 end else begin
491                         Result := dsNotModify;
492                 end;
493         finally
494                 uri.Free;
495                 uriList.Free;
496                 content.Free;
497         end;
498
499 end;
500
501 // *************************************************************************
502 // \8f\91\82«\8d\9e\82Ý\82ð\8ew\8e¦\82³\82ê\82½
503 // *************************************************************************
504 function        TMachiBBSThreadItem.Write(
505         inName                          : string;       // \96¼\91O(\83n\83\93\83h\83\8b)
506         inMail                          : string;       // \83\81\81[\83\8b\83A\83h\83\8c\83X
507         inMessage                       : string        // \96{\95
508 ) : TDownloadState;                             // \8f\91\82«\8d\9e\82Ý\82ª\90¬\8c÷\82µ\82½\82©\82Ç\82¤\82©
509 var
510         postURL                         : string;
511         postData                        : string;
512         postResult              : PChar;
513         uri                                             : TIdURI;
514         uriList                         : TStringList;
515 begin
516
517         uri                     := TIdURI.Create( URL );
518         uriList := TStringList.Create;
519         try
520                 ExtractHttpFields(
521                         ['&'], [],
522                         Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
523
524                 postURL         := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
525                 postData        :=
526                         'NAME='                 + HttpEncode( inName ) +
527                         '&MAIL='                + HttpEncode( inMail ) +
528                         '&MESSAGE='     + HttpEncode( inMessage ) +
529                         '&BBS='                 + uriList.Values[ 'BBS' ] +
530                         '&KEY='                 + uriList.Values[ 'KEY' ] +
531                         '&TIME='                + IntToStr( DateTimeToUnix( Now ) ) +
532                         '&submit='      + HttpEncode( '\8f\91\82«\8d\9e\82Þ' );
533
534                 // \93Æ\8e©\82É\92Ê\90M\82µ\82È\82¢\8fê\8d\87\82Í InternalPost \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
535                 InternalPost( PChar( postURL ), PChar( postData ), postResult );
536                 DisposeResultString( postResult );
537
538                 Result := dsComplete
539         finally
540                 uri.Free;
541                 uriList.Free;
542         end;
543
544 end;
545
546 // *************************************************************************
547 // \83\8c\83X\94Ô\8d\86 inNo \82É\91Î\82·\82é html \82ð\97v\8b\81\82³\82ê\82½
548 // *************************************************************************
549 function TMachiBBSThreadItem.GetRes(
550         inNo            : Integer               // \97v\8b\81\82³\82ê\82½\83\8c\83X\94Ô\8d\86
551 ) : string;                                             // \91Î\89\9e\82·\82é HTML
552 var
553         res                     : string;
554         tmp                     : PChar;
555 begin
556
557         // \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
558         // InternalAbon \82¨\82æ\82Ñ Dat2HTML \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
559         LoadDat;
560         if FDat = nil then begin
561                 // \83\8d\83O\82É\91\8dÝ\82µ\82È\82¢\82Ì\82Å\82±\82Ì\82Ü\82Ü\8fI\97¹
562                 Result := '';
563                 Exit;
564         end;
565         res                     := FDat[ inNo - 1 ];
566         tmp                     := InternalAbonForOne( PChar( res ), PChar(FilePath), inNo);
567         try
568                 Result  := Dat2HTML( string( tmp ), inNo );
569         finally
570                 DisposeResultString( tmp );
571         end;
572
573 end;
574
575 // *************************************************************************
576 // \83X\83\8c\83b\83h\82Ì\83w\83b\83_ html \82ð\97v\8b\81\82³\82ê\82½
577 // *************************************************************************
578 function TMachiBBSThreadItem.GetHeader(
579         inOptionalHeader        : string
580 ) : string;
581 begin
582
583         // \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
584         // InternalHeader \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
585         Result := InternalHeader(
586                 '<meta http-equiv="Content-type" content="text/html; charset=Shift_JIS">' +
587                 inOptionalHeader );
588
589
590         // GetRes \82ð\8cÄ\82Î\82ê\82é\82±\82Æ\82ª\97\\91z\82³\82ê\82é\82Ì\82Å FDat \82ð\90\90¬\82µ\82Ä\82¨\82­
591         try
592                 FreeDat;
593                 LoadDat;
594         except
595         end;
596
597 end;
598
599 // *************************************************************************
600 // \83X\83\8c\83b\83h\82Ì\83t\83b\83^ html \82ð\97v\8b\81\82³\82ê\82½
601 // *************************************************************************
602 function TMachiBBSThreadItem.GetFooter(
603         inOptionalFooter : string
604 ) : string;
605 begin
606
607         // \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
608         // InternalFooter \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
609         Result := InternalFooter( inOptionalFooter );
610
611         // \82à\82¤ GetRes \82Í\8cÄ\82Î\82ê\82È\82¢\82Æ\8ev\82¤\82Ì\82Å FDat \82ð\8aJ\95ú\82µ\82Ä\82¨\82­
612         try
613                 FreeDat;
614         except
615         end;
616
617 end;
618
619 // *************************************************************************
620 // \82±\82Ì ThreadItem \82ª\91®\82·\82é\94Â\82Ì URL \82ð\97v\8b\81\82³\82ê\82½
621 // *************************************************************************
622 function        TMachiBBSThreadItem.GetBoardURL : string;
623 var
624         uri                                             : TIdURI;
625         uriList                         : TStringList;
626 begin
627
628         if Copy( URL, Length( URL ), 1 ) = '/' then
629                 uri := TIdURI.Create( URL )
630         else
631                 uri := TIdURI.Create( URL + '/' );
632         uriList := TStringList.Create;
633         try
634                 ExtractHttpFields(
635                         ['&'], [],
636                         Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
637                 FileName := uriList.Values[ 'KEY' ] + '.dat';
638                 // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446
639                 // http://hokkaido.machi.to/hokkaidou/
640                 Result          := CreateResultString(
641                         uri.Protocol + '://' + uri.Host + '/' + uriList.Values[ 'BBS' ] + '/' );
642         finally
643                 uri.Free;
644                 uriList.Free;
645         end;
646
647 end;
648
649 // *************************************************************************
650 // \82Ü\82¿BBS\82Ì HTML \82ð 2ch \82Ì dat \8c`\8e®\82É
651 // *************************************************************************
652 procedure       TMachiBBSThreadItem.To2chDat(
653         ioHTML                          : TStringList;
654         inStartNo                       : Integer = 1
655 );
656 var
657         i, bound                        : Integer;
658         foundPos                        : Integer;
659         strTmp                          : string;
660         res                                             : TStringList;
661         no                                              : Integer;
662 const
663         MAIL_TAG                        = '<a href="mailto:';
664 begin
665
666         //===== 2ch \82Ì dat \8c`\8e®\82É\95Ï\8a·
667         // \83z\83X\83g\96¼\82Ì\8cã\82Å\89ü\8ds\82³\82ê\82Ä\82¢\82½\82è\82·\82é\82Ì\82Å\89ü\8ds\82ð\82·\82×\82Ä\8eæ\82è\8f\9c\82­
668         ioHTML.Text     := CustomStringReplace( ioHTML.Text, #13#10, '');
669         //StringReplace( ioHTML.Text, #13#10, '', [rfReplaceAll] );
670         // \91ã\82í\82è\82É <dt> \82ð\8ds\82Ì\8bæ\90Ø\82è\82É\82·\82é
671         ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<dt>', #10 );
672         //StringReplace( ioHTML.Text, '<dt>', #10, [rfReplaceAll] );
673         // <dt> \82©\82ç\8en\82Ü\82Á\82Ä\82¢\82é\82Ì\82Å\8dÅ\8f\89\82Í\8bó\82Ì\82Í\82¸
674         if Length( ioHTML[ 0 ] ) = 0 then
675                 ioHTML.Delete( 0 );
676
677         // \8cy\82­\82 \82Ú\81[\82ñ\83`\83F\83b\83N
678         // \81¦\91å\8eG\94c\82¾\82©\82ç\82¿\82á\82ñ\82Æ\8fo\97\88\82Ä\82È\82¢\82©\82à
679         try
680                 i                       := 0;
681                 while i < ioHTML.Count do begin
682                         foundPos := AnsiPos( ' ', ioHTML[ i ] );
683                         if foundPos > 0 then begin
684                                 no := StrToInt( Copy( ioHTML[ i ], 1, foundPos - 1 ) );
685                                 if inStartNo < no then
686                                         ioHTML.Insert( i, '<><><><>' );
687                         end;
688                         Inc( i );
689                         Inc( inStartNo );
690                 end;
691         except
692                 // \82 \82Ú\81[\82ñ\83`\83F\83b\83N\82Å\96â\91è\82ª\94­\90\82µ\82Ä\82à\90æ\82Ö\90i\82ß\82½\82¢\82Ì\82Å
693         end;
694
695         // \83g\83\8a\83b\83v\82Ì\8cã\82Ì '<b> </b>' \82ð\8bó\82É
696         ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<b> </b>', '', true );
697         //StringReplace( ioHTML.Text, '<b> </b>', '', [rfReplaceAll, rfIgnoreCase] );
698         // '<b>' \82Í\83\81\81[\83\8b\82Æ\96¼\91O\82Ì\8bæ\90Ø\82è
699         ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<b>', '<>', true );
700         //StringReplace( ioHTML.Text, '<b>', '<>', [rfReplaceAll, rfIgnoreCase] );
701         // \83\81\81[\83\8b\82Æ\96¼\91O\82É\82Â\82¢\82Ä\82­\82é\95Â\82\83^\83O\82ð\93\8a\8de\93ú\82Æ\82Ì\8bæ\90Ø\82è\82É
702         ioHTML.Text     := CustomStringReplace( ioHTML.Text, '</b></a>', '<>', true );
703         //StringReplace( ioHTML.Text, '</b></a>', '<>', [rfReplaceAll, rfIgnoreCase] );
704         ioHTML.Text     := CustomStringReplace( ioHTML.Text, '</b>', '<>', true );
705         //StringReplace( ioHTML.Text, '</b>', '<>', [rfReplaceAll, rfIgnoreCase] );
706         // '<dd>' \82ð\96{\95\82Æ\82Ì\8bæ\90Ø\82è\82É
707         ioHTML.Text     := CustomStringReplace( ioHTML.Text, '<dd>', '<>', true );
708         //StringReplace( ioHTML.Text, '<dd>', '<>', [rfReplaceAll, rfIgnoreCase] );
709
710         res := TStringList.Create;
711         try
712                 bound := ioHTML.Count - 1;
713                 for i := 0 to bound do begin
714                         res.Text := CustomStringReplace( ioHTML[ i ], '<>', #10 );
715                                                 //StringReplace( ioHTML[ i ], '<>', #10, [rfReplaceAll] );
716                         if res.Count >= 3 then begin    // 3 \96¢\96\9e\82Í\82 \82è\82¦\82È\82¢\82Æ\8ev\82¤\82¯\82Ç\88À\91S\82Ì\82½\82ß
717                                 foundPos := AnsiPos( MAIL_TAG, res[ 0 ] );
718                                 if foundPos > 0 then begin
719                                         // \83\81\81[\83\8b\83A\83h\83\8c\83X\82ð\94²\82«\8fo\82·
720                                         foundPos        := foundPos + Length( MAIL_TAG );
721                                         res[ 0 ]        := Copy( res[ 0 ], foundPos, Length( res[ 0 ] ) );
722                                         strTmp          := Copy( res[ 0 ], 1, AnsiPos( '">', res[ 0 ] ) - 1 );
723                                         // \83\81\81[\83\8b\82Æ\96¼\91O\82ª\8bt\82È\82Ì\82Å\82Ð\82Á\82­\82è\95Ô\82µ\82Ä\96ß\82·
724                                         res[ 0 ]        := res[ 1 ];
725                                         res[ 1 ]        := strTmp;
726                                 end else begin
727                                         // \83\81\81[\83\8b\82Æ\96¼\91O\82ª\8bt\82È\82Ì\82Å\82Ð\82Á\82­\82è\95Ô\82·
728                                         res[ 0 ]        := res[ 1 ];
729                                         res[ 1 ]        := '';
730                                 end;
731                                 res[ 2 ] := StringReplace( res[ 2 ], '[', 'IP:', [] );
732                                 res[ 2 ] := StringReplace( res[ 2 ], ']', '', [] );
733                         end;
734                         ioHTML[ i ] := CustomStringReplace( res.Text, #13#10, '<>');
735                         //StringReplace( res.Text, #13#10, '<>', [rfReplaceAll] );
736                 end;
737         finally
738                 res.Free;
739         end;
740
741 end;
742
743 // *************************************************************************
744 // FDat \82Ì\90\90¬
745 // *************************************************************************
746 procedure       TMachiBBSThreadItem.LoadDat;
747 begin
748
749         if FDat = nil then begin
750                 if IsLogFile then begin
751                         // dat \82Ì\93Ç\82Ý\8d\9e\82Ý
752                         FDat := TStringList.Create;
753                         FDat.LoadFromFile( FilePath );
754                 end;
755         end;
756
757 end;
758
759 // *************************************************************************
760 // FDat \82Ì\8aJ\95ú
761 // *************************************************************************
762 procedure       TMachiBBSThreadItem.FreeDat;
763 begin
764
765         if FDat <> nil then begin
766                 FDat.Free;
767                 FDat := nil;
768         end;
769
770 end;
771
772 // *************************************************************************
773 // TThreadItem \82ª\90\90¬\82³\82ê\82½\8fê\8d\87\82Ì\8f\88\92u(TMachiBBSThreadItem \82ð\90\90¬\82·\82é)
774 // *************************************************************************
775 procedure ThreadItemOnCreateOfTMachiBBSThreadItem(
776         inInstance : DWORD
777 );
778 var
779         threadItem : TMachiBBSThreadItem;
780 begin
781
782         threadItem := TMachiBBSThreadItem.Create( inInstance );
783         ThreadItemSetLong( inInstance, tipContext, DWORD( threadItem ) );
784
785 end;
786
787 // *************************************************************************
788 // TThreadItem \82ª\94j\8aü\82³\82ê\82½\8fê\8d\87\82Ì\8f\88\92u(TMachiBBSThreadItem \82ð\94j\8aü\82·\82é)
789 // *************************************************************************
790 procedure ThreadItemOnDisposeOfTMachiBBSThreadItem(
791         inInstance : DWORD
792 );
793 var
794         threadItem : TMachiBBSThreadItem;
795 begin
796
797         threadItem := TMachiBBSThreadItem( ThreadItemGetLong( inInstance, tipContext ) );
798         threadItem.Free;
799
800 end;
801
802 // =========================================================================
803 // TMachiBBSBoardItem
804 // =========================================================================
805
806 // *************************************************************************
807 // \83R\83\93\83X\83g\83\89\83N\83^
808 // *************************************************************************
809 constructor TMachiBBSBoardItem.Create(
810         inInstance      : DWORD
811 );
812 var
813         uri                                     : TIdURI;
814         uriList                 : TStringList;
815 begin
816
817         inherited;
818
819         OnDownload                                              := Download;
820         OnCreateThread                          := CreateThread;
821         OnEnumThread                                    := EnumThread;
822         OnFileName2ThreadURL    := ToThreadURL;
823
824         FilePath                        := '';
825         FIsTemporary    := False;
826         FDat                                    := nil;
827
828         uri                     := TIdURI.Create( SubjectURL );
829         uriList := TStringList.Create;
830         try
831                 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
832                 // http://hokkaido.machi.to/hokkaidou/subject.txt
833                 FilePath        := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
834                 IsLogFile       := FileExists( FilePath );
835         finally
836                 uri.Free;
837                 uriList.Free;
838         end;
839
840 end;
841  
842 // *************************************************************************
843 // \83f\83X\83g\83\89\83N\83^
844 // *************************************************************************
845 destructor TMachiBBSBoardItem.Destroy;
846 begin
847
848         if FDat <> nil then begin
849                 try
850                         FDat.Free;
851                         FDat := nil;
852                 except
853                 end;
854         end;
855
856         // \88ê\8e\9e\83t\83@\83C\83\8b\82Ì\8fê\8d\87\82Í\8dí\8f\9c\82·\82é
857         if FIsTemporary then
858                 DeleteFile( FilePath );
859
860         inherited;
861
862 end;
863
864 // *************************************************************************
865 // \8ew\92è\82µ\82½\83X\83\8c\88ê\97\97\82Ì\83_\83E\83\93\83\8d\81[\83h\82ð\97v\8b\81\82³\82ê\82½
866 // *************************************************************************
867 function TMachiBBSBoardItem.Download : TDownloadState;
868 var
869         modified                        : Double;
870         downResult              : PChar;
871         responseCode    : Longint;
872         uri                                             : TIdURI;
873         uriList                         : TStringList;
874 begin
875
876         Result := dsError;
877
878         if FDat <> nil then begin
879                 try
880                         FDat.Free;
881                         FDat := nil;
882                 except
883                 end;
884         end;
885         FDat            := TStringList.Create;
886         uri                     := TIdURI.Create( SubjectURL );
887         uriList := TStringList.Create;
888         // \93Æ\8e©\82É\83_\83E\83\93\83\8d\81[\83h\82â\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í
889         // InternalDownload \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
890         modified                        := LastModified;
891         responseCode    := InternalDownload( PChar( uri.URI ), modified, downResult );
892         try
893                 if responseCode = 200 then begin
894                         try
895                                 // \83p\83X\82ð\8eZ\8fo
896                                 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
897                                 if MyLogFolder = '' then begin
898                                         // \82Ç\82±\82É\95Û\91\82µ\82Ä\82¢\82¢\82Ì\82©\95ª\82©\82ç\82È\82¢\82Ì\82Å\88ê\8e\9e\83t\83@\83C\83\8b\82É\95Û\91
899                                         FilePath                        := TemporaryFile;
900                                         FIsTemporary    := True;
901                                 end else begin
902                                         FilePath                        := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
903                                         FIsTemporary    := False
904                                 end;
905
906                                 // \95Û\91\97p\82Ì\83f\83B\83\8c\83N\83g\83\8a\82ð\8c@\82é
907                                 ForceDirectoriesEx( Copy( FilePath, 1, LastDelimiter( '\', FilePath ) ) );
908
909                                 FDat.Text := string( downResult );
910                                 // \95Û\91
911                                 FDat.SaveToFile( FilePath );
912
913                                 IsLogFile                       := True;
914                                 RoundDate                       := Now;
915                                 LastModified    := modified;
916                                 LastGetTime             := Now;
917                         finally
918                                 uri.Free;
919                                 uriList.Free;
920                         end;
921                         Result := dsComplete;
922                 end;
923         finally
924                 DisposeResultString( downResult );
925         end;
926
927 end;
928
929 // *************************************************************************
930 // \83X\83\8c\97§\82Ä\82ð\8ew\8e¦\82³\82ê\82½
931 // *************************************************************************
932 function        TMachiBBSBoardItem.CreateThread(
933         inSubject                       : string;       // \83X\83\8c\83^\83C
934         inName                          : string;       // \96¼\91O(\83n\83\93\83h\83\8b)
935         inMail                          : string;       // \83\81\81[\83\8b\83A\83h\83\8c\83X
936         inMessage                       : string        // \96{\95
937 ) : TDownloadState;                             // \8f\91\82«\8d\9e\82Ý\82ª\90¬\8c÷\82µ\82½\82©\82Ç\82¤\82©
938 var
939         postURL                         : string;
940         postData                        : string;
941         postResult              : PChar;
942         uri                                             : TIdURI;
943         uriList                         : TStringList;
944 begin
945
946         uri                     := TIdURI.Create( URL );
947         uriList := TStringList.Create;
948         try
949                 ExtractHttpFields(
950                         ['&'], [],
951                         Copy( uri.Params, AnsiPos( '?', uri.Params ) + 1, Length( uri.Params ) ), uriList );
952
953                 postURL         := uri.Protocol + '://' + uri.Host + '/bbs/write.cgi';
954                 postData        :=
955                         'SUBJECT='      + HttpEncode( inSubject ) +
956                         '&NAME='                + HttpEncode( inName ) +
957                         '&MAIL='                + HttpEncode( inMail ) +
958                         '&MESSAGE='     + HttpEncode( inMessage ) +
959                         '&BBS='                 + uriList[ 1 ] +
960                         '&TIME='                + IntToStr( DateTimeToUnix( Now ) ) +
961                         '&submit='      + HttpEncode( '\90V\8bK\8f\91\82«\8d\9e\82Ý' );
962
963                 // \93Æ\8e©\82É\92Ê\90M\82µ\82È\82¢\8fê\8d\87\82Í InternalPost \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
964                 InternalPost( PChar( postURL ), PChar( postData ), postResult );
965                 DisposeResultString( postResult );
966
967                 Result := dsComplete
968         finally
969                 uri.Free;
970                 uriList.Free;
971         end;
972
973 end;
974
975 // *************************************************************************
976 // \83X\83\8c\88ê\97\97\82Ì URL \82©\82ç\83X\83\8c\83b\83h\82Ì URL \82ð\93±\82«\8fo\82·
977 // *************************************************************************
978 function TMachiBBSBoardItem.ToThreadURL(
979         inFileName      : string        // \83X\83\8c\83b\83h\83t\83@\83C\83\8b\96¼
980 ) : string;                                                     // \83X\83\8c\83b\83h\82Ì URL
981 var
982         threadURL               : string;
983         uri                                     : TIdURI;
984         uriList                 : TStringList;
985         found                           : Integer;
986 begin
987
988         found := AnsiPos( '.', inFileName );
989         if found > 0 then
990                 inFileName := Copy( inFileName, 1, found - 1 );
991
992         uri                     := TIdURI.Create( SubjectURL );
993         uriList := TStringList.Create;
994         try
995                 try
996                         // http://hokkaido.machi.to/hokkaidou/
997                         // http://hokkaido.machi.to/bbs/read.pl?BBS=hokkaidou&KEY=1061764446&LAST=50
998                         ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
999                         threadURL       := uri.Protocol + '://' + uri.Host + '/bbs/read.pl?' +
1000                                 'BBS=' + uriList[ 1 ] + '&KEY=' + inFileName + '&LAST=50';
1001                         Result          := threadURL;
1002                 finally
1003                         uri.Free;
1004                         uriList.Free;
1005                 end;
1006         except
1007                 Result := '';
1008         end;
1009
1010 end;
1011
1012 // *************************************************************************
1013 // \82±\82Ì\94Â\82É\82¢\82­\82Â\82Ì\83X\83\8c\82ª\82 \82é\82©\97v\8b\81\82³\82ê\82½
1014 // *************************************************************************
1015 procedure       TMachiBBSBoardItem.EnumThread(
1016         inCallBack      : TBoardItemEnumThreadCallBack
1017 );
1018 var
1019         uri                                     : TIdURI;
1020         uriList                 : TStringList;
1021 begin
1022
1023         try
1024                 if FDat = nil then begin
1025                         FDat := TStringList.Create;
1026
1027                         uri                     := TIdURI.Create( SubjectURL );
1028                         uriList := TStringList.Create;
1029                         try
1030                                 // \83p\83X\82ð\8eZ\8fo
1031                                 ExtractHttpFields( ['/', '?'], [], uri.Path, uriList );
1032                                 // http://hokkaido.machi.to/hokkaidou/subject.txt
1033                                 FilePath        := MyLogFolder + uriList[ 1 ] + '\' + uri.Document;
1034                                 if FileExists( FilePath ) then
1035                                         // \93Ç\82Ý\8d\9e\82Ý
1036                                         FDat.LoadFromFile( FilePath );
1037                         finally
1038                                 uri.Free;
1039                                 uriList.Free;
1040                         end;
1041                 end;
1042
1043                 // \93Æ\8e©\82É\83t\83B\83\8b\83^\83\8a\83\93\83O\82ð\8ds\82í\82È\82¢\8fê\8d\87\82Í EnumThread \82É\94C\82¹\82é\82±\82Æ\82ª\8fo\97\88\82é
1044                 inherited EnumThread( inCallBack, CustomStringReplace( FDat.Text, ',', '<>' ) );
1045         except
1046         end;
1047
1048 end;
1049
1050 // *************************************************************************
1051 // \83X\83\8c\88ê\97\97\82Ì URL \82ð\8b\81\82ß\82é
1052 // *************************************************************************
1053 function        TMachiBBSBoardItem.SubjectURL : string;
1054 var
1055         uri                     : TIdURI;
1056         uriList : TStringList;
1057 begin
1058
1059         uri                     := TIdURI.Create( URL );
1060         uriList := TStringList.Create;
1061         try
1062                 if uri.Document <> SUBJECT_NAME then begin
1063                         if Copy( URL, Length( URL ), 1 ) = '/' then
1064                                 Result := URL + SUBJECT_NAME
1065                         else
1066                                 Result := URL + '/' + SUBJECT_NAME;
1067                 end else begin
1068                         // \82±\82±\82É\82Í\97\88\82È\82¢\82Æ\8ev\82¤\82¯\82Ç
1069                         Result := URL;
1070                 end;
1071         finally
1072                 uri.Free;
1073                 uriList.Free;
1074         end;
1075
1076 end;
1077
1078 // *************************************************************************
1079 // TBoardItem \82ª\90\90¬\82³\82ê\82½\8fê\8d\87\82Ì\8f\88\92u(TMachiBBSBoardItem \82ð\90\90¬\82·\82é)
1080 // *************************************************************************
1081 procedure BoardItemOnCreateOfTMachiBBSBoardItem(
1082         inInstance : DWORD
1083 );
1084 var
1085         boardItem : TMachiBBSBoardItem;
1086 begin
1087
1088         boardItem := TMachiBBSBoardItem.Create( inInstance );
1089         BoardItemSetLong( inInstance, bipContext, DWORD( boardItem ) );
1090
1091 end;
1092
1093 // *************************************************************************
1094 // TBoardItem \82ª\94j\8aü\82³\82ê\82½\8fê\8d\87\82Ì\8f\88\92u(TMachiBBSBoardItem \82ð\94j\8aü\82·\82é)
1095 // *************************************************************************
1096 procedure BoardItemOnDisposeOfTMachiBBSBoardItem(
1097         inInstance : DWORD
1098 );
1099 var
1100         boardItem : TMachiBBSBoardItem;
1101 begin
1102
1103         boardItem := TMachiBBSBoardItem( BoardItemGetLong( inInstance, bipContext ) );
1104         boardItem.Free;
1105
1106 end;
1107
1108
1109
1110 // =========================================================================
1111 // \83G\83\93\83g\83\8a\83|\83C\83\93\83g
1112 // =========================================================================
1113 procedure DLLEntry(
1114         ul_reason_for_call : DWORD
1115 );
1116 var
1117         module : HMODULE;
1118 begin
1119
1120         case ul_reason_for_call of
1121                 DLL_PROCESS_ATTACH:
1122                 begin
1123                         Randomize;
1124
1125                         module := GetModuleHandle( nil );
1126
1127                         LoadInternalAPI( module );
1128                         LoadInternalFilePathAPI( module );
1129                         LoadInternalThreadItemAPI( module );
1130                         LoadInternalBoardItemAPI( module );
1131
1132                         // ===== \83C\83\93\83X\83^\83\93\83X\82Ì\8eæ\82è\88µ\82¢\82ð TThreadItem \82©\82ç TMachiBBSThreadItem \82É\95Ï\8dX\82·\82é
1133                         ThreadItemOnCreate      := ThreadItemOnCreateOfTMachiBBSThreadItem;
1134                         ThreadItemOnDispose     := ThreadItemOnDisposeOfTMachiBBSThreadItem;
1135                         // ===== \83C\83\93\83X\83^\83\93\83X\82Ì\8eæ\82è\88µ\82¢\82ð TBoardItem \82©\82ç TMachiBBSBoardItem \82É\95Ï\8dX\82·\82é
1136                         BoardItemOnCreate               := BoardItemOnCreateOfTMachiBBSBoardItem;
1137                         BoardItemOnDispose      := BoardItemOnDisposeOfTMachiBBSBoardItem;
1138                 end;
1139                 DLL_PROCESS_DETACH:
1140                         ;
1141                 DLL_THREAD_ATTACH:
1142                         ;
1143                 DLL_THREAD_DETACH:
1144                         ;
1145         end;
1146
1147 end;
1148
1149 exports
1150         OnVersionInfo,
1151         OnAcceptURL;
1152
1153 begin
1154
1155         try
1156                 DllProc := @DLLEntry;
1157                 DLLEntry( DLL_PROCESS_ATTACH );
1158         except end;
1159
1160 end.