Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

Commit

Permalink
Refectoring and Refactoring.
Browse files Browse the repository at this point in the history
Hopefully fixed the blocking issue.
(status): added to check status availability.
  • Loading branch information
takuo committed Sep 4, 2009
1 parent ee7e2ba commit fe49e4d
Showing 1 changed file with 125 additions and 99 deletions.
224 changes: 125 additions & 99 deletions imaprowl.rb
Expand Up @@ -26,25 +26,98 @@ class IMAProwl

PROWL_API_ADD = "https://prowl.weks.net/publicapi/add"

attr_reader :thread
attr_reader :logged_in
attr_reader :idle_time
attr_reader :interval

@@conf = Hash.new
@@logger = nil
@@prowl_conf = nil

attr_reader :enable
attr_reader :idle_thread

def initialize( global, conf )
@@conf = global
_prowl_conf_validate( global['Prowl'] )
@application = conf['Application'] ? conf['Application'] : "IMAProwl"
@user = conf['User']
@pass = conf['Pass']
@host = conf['Host']
@port = conf['Port'] ? conf['Port'] : 993
@mailbox = conf['MailBox'] ? conf['MailBox'] : "INBOX"
@interval = conf['Interval'] ? conf['Interval'] : 20
@length = conf['BodyLength'] ? conf['BodyLength'] - 1 : 99
@length = 1 if @length < 0
@priority = conf['Priority'] ? conf['Priority'] : 0
@notified = []
@enable = conf.has_key?('Enable') ? conf['Enable'] : true
end

# start() should run only once
def start
info "Starting..."
connect()
unless @imap.capability.include?( 'IDLE' )
error "Error: #{@host} does not support IDLE."
begin
@imap.disconnect
ensure
@enable = false
return
end
end
login()
check_unseen( false )
idler()
end

def restart
info "Restarting..."
connect()
login()
check_unseen( true )
idler()
debug "Restarted"
end

def stop
@imap.idle_done
debug "DONE IDLE."
end

def status
retried = false
debug "Check process status..."
begin
if @imap.disconnected?
@idle_thread.exit if @idle_thread.alive?
error "socket is disconnected. trying to reconnect..."
restart
elsif ! @idle_thread.alive?
error "IDLE thread is dead."
restart
end
if @interval > 0 && Time.now - @idle_time > 60 * @interval
info "encounter interval."
stop
end
rescue
@idle_thread.exit if @idle_thread.alive?
error $!.to_s
unless retried
retried = true
retry
end
end
end

private
def _prowl_conf_validate(val)
def _prowl_conf_validate( val )
return if @@prowl_conf
@@prowl_conf = val
unless @@prowl_conf.kind_of?(Hash)
STDERR.printf "Configuration Error: Prowl section must be Hash.\n"
unless @@prowl_conf.kind_of?( Hash )
STDERR.print "Configuration Error: Prowl section must be Hash.\n"
exit 1
end
unless @@prowl_conf.has_key?('APIKey')
STDERR.printf "Configuration Error: APIKey must be given.\n"
unless @@prowl_conf.has_key?( 'APIKey' )
STDERR.print "Configuration Error: APIKey must be given.\n"
exit 1
end
_init_logger()
Expand All @@ -53,77 +126,53 @@ def _prowl_conf_validate(val)
def _init_logger
if @@conf['LogDir']
logdir = @@conf['LogDir']
Dir.mkdir(logdir) unless Dir.exist?(logdir)
STDOUT.puts "All logs will be written into #{File.join(logdir, "imaprowl.log")}."
Dir.mkdir( logdir ) unless File.exist?( logdir )
filename = File.join( logdir, "imaprowl.log" )
STDOUT.puts "All logs will be written into #{filename}."
STDOUT.flush
@@logger = Logger.new(File.join(logdir, "imaprowl.log"), 'daily')
@@logger = Logger.new( filename, 'daily' )
@@logger.level = @@conf['Debug'] ? Logger::DEBUG : Logger::INFO
@@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
@@logger.datetime_format = "%Y-%m-%dT%H:%M:%S"
else
@@logger = nil
STDOUT.sync = true
STDERR.sync = true
end
end

def _log(severity, str)
def _log( severity, str )
if @@logger
@@logger.add(severity, str, @application)
@@logger.add( severity, str, @application )
else
format = "[%Y-%m-%dT%H:%M:%S##{Process.pid}] #{@application} - #{str}\n"
if severity == Logger::ERROR
STDERR.print Time.now.strftime("[%Y.%m.%d %H:%M:%S] #{@application} - "), str, "\n"
STDERR.print Time.now.strftime( format )
else
print Time.now.strftime("[%Y.%m.%d %H:%M:%S] #{@application} - "), str, "\n"
print Time.now.strftime( format )
end
end
end

public
def debug(str)
_log(Logger::DEBUG, str)
def debug( str )
_log( Logger::DEBUG, str )
end

def error(str)
_log(Logger::ERROR, str)
def error( str )
_log( Logger::ERROR, str )
end

def info(str)
_log(Logger::INFO, str)
end

def initialize(global, conf)
@@conf = global
_prowl_conf_validate(global['Prowl'])
@application = conf['Application'] ? conf['Application'] : "IMAProwl"
@user = conf['User']
@pass = conf['Pass']
@host = conf['Host']
@port = conf['Port'] ? conf['Port'] : 993
@mailbox = conf['MailBox'] ? conf['MailBox'] : "INBOX"
@interval = conf['Interval'] ? conf['Interval'] : 20
@length = conf['BodyLength'] ? conf['BodyLength'] - 1 : 99
@length = 1 if @length < 0
@priority = conf['Priority'] ? conf['Priority'] : 0
@notified = []
connect()
unless @imap.capability.include?('IDLE')
error "Error: #{@host} does not support IDLE."
begin
@imap.disconnect
rescue
end
return nil
end
def info( str )
_log( Logger::INFO, str )
end

def login
return true if @logged_in
ret = @imap.login(@user, @pass)
ret = @imap.login( @user, @pass )
if ret.name != "OK"
error "Failed to login: user: #{@user}@#{@host}."
return false
end
@imap.select(@mailbox)
check_unseen(false)
@imap.select( @mailbox )
@logged_in = true
return true
end
Expand All @@ -141,17 +190,6 @@ def disconnected?
return @imap.disconnected?
end

def run
info "Start."
idler()
end

def stop
@imap.idle_done
debug "Stop IDLE."
end

private
def prowl( params = {} )
uri = URI::parse( PROWL_API_ADD )
if @@prowl_conf['ProxyHost']
Expand All @@ -178,7 +216,7 @@ def prowl( params = {} )
def check_unseen( prowl = false )
debug "Checking UNSEEN mail."

unseen = @imap.search(['UNSEEN'])
unseen = @imap.search( ['UNSEEN'] )
return unless unseen.size > 0

unseen_set = Array.new
Expand Down Expand Up @@ -218,7 +256,7 @@ def check_unseen( prowl = false )
body = attr['BODY[1]']
end

body = NKF.nkf('-w', body)
body = NKF.nkf( '-w', body )
body = body.split(//u)[0..@length].join

# prowling
Expand All @@ -241,10 +279,9 @@ def check_unseen( prowl = false )
# caching
@notified = unseen_set
end

def idler
return unless login()
@thread = Thread.new do
@idle_thread = Thread.start do
loop do
begin
event = false
Expand All @@ -261,60 +298,49 @@ def idler
check_unseen(true) if event
rescue
error "Error in idler(): #{$!}"
begin
## unlock IDLE if it still exists.
@imap.idle_done
rescue
end
##begin
## ## unlock IDLE if it still exists.
## @imap.idle_done
##rescue
## debug "Error sending DONE."
##end
debug "Exiting thread"
Thread.current.exit
end
debug "idler(): Still in loop"
end # loop
end
end # Thread
end

end
end # class

Dir.chdir(File.dirname(__FILE__))
config = YAML.load_file('config.yml')

# Create Account Thread
application = Array.new
config['Accounts'].each do |account|
a = IMAProwl.new(config, account)
next if a.nil?
a.run
application.push(a)
app = IMAProwl.new( config, account )
app.start()
application.push( app ) if app.enable
end

Signal.trap("INT") {
application.each { |a|
application.each { |app|
begin
a.stop;
app.stop
ensure
Thread.kill( a.thread ) if a.thread.alive?
sleep 1
app.idle_thread.exit if app.idle_thread.alive?
end
}
print "DEBUG: Number of Threads: #{Thread.list.size}\n"
exit
}

loop do
sleep 60
application.each do |a|
begin
if a.interval > 0 && Time.now - a.idle_time > 60 * a.interval
a.stop
end
unless a.thread.alive?
a.error "socket is disconnected. trying to reconnect..."
a.connect
a.run
a.debug "Restarted"
end
rescue
Thread.kill( a.thread ) if a.thread.alive?
a.error $!.to_s
a.debug $!.backtrace.to_s
end
application.each do |app|
app.status
end
end

0 comments on commit fe49e4d

Please sign in to comment.