#!/usr/bin/perl -w
#
# gnview 2ch BBS Viewer
# http://gnview.sourceforge.jp/

#--------------------------------------
# ライブラリ読み込み
#--------------------------------------

use utf8;
use strict;
use Config;
BEGIN {
   $Config{useithreads} or die "Recompile perl with ithreads to use this program.";
}

use threads;
use threads::shared;
use Thread::Queue;

use POSIX qw/ locale_h strftime /;
use Encode qw/ encode from_to decode /;
use Encode::Guess qw/ euc-jp shiftjis /;
use Time::HiRes qw/ sleep gettimeofday tv_interval /;
use Time::Local;
use Fcntl qw/ :flock /;

use Gtk2 '-init';						# perl-Gtk2 パッケージが必要
use Gtk2::GladeXML;					# perl-Gtk2-GladeXML パッケージが必要
use Gtk2::Pango;
use Glib::Object::Subclass Glib::Object::, interfaces => [ Gtk2::TreeModel::, Gtk2::TreeSortable:: ];

use HTML::TokeParser;
use HTML::Entities;
use HTTP::Date;
use Compress::Zlib;					# perl-Compress-Zlibパッケージが必要
use List::Util qw/ min /;

use LWP::UserAgent;					# perl-libwww-perl パッケージが必要
use LWP::MediaTypes qw/ guess_media_type /;
use HTTP::Cookies;

use Data::Dumper;

#--------------------------------------
# 全体設定
#--------------------------------------

use constant TRUE  => 1;
use constant FALSE => 0;

#--------------------------------------
# グローバル定数
#--------------------------------------
   
	# カーソル作成
	# スレのポップアップメニュー用
	our $gnCursor_Beam = Gtk2::Gdk::Cursor->new('xterm');
	our $gnCursor_Link = Gtk2::Gdk::Cursor->new('hand2');

	# 2ch用定数
	our $gnKeyTime = "1104688508";

	our $gnIdxFileVersion			= "1.01";		# よくわかんないけどFolder.idxのなかに出てくるので入れるようにした
													# ギコナビ互換用
	our $gnGnname					= "gnview";		# gnviewの名前
	our $gnVersion					= "0.8";		# gnviewのバージョン
	our $gnUsrAgent : shared		= "Monazilla/1.00 \(${gnGnname}\/${gnVersion}\)";
													# ユーザーエージェント指定

    # デバッグ関連
    our $gnDebugFlag : shared = 0;		# デバッグレベル指定(0 = まったく出力しない, 1-->大きくなるほど詳細な
										# デバッグ出力が行われる)
	our $gnDegugLevel_global = 1;		# 各モジュール側のデバッグレベル
										# 実際には	
										# $gnDebugLevel = $gnDegugLevel_global + $gnDegugLevel_module + $gnDegugLevel_function
										#  ^my変数           ^our変数                 ^モジュール全体のmy変数     ^各関数内で指定されるmy
										# で指定され、
										# $gnDebugFlag > $gnDebugLevel
										# の場合にデバッグ出力が行われる
	
	# 共有ファイルパス保管用
	my $LibPath					= &gnGetLibPath;
	our $gnIconfn				= $LibPath . "\/${gnGnname}.png";		# アイコン
	our $gladefn				= $LibPath . "\/${gnGnname}.glade";   	# GladeでデザインしたGUIのXMLファイルの場所
	our $gnEnvABimgfn			= $LibPath . "\/1pix.png";
	our $gnEnvABcenterimgfn		= $LibPath . "\/1pix_glay.png";
	my $gnPrg_firstrun			= $LibPath . "\/${gnGnname}_firstrun.pl";
	my $gnPrg_env				= $LibPath . "\/${gnGnname}_env.pl";
	my $gnPrg_lowlevel			= $LibPath . "\/${gnGnname}_lowlevel.pl";

#--------------------------------------
# 共有ライブラリ読み込み
#--------------------------------------

require($gnPrg_lowlevel);
require($gnPrg_firstrun);
require($gnPrg_env);

#--------------------------------------
# グローバル変数
#--------------------------------------

	# スレッド間共有
	our $hold : shared;
	our $gnImgGetSt : shared;
	our $queue : shared = Thread::Queue->new;
	our $fnsize : shared;

	# 設定ファイルパス保管用
	our $gnEnvFile;
	our $gnURLIniFile;
	our $gnSentIniFile;

	our $gnLockFileN;						# 多重起動抑止用ロックファイル
	our %gnEnvArg;						# gikoNavi.ini保存配列
	our %gnURLIni;						# url.iniの内容をハッシュ配列に格納
	our %gnInitCfg;						# 初期設定保存配列
	our $gnCacheTblFile;

	our $boardcfg;						# 板一覧設定ファイル
	our %gnBoardTbl;
	our $logdir;

	our $gnTmpfn;
	our $tmpdir = &gnGetTmpDir;		# テンポラリディレクトリを取得
	if($gnDebugFlag) { print "$tmpdir\n"; }

	# 内部使用変数
	our %gnFH;								# ファイルハンドル管理用ハッシュ配列

	our $gnHoverOverLink		= FALSE;	# カーソルがリンクの上にあるかのフラグ
	our $gnPopupText			= "";		# レス表示ウィンドウがポップアップしているかのフラグ
											#    ポップアップがなければNULL,
	                                        #    ポップアップしていればGtk2::Windowが入っている
	our $gnPopupImg			= undef;		# 画像表示ウィンドウがポップアップしているかのフラグ
											# ポップアップがなければundef,
	our $gnPopupImgSt			= 1;
	our %gnImgPopup_info;					# ポップアップ画像の情報を格納する配列
	our $gnPop2;							# ポップアップしていればGtk2::Windowが入っている
	our $gnPopupImgBuf;						# ポップアップ用画像バッファ
	our %gnCacheTbl;						# 画像キャッシュテーブル保存配列

	our $gnItaLogDir = '';			# 板毎のログ格納ディレクトリ
	our @gnSureViewInfo;				# スレ表示管理用配列
										# n(偶数,0スタート): スレファイル名
	our $gnSureViewPageNum = 0;		# スレ表示用ページの最終番号
									# n+1(奇数,1スタート): Notebookタブの番号

	our $gnTimeforPopup = 0;			# ポップアップウィンドウ遅延表示用
	our $gnPopupTextCallback;
	our $gnPopupCallback;
	our $gnImgUpdateCallback;
	our $gnPopupCnt = 0;

	our $gnSuppressEventFlg = FALSE;	# コールバック関数を実行するかどうかのフラグ。
										# TRUEならコールバック時に何もしない
	our $gnSignalHandler;				# コールバック関数

	our $gnGUIxml;			# gladeで生成したXMLファイル格納用
	our $gnFRxml;				# gladeで生成したXMLファイル格納用
	our $gnWxml = "";			# gladeで生成したXMLファイル格納用
	our $gnIPxml;
	our $gnTPxml;
	our $gnISxml;
	our $gnEnvXML;
	our $gnEnvABXML;

	our $gnFind_Iter;
	our $gnFind_pg;
	our $gnFind_keyst = "";

#--------------------------------------
# 初期処理
#--------------------------------------
print STDERR "Starting $gnGnname $gnVersion\n";
my $gnDebugLevel = $gnDegugLevel_global;
  #____________________________________________________
  # 初回起動かどうかをチェック
  our $gnCfgPath = &gnGetPersonalCfgPath;
  #my $gnCfgFileN = &gnFnEncode($gnCfgPath . "\." . "${gnGnname}config");
  #if($gnDebugFlag) { print Dumper($gnCfgFileN); }
  if (!(&gnCheckPath($gnCfgPath . "\." . "${gnGnname}config"))) {
     &gnFirstRun($gladefn);
  }else{
     &gnInit;
  }
  #--------------------------------------
  # スレッドの開始
  my $thr = threads->new (\&command_runner);   #<--1000usec程度かかっている

  Gtk2->main;


#--------------------------------------
# 初回起動処理
#--------------------------------------

sub gnInit {

  $gnGUIxml = Gtk2::GladeXML->new($gladefn, 'mW');
  
  # ロックファイルをチェックし、多重起動を抑止する
  my $gnLockFile = $gnCfgPath . "\." . "${gnGnname}lock";
  #my $gnLockFileN = &gnFnEncode($gnLockFile);
  if(&gnCheckPath($gnLockFile)) {
    if($gnDebugFlag) { print "Lockfile Detected\n"; };
    my $retval = &gnYesNo("多重起動防止用のロックファイル\($gnLockFile\)が見つかりました。\n" .
                              "既にgnviewが起動しているか、前回正しく終了しなかったかもしれません。\n" .
                              "ロックファイルを無視して強制的に起動しますか？");
    if ($retval eq "no") {
        print STDERR "$gnGnname exited by user interuption.\(Lockfile\($gnLockFile\) detected\)\n";
        exit(1);
    }
  }
  
  my $LFN = &gnOpenLocal($gnLockFile, "w");
  #open(LFN, ">$gnLockFileN");
  &gnCloseLocal($gnLockFile);
  #close(LFN);

  # 初期設定ファイル(.gnconfig)読み込み
  print STDERR "Loading Configration File\n";
  my $gnCfgFile = $gnCfgPath . "\." . "${gnGnname}config";
  #my $gnCfgFileN = &gnFnEncode($gnCfgPath . "\." . "${gnGnname}config");
  #if($gnDebugFlag) { print "gnCfgFileN\: $gnCfgFileN\n"; }
  if (!(&gnCheckPath($gnCfgFile))) {
     if($gnDebugFlag) { print "gnCfgFileN load failed\n"; }
     &gnRestartInit;
  }
  #my $gnInitCfgRef = &gnLoadEnv($gnCfgFileN);
  my $gnInitCfgRef = &gnLoadEnv($gnCfgFile);
  %gnInitCfg = %$gnInitCfgRef;
  if($gnDebugFlag) { print "gnInit_LoadCfg=\n" . Dumper(%gnInitCfg); }
  
  $gnEnvFile = $gnInitCfg{'Main'}{'gikoNavi.ini'};
  #my $gnEnvFile_1 = &gnFnEncode($gnEnvFile);
  if (!(&gnCheckPath($gnEnvFile))) {
     if($gnDebugFlag) { print "gnEnvFile load failed\n"; }
     &gnRestartInit;
  }
  $gnURLIniFile = $gnInitCfg{'Main'}{'url.ini'};
  #my $gnURLIniFile_1 = &gnFnEncode($gnURLIniFile);
  if (!(&gnCheckPath($gnURLIniFile))) {
     if($gnDebugFlag) { print "gnURLIniFile load failed\n"; }
     &gnRestartInit;
  }
  $gnSentIniFile = $gnInitCfg{'Main'}{'sent.ini'};
  #my $gnSentIniFile_1 = &gnFnEncode($gnSentIniFile);
  if (!(&gnCheckPath($gnSentIniFile))) {
     if($gnDebugFlag) { print "gnSentIniFile load failed\n"; }
     &gnRestartInit;
  }
  $gnCacheTblFile = $gnInitCfg{'Main'}{'cachetbl.ini'};
  if($gnDebugFlag) { print "cachetbl.ini\n".Dumper($gnCacheTblFile); }
  if ($gnCacheTblFile eq "") {
     if($gnDebugFlag) { print "gnCacheTblFile not defined\n"; }
     &gnRestartInit;
  }
  $logdir = $gnInitCfg{'Main'}{'LogFolder'} . "\/2ch\/";
  #my $logdir_en = &gnFnEncode($logdir);
  if($gnDebugFlag) { print "logdir\: " . $logdir . "\n"; }
  if (!(&gnCheckPath($logdir))) {
     if($gnDebugFlag) { print "logdir load failed\n"; }
     &gnRestartInit;
  }

  
  $gladefn = &gnGetLibPath . $gnGnname . ".glade";
  
  # 環境設定ファイル読み込み(gikoNavi.ini)
  if($gnDebugFlag) { print "gikonaviini=\n" . Dumper($gnEnvFile); }
  my $gnEnvArgRef = &gnLoadEnv($gnEnvFile);
  %gnEnvArg = %$gnEnvArgRef;
  $gnEnvArg{'Folder'}{'LogFolderUnix'} = $gnInitCfg{'Main'}{'LogFolder'};
  
  # gnview独自環境変数がセットされていなければシステム・デフォルトをセット
  if(!($gnEnvArg{'Cache'}{'gnCacheFolder'})) {
     $gnEnvArg{'Cache'}{'gnCacheFolder'} = $tmpdir;
  }
  if(!($gnEnvArg{'Thread'}{'gnLinkColorAlreadyCached'})) {
     $gnEnvArg{'Thread'}{'gnLinkColorAlreadyCached'} = 'blue';
  }
  if(!($gnEnvArg{'Thread'}{'gnLinkColorNotCached'})) {
     $gnEnvArg{'Thread'}{'gnLinkColorNotCached'} = 'blue';
  }
  if(!($gnEnvArg{'Browser'}{'AvoidBorderLeft'})) {
     $gnEnvArg{'Browser'}{'AvoidBorderLeft'} = 0;
     $gnEnvArg{'Browser'}{'AvoidBorderRight'} = 0;
     $gnEnvArg{'Browser'}{'AvoidBorderTop'} = 0;
     $gnEnvArg{'Browser'}{'AvoidBorderBottom'} = 0;
  }
  if(!($gnEnvArg{'Browser'}{'gnBrowserFontUseCustom'})) {
     $gnEnvArg{'Browser'}{'gnBrowserFontUseCustom'} = 0;
  }
  if(!($gnEnvArg{'Browser'}{'gnWriteWithQuotation'})) {
     $gnEnvArg{'Browser'}{'gnWriteWithQuotation'} = 0;
  }
  if(!($gnEnvArg{'Browser'}{'gnPermitPopupExt'})) {
     $gnEnvArg{'Browser'}{'gnPermitPopupExt'} = "jpg,gif,bmp,tif,png";
  }
  # 環境設定ファイル読み込み(url.ini)
  if($gnDebugFlag) { print "urliini=\n" . Dumper($gnURLIniFile); }
  my $gnUrlArgRef = &gnLoadEnv($gnURLIniFile);
  %gnURLIni = %$gnUrlArgRef;
  if($gnDebugFlag) { print "urlini=\n" . Dumper(%gnURLIni); }

  # 環境設定ファイル読み込み(cachetbl.ini)
  if($gnDebugFlag) { print "cachetbl.ini=\n" . Dumper($gnCacheTblFile); }
  my $gnCacheTblRef = &gnLoadEnv($gnCacheTblFile);
  %gnCacheTbl = %$gnCacheTblRef;

  # 起動時に環境を読み込みメインウィンドウを開く
  $gnGUIxml->signal_autoconnect_from_package('main');


  #____________________________________________________
  # 板一覧読み込み
  print STDERR "Building Board List...";
  # 板一覧のファイル名を与えると、TreeStore型のウィジェットが帰ってくる
  my $gnItaStore;
  $boardcfg = $gnCfgPath . "2chboard.lst";
  #my $boardcfgN = &gnFnEncode($boardcfg)
  #if (-e $boardcfgN) {
     $gnItaStore = &gnMakeItaTreeStore($boardcfg);
  #}else{
  if(!($gnItaStore)) {
     &gnWarn("板一覧を保存するファイルが見つかりません\nメニューの\[ファイル\]-\[板更新\]を選択して板の一覧を取得してください");
  }
  #}
  print STDERR "...Complete";
  
  # TreeView作成
  my $gnItaView = $gnGUIxml->get_widget('gnII');
  $gnItaView->set_model($gnItaStore);
  
  my $gnIICol1 = Gtk2::TreeViewColumn->new();
  $gnIICol1->set_title('２ちゃんねる');
  
  my $gnIICol1Rend = Gtk2::CellRendererText->new;
  $gnIICol1->pack_start($gnIICol1Rend, FALSE);
  $gnIICol1->add_attribute($gnIICol1Rend, text => 0);

  $gnItaView->append_column($gnIICol1);
  
  my $gnIS_pos = Gtk2::TreePath->new_from_indices(0);
  $gnItaView->expand_row($gnIS_pos, FALSE);
  
  
  # 板名が選択されたらスレ一覧読み込み
  $gnItaView->signal_connect('cursor-changed' => sub{ &gnSleIchiranSelect($gnItaView,"none"); });
  
  #____________________________________________________
  # スレ一覧初期設定
  #
  my $gnSureLstStore = &gnMakeInitialSureLst;
#  my $gnSureLstStore = &gnview_env::gnMakeInitialSureLst;
  &gnSureIchiranInit($gnSureLstStore, undef);
#  &gnview_env::gnSureIchiranInit($gnSureLstStore, undef);
  
  #____________________________________________________
  # スレ表示部初期設定
  my $gnNoteInit = $gnGUIxml->get_widget('gnNote');
  $gnNoteInit->set_property(homogeneous => FALSE);
  $gnSignalHandler->{gnNote}{switch_page} = $gnNoteInit->signal_connect_after('switch-page' => sub{ &on_gnNote_switch_page; });
  if($gnDebugFlag) { print Dumper($gnSignalHandler)."\n"; }

  #--------------------------------------
  # メインウィンドウ表示
  #--------------------------------------

   # iniでサイズが指定されている部分はそれに合わせてリサイズする
   my $mW = $gnGUIxml->get_widget('mW');

   # アイコンをセット
   $mW->set_default_icon(&gnGetgnIconPixbuf());
   $mW->set_icon(&gnGetgnIconPixbuf());

   # メインウィンドウのリサイズ
   $mW->resize($gnEnvArg{'WindowSize'}{'Width'}, $gnEnvArg{'WindowSize'}{'Height'});
   $mW->move($gnEnvArg{'WindowSize'}{'Left'}, $gnEnvArg{'WindowSize'}{'Top'});
   $mW->queue_resize;
   
   # カテゴリ一覧の幅を環境変数から読み取ってセット
   my $gnCatHPan = $gnGUIxml->get_widget('gnCatHPan');
   $gnCatHPan->set_position($gnEnvArg{'CategoryColumnWidth'}{'ID0'});

   # 板一覧の高さを環境変数から読み取ってセット
   my $gnItaVPan = $gnGUIxml->get_widget('gnItaVPan');
   $gnItaVPan->set_position($gnEnvArg{'BoardColumnWidth'}{'ID7'});
   


   # メインウィンドウを表示
   $mW->show_all;
   
   print "done. Ready.\n";

}

sub gnRestartInit {
   # 初期設定内容に不備があった場合に、再度初期設定を行うよう
   # 促す関数
   #
   # 引数: なし
   # 返り値: なし
#   $gnGUIxml = Gtk2::GladeXML->new($gladefn, 'mW');
   my $mW = $gnGUIxml->get_widget('mW');
   &gnWarn("初期設定内容に不備があるか、\nバージョンの変更に伴い内容に不足が生じました。\n$gnInitCfg{'Main'}{'gnCfgPath'}\.${gnGnname}configを削除するかリネームしてから${gnGnname}をもう一度起動して\n再度初期設定を行ってください");
   exit(1);
}

sub gnGetLibPath {
   # ライブラリパスをチェック
   #
   # 引数:      なし
   # 返り値: 1: ライブラリへのフルパス
   
   my $gnLibPath = "";
   if ($^O eq "MSWin32") {
      # "perl -V"の"osname"がMSWin32の場合は
      # 実行環境がWindowsであると判断
      $gnLibPath = &gnGetEnvVal('APPDATA') . "\\${gnGnname}\\";
      if(-d $gnLibPath) {
         if($gnDebugFlag) { print "Your gnview library is $gnLibPath from APPDATA environment valiables\n";}
         return($gnLibPath);
      }
   }else{
	  # Windowsでない場合はFreedesktop.org Specification準拠に従って
	  # ライブラリパスを探索する。
	  # ヒットした時点でreturn。
	  if(&gnGetEnvVal('XDG_DATA_HOME')) {
         $gnLibPath = &gnGetEnvVal('XDG_DATA_HOME') . "\/gnview\/";
         if(-d $gnLibPath) {
            if($gnDebugFlag) { print "Your gnview library is $gnLibPath from XDG_DATA_HOME environment valiables\n";}
            return($gnLibPath);
         }
	  }else{
         $gnLibPath = &gnGetEnvVal('HOME') . "\/.local\/share\/gnview\/";
         if(-d $gnLibPath) {
            if($gnDebugFlag) { print "Your gnview library is $gnLibPath from HOME environment valiables\n";}
            return($gnLibPath);
         }
	  }
	  if(&gnGetEnvVal('XDG_DATA_DIRS')) {
         my @dvars = split(/:/, &gnGetEnvVal('XDG_DATA_DIRS'));
         foreach my $dvar(@dvars) {
            chomp($dvar);
            $gnLibPath = $dvar . "\/gnview\/";
            if(-d $gnLibPath) {
               if($gnDebugFlag) { print "Your gnview library is $gnLibPath from XDG_DATA_DIRS environment valiables\n";}
               return($gnLibPath);
            }
         }
      }
      my @dvars = ('/usr/local/share/', '/usr/share/');
      foreach my $dvar(@dvars) {
         chomp($dvar);
         $gnLibPath = $dvar . "gnview\/";
         if(-d $gnLibPath) {
            if($gnDebugFlag) { print "Your gnview library is $gnLibPath from fixed path\n";}
            return($gnLibPath);
         }
      }
   }
   
   if($gnLibPath eq "") {
      print STDERR "Fatal. gnview library path not found. check installation.\n";
   }else{
      if(-d $gnLibPath) {
         if($gnDebugFlag) { print "Your gnview library is $gnLibPath....but where did you point from \?\n";}
         return($gnLibPath);
      }else{
         print STDERR "Fatal. gnview library path you choiced is not found $gnLibPath.\n";
      }
   }
}

sub gnGetEnvVal {
   # 環境変数を取得して、UTF-8フラグをつけて返す関数
   #
   # 引数：文字列(環境変数のキー)
   # 返り値：文字列(環境変数の値。Encode::decodeされた値。存在しなければundefが返る)
   my $key = $_[0];
   
   my $val = Encode::decode(&env_locale_to_encstr($ENV{'LANG'}), $ENV{$key});
   return($val);

}

sub env_locale_to_encstr {
    # ロケール名からEncodeモジュールが解釈できる
    # 文字エンコード名を返す関数
    # 引数=文字列(ロケール名)
    
    # ロケール名を取得
    my $myLocVal = $_[0];

    # Windowsでは"Japanese_Japan"という文字列が使われているので
    # 一括変換しやすいように"ja_JPと置換"
    $myLocVal =~ s/Japanese_Japan/ja_JP/g;
    
    # "ja_JP.eucJP"の"ja_JP"部はいらないので切り取る
    my @myLocStr  = split(/\./, $myLocVal);

    # 後ろの"eucJP"の部分は小文字に置き換える
    # (実際にも大文字・小文字を区別しないよう推奨されている)
    if($myLocStr[1]) {
       $myLocStr[1] = lc($myLocStr[1]);
    }else{
        # SolarisでLocaleの２番目がなかったらeucに決めうち
       if($^O eq 'solaris') {
          push(@myLocStr, "eucjp");
        }
     }
    
    # あとはパターンマッチ
    if    ($myLocStr[1] eq "932")			{ return('cp932');
    }elsif($myLocStr[1] eq "pck")			{ return('cp932');
    }elsif($myLocStr[1] eq "sjis")			{ return('shiftjis');
    }elsif($myLocStr[1] eq "20932")		{ return('euc-jp');
    }elsif($myLocStr[1] eq "eucjp")		{ return('euc-jp');
    }elsif($myLocStr[1] eq "euc-jp")		{ return('euc-jp');
    }elsif($myLocStr[1] eq "euc")			{ return('euc-jp');
    }elsif($myLocStr[1] eq "ujis")			{ return('euc-jp');
    }elsif($myLocStr[1] eq "iso-2022-jp")	{ return('iso-2022-jp');
    }elsif($myLocStr[1] eq "utf-8")		{ return('utf8');
    }elsif($myLocStr[1] eq "utf8")			{ return('utf8');
    }else										{ return('ascii'); # エンコードが判別できなかったらシングルバイトエンコード(単なるバイト列)として解釈する
    }

    
}

sub command_runner {
    # UTF-8 Compliant!
    ## 別スレッドで動く関数
    # goggify.pl(http://spr.mahonri5.net/oggify/)より使用
    if ($gnDebugFlag) { print STDERR "thread-start\n"; }
    my $run = 1;
    my $run2 = 1; 
    my $gnUA_res;
    my $gnUA;
    my $job;
    my $url;
    my $fn;
    my $proxy_flg;
    my $proxy_addr;
    my $proxy_port;
    my $proxy_uname;
    my $proxy_pass;
    # run until return
    while ($run) {

        $job = $queue->dequeue;
        if ($job eq "geturl") {
           $url = $queue->dequeue_nb;
           $fn = $queue->dequeue_nb;
           $proxy_flg = $queue->dequeue;
              if ($gnDebugFlag>1) { print STDERR "proxyflg\: " . $proxy_flg . "\n"; }
           $proxy_addr = $queue->dequeue_nb;
              if ($gnDebugFlag>1) { print STDERR "proxyaddr\: " . $proxy_addr . "\n"; }
           $proxy_port = $queue->dequeue;
              if ($gnDebugFlag>1) { print STDERR "proxyport\: " . $proxy_port . "\n"; }
           $proxy_uname = $queue->dequeue;
              if ($gnDebugFlag>1) { print STDERR "proxyUserID\: " . $proxy_uname . "\n"; }
           $proxy_pass = $queue->dequeue;
              if ($gnDebugFlag>1) { print STDERR "proxyPass\: " . $proxy_pass . "\n"; }
           {
              lock $gnImgGetSt;
              $gnImgGetSt = TRUE;
           }

           if ($run2 == 1) {
              { lock $fnsize; $fnsize = 0; }
              $gnUA = LWP::UserAgent->new;
              $gnUA->agent($gnUsrAgent);
              $gnUA->timeout(15); # 15秒間無反応だったら中断する
              $run2 = 0;
           }

           # プロキシの設定
           if(!($proxy_flg)) {
               $gnUA->proxy('http', undef);
           }elsif($proxy_flg == 1) {
               my $gnUA_proxystr = "http\:\/\/" . $proxy_addr . "\:" . $proxy_port . "\/";
               $gnUA->proxy('http', $gnUA_proxystr);
           }else{
               $gnUA->proxy('http', undef);
           }
           if ($gnDebugFlag>1) { print STDERR "proxy\: " . $gnUA->proxy('http') . "\n"; }
           
           my $gnTotSz = 0;
           $gnUA_res = $gnUA->request(HTTP::Request->new(GET => $url),
                                            sub {
                                               my($chunk, $res) = @_;
                                               my $gnFN = &gnOpenLocal($fn, "a");
                                               #open(gnFN, ">>$fn");
                                                  binmode $gnFN;
                                                  syswrite $gnFN, $chunk, length($chunk);
                                               &gnCloseLocal($fn);
                                               #close(gnFN);
                                               $gnTotSz += length($chunk);
                                               if ($gnDebugFlag>1) { print STDERR "thread-write\: " . $gnTotSz . "\/$fnsize bytes\n"; }
                                            });
           {
              lock $gnImgGetSt;
              $gnImgGetSt = FALSE;
           }
        }elsif($job eq "exit") {
           $run = 0;
        }
        { lock $hold; $hold = 0; } 
    }    
    
}

