#このファイルはGPLで配付しています.
#このプログラムは無保証です.
# connect2ch.rb  version 0.08
# 春山 征吾 haruyama@unixuser.org
# $Id: connect2ch.rb,v 1.16 2002/01/28 03:24:19 haruyama Exp $

# EUC版
# まだ適当

require 'kconv'
require 'net/http'
require 'timeout'
begin
  require 'zlib'
  $connect_2ch_gzip = true
rescue LoadError
  #
  $connect_2ch_gzip = false
end


def parse_http_url(url)
  # httpsやftp は別に扱うか
  if %r!^h?ttp://(\S*?)(?::(\d+))?(/\S*)?$! =~  url
    host = $1
    if $2
      port = Integer($2)
    else
      port = 80
    end
    path = $3
    return host,port,path
  else
    return nil,nil,nil
  end

end


module PostMessage2ch

  def http_encode(str)
    return str.gsub(/[^a-zA-Z0-9_.-]/n){sprintf("%%%02X",$&.unpack("C")[0]) }
  end

  def quote(str)
#まだなし
    return str
  end

  def convert_and_encode(str)
    str = Kconv::kconv(str,Kconv::SJIS,Kconv::EUC)
    return http_encode(str)
  
  end


  def post_message(thread,name,mailto,message)
    host = thread.get_host
    port = thread.get_port
    path = thread.get_base_path + "test/bbs.cgi"
    bbs = thread.get_bbs
    key = thread.get_key
    if port == 80
      tmp  = "http://#{host}/"
    else
      tmp  = "http://#{host}:#{port}/"
    end
    referer = tmp + "#{bbs}/index2.html"
    return post_message_(host,port,path,referer,bbs,key,name,mailto,message)
  end

  def post_message_(host,port,path,referer,bbs,key,name,mailto,message)
    kakikomu='書きこむ'
    kakikomu = convert_and_encode(kakikomu)
    name = convert_and_encode(name)
    mailto = convert_and_encode(mailto)
    message = convert_and_encode(message)

#    time
    time = Time.now.to_i.to_s


    header = {}

    header["Referer"]= referer
    header["Content-Type"]= "application/x-www-form-urlencoded"
    header["Cookie"]= "NAME=#{name};MAIL=#{mailto}"
    
    Net::HTTP.start(host,port ) {|http|
#/test/bbs.cgi
#      p path
#      p     "submit=#{kakikomu}&FROM=#{name}&mail=#{mailto}&MESSAGE=#{message}&bbs=#{bbs}&key=#{key}&time=#{time}"
      
      begin
	response , = http.post( path,
			       "submit=#{kakikomu}&FROM=#{name}&mail=#{mailto}&MESSAGE=#{message}&bbs=#{bbs}&key=#{key}&time=#{time}",
			     header)


# なにか失敗があれば return false
	if response.code == "200"
	  return true
	else
	  STDERR.print Kconv::kconv(response.body,Kconv::EUC,Kconv::SJIS)
	  return false
	end
      rescue Net::ProtoRetriableError
# 一度出たので明示的に取ってみる
# リダイレクトページだと出るようだ
#	print "Net::ProtoRetriableError\n"
#	print "例外発生。書きこまれたかどうかわかりません。\n"
	return true
      rescue
	print "例外発生。書きこまれたかどうかわかりません。\n"
	return false
      end
    }
  end


end


module HTTPGetGzip


  def http_get_file(host,port,path,filename,gzip=true)

    http_header = {}
    if gzip
      gzip =  $connect_2ch_gzip
    end
    
    if gzip
      http_header["Accept-Encoding"]="gzip"
    end


# Thanks >>7
    file = nil
    begin
      timeout(60){
	Net::HTTP.start(host,port,$proxy_addr,$proxy_port){ |http|
#	http.open_timeout=60
#	http.read_timeout=60
	  response , = http.get(path,http_header)
	  begin
	    file = open( filename, 'w+' )
	  rescue 
	    STDERR.print "#{filename}が開けませんでした。\n"    
	    return nil
	  end
	  file.write response.body
	  file.rewind
	  if  gzip == true && response['Content-Encoding'] == "gzip"
	    begin 
	      file=Zlib::GzipReader.new(file)
	    rescue
	    end
	  end
	}
      }
    rescue 
      STDERR.print "ファイルの取得に失敗。\n"    
      return nil
    end
    return file
  end
end


module GetThread2ch
  include HTTPGetGzip

  def file_change(from,to)
    File.rename(from,to)

    begin
      file =  open(to,'r')
    rescue
      STDERR.print "#{to}が開けませんでした。\n"    
      return nil
    end


    begin
      file = Zlib::GzipReader.new(file)
    rescue
    end
    return file
  end

  def get_thread_file(thread,size=0,num_of_statements=0)
    host = thread.get_host
    port = thread.get_port
    path = thread.get_path
    filename = thread.get_filename
    file = thread.get_file    
    dat=  thread.get_dat
    return get_thread_file_(host,port,path,filename,file,dat,size,num_of_statements)
  end


  def get_thread_file_(host,port,path,filename,file,dat=nil,size=0,num_of_statements=0)

    if file 
      file.rewind
    else
      if File.exist?(filename)
	begin
	  file = open( filename, 'r' )
	rescue
	  STDERR.print "#{filename}が開けませんでした。\n"   
	  return nil,nil
	end
	begin
	  file = Zlib::GzipReader.new(file)
	rescue  
	  # gzipでない場合
	end
      end
    end


    #差分読みこみ用準備 差分の処理はかなりいいかげん

    if size <=0 && num_of_statements <=0
      size =0
      num_of_statements=0
      if file 
	file.each{ |line|
	  line=Kconv::kconv(line,Kconv::EUC,Kconv::SJIS)
	  if /^(?:\+OK|-INCR)\s+(\d+)/ =~ line
	    size+=Integer($1)
	  else
	    num_of_statements+=1
	  end
	}
      end

    end



    if dat
      # dat直読み
      return get_thread_file_via_dat(host,port,path,filename),num_of_statements
    else
      return get_thread_file_via_read_cgi(host,port,path,filename,file,size,num_of_statements)
    end

  end

#未テスト
  def get_thread_file_via_dat(host,port,path,filename)
    
    file = http_get_file(host,port,path,filename)
    if file ==nil
      STDERR.print "datファイルの取得に失敗しました。\n"
      if File.exist?(filename)
	STDERR.print "キャッシュを利用します。\n"
	begin
	  file = open( filename, 'r' )
	rescue
	  STDERR.print "#{filename}が開けませんでした。\n"   
	  return nil
	end
	begin
	  file = Zlib::GzipReader.new(file)
	rescue  
	  # gzipでない場合
	end
      else
	STDERR.print "キャッシュもありません。\n"
	return nil
      end

    end
    return file
    
  end

  def get_thread_file_via_read_cgi(host,port,path,filename,file,size=0,num_of_statements=0)


    if path =~ /\?/
      path += "&raw=#{num_of_statements}.#{size}"
    else
      path += "?raw=#{num_of_statements}.#{size}"
    end

    tmp_filename = filename+"_tmp"
    tmp_file = http_get_file(host,port,path,tmp_filename)

    if tmp_file ==nil
      STDERR.print "thread情報ファイルの取得に失敗しました。\n"
      if file
	STDERR.print "キャッシュを利用します.\n"
	return file,nil
      else
	STDERR.print "キャッシュもありません.\n"
	return nil,nil
      end
    end
    
    line= tmp_file.gets
    line=Kconv::kconv(line,Kconv::EUC,Kconv::SJIS)
    #TODO: サイズが0のときは追加しないようにする

    if /^\+OK\s+(\d+)/ =~ line
      if $1 == "0"
	tmp_file.close
	File.unlink(tmp_filename)
	return file,num_of_statements
      end

      tmp_file.rewind
      if file 

	file.rewind
	contents = file.read
	file.close
	# fileがかならずしもgzipで圧縮されているとはかぎらないので
	# 面倒なことをする
	# また GzipReaderにはrewindはあってもseekはないし
	# (gzipのヘッダ フッタのためだろう)
	begin
	  file = open(filename,'w')
	rescue
	  STDERR.print "#{filename}が開けませんでした。\n"    
	  return nil,nil
	end

	file = Zlib::GzipWriter.new(file)
	
	file.write  contents
	file.write  tmp_file.read
	
	file.close
	tmp_file.close

	File.unlink(tmp_filename)

	begin
	  file =  open(filename,'r')
	rescue 
	  STDERR.print "#{filename}が開けませんでした。\n"    
	  return nil,nil
	end
	  

	file = Zlib::GzipReader.new(file)
      else
	tmp_file.close
	file = file_change(tmp_filename,filename)
      end
    elsif  /^\-INCR/ =~ line
      if file
	file.close
      end
      tmp_file.close

      file = file_change(tmp_filename,filename)
    else
      STDERR.print "thread情報ファイルに異常があります。\n"
      tmp_file.close
      File.unlink(tmp_filename)
      return file,nil
    end
    return file,num_of_statements
  end


end

module  GetBoardSubject2ch
  include HTTPGetGzip


  def get_board_subject_file(board)
    host = board.get_host
    port = board.get_port
    path = board.get_path
    filename = board.get_filename

    if board.get_dat
      return get_board_subject_file_dat(host,port,path,filename)
    else
      return get_board_subject_file_read_cgi(host,port,path,filename)
    end
  end

  def get_board_subject_file_read_cgi(host,port,path,filename,ls=nil)
    # lsは未テスト
    if %r!^(.*)(/[^/]+/)$! =~ path
      path2 = $1 + "/test/read.cgi" + $2 + "?raw=0.0"
      if ls 
	path2 += "&ls=#{ls}"
      end
    else
      return get_board_subject_file_(host,port,path,filename,nil)
    end
    file=http_get_file(host,port,path2,filename)
    return get_board_subject_file_(host,port,path,filename,file)
  end

  def get_board_subject_file_dat(host,port,path,filename)
    
    path2 = path + "subject.txt"
    file=http_get_file(host,port,path2,filename)
    return get_board_subject_file_(host,port,path,filename,file)
  end

  def get_board_subject_file_(host,port,path,filename,file)
    # Thanks >>8:
    if file == nil
      STDERR.print "subjectファイルの取得に失敗しました。\n"
      if File.exist?(filename)
	STDERR.print "キャッシュを利用します.\n"
	begin
	  file = open( filename, 'r' )
	rescue
	  STDERR.print "#{filename}が開けませんでした。\n"   
	  return nil
	end
	begin
	  file = Zlib::GzipReader.new(file)
	rescue  
         # gzipでない場合
	end
	return file
      else
	STDERR.print "キャッシュもありません.\n"
      end

      return nil
    end

    

    return file

  end

end

#未テスト
module  GetBoardInfo2ch
  include HTTPGetGzip

  def get_board_info(host,port,path)
     Net::HTTP.start(host,port,$proxy_addr,$proxy_port){ |http|
      response,= http.get(path,nil)

      if response.code == "200"
	return response.body
      else
	return nil
      end
    }
  end

  def parse_board_info_html(body)

    flag = 0
    info = []
    body.each { |line|
      while true
	line=Kconv::toeuc(line)
#	p line
	line.strip!
	if /^<B>(.*?)<\/B><BR>(.*)$/i =~  line
	  tmp ="C " + $1 +"\n"
	  if "チャット" == $1
	    return info
	  elsif "まちＢＢＳ" == $1
	    flag=0
	  else
	    flag=1
	    info << tmp
	  end
	  line = $2
	elsif /^<A HREF=([^> ]*).*?>(.*?)<\/A>(.*)$/i =~ line
	  line = $3
	  if $1 != "http://www.machibbs.com/"
	    if flag ==1
	      tmp = "B " 
	    elsif flag ==2
	      tmp = "A " 
	    end
	    if flag > 0 
	      tmp1 = $1
	      tmp2 = $2
	      tmp2.gsub!(/<br>/i," ")
	      tmp += tmp1 + " " + tmp2  + "\n"
	      info << tmp
	    end
	  end
	elsif /^.+?((<B>|<A).*)$/i =~ line
	  line = $1
	else
	  break
	end
      end
    }
    return info
  end

end
