Difference between revisions of "Chewie71-Notes"

(New page: #!/usr/local/bin/ruby # == Synopsis # This application updates RSS Feed folders in Zmibra user accounts. # # == Examples # This command does RSS folder updates. # update_feeds ...)
 
(Removing all content from page)
Line 1: Line 1:
#!/usr/local/bin/ruby
 
  
# == Synopsis
 
#  This application updates RSS Feed folders in Zmibra user accounts. 
 
#
 
# == Examples
 
#  This command does RSS folder updates.
 
#    update_feeds
 
#
 
#  Other examples:
 
#    ruby_cl_skeleton -q bar.doc
 
#    ruby_cl_skeleton --verbose foo.html
 
#
 
# == Usage
 
#  update_feeds [options]
 
#
 
#  For help use: update_feeds -h
 
#
 
# == Options
 
#  -u, --user          User to synchronize {uid|email|all}
 
#  -h, --help          Displays help message
 
#  -t, --test          Displays test/debug information and logs DEBUG messages
 
#  -v, --version      Display the version, then exit
 
#  -q, --quiet        Output as little as possible, overrides verbose
 
#  -V, --verbose      Verbose output
 
#  TO DO - add additional options
 
#
 
# == Author
 
#  Matt Mencel
 
#
 
# == Copyright
 
#  Copyright (c) 2008 Matt Mencel. Licensed under the MATT License:
 
 
require "date"
 
require "logger"
 
require "pathname"
 
require "open3"
 
require "optparse"
 
require "ostruct"
 
require "rdoc/usage"
 
 
require 'rubygems'
 
require 'icalendar'
 
require 'rss/1.0'
 
require 'rss/2.0'
 
require 'open-uri'
 
require 'hpricot'
 
 
 
class App
 
  VERSION = '0.0.1'
 
   
 
  attr_reader :options
 
 
  def initialize(arguments, stdin)
 
    @arguments = arguments
 
puts "INITARGS: #{@arguments}"
 
puts "ARGSLGTH: #{@arguments.size}"
 
    @stdin = stdin
 
   
 
    # Set defaults
 
    @options = OpenStruct.new
 
    @options.verbose = false
 
    @options.quiet = false
 
    # TO DO - add additional defaults
 
  end
 
 
 
  # Parse options, check arguments, then process the command
 
  def run
 
    puts "OPTS: #{parsed_options?}"
 
puts "VALIDARGS: #{arguments_valid?}"
 
    if parsed_options? && arguments_valid?
 
      puts "Start at #{DateTime.now}\\n\\n" if @options.verbose
 
      output_options if @options.verbose # [Optional]
 
      process_arguments           
 
      process_command
 
      puts "\\nFinished at #{DateTime.now}" if @options.verbose
 
    else
 
      output_usage
 
    end
 
  end
 
 
 
  protected
 
  def parsed_options?
 
    # Specify options
 
    opts = OptionParser.new
 
    opts.on('-h', '--help')      { output_help }
 
    opts.on('-v', '--version')    { output_version ; exit 0 }
 
    opts.on('-V', '--verbose')    { @options.verbose = true } 
 
    opts.on('-q', '--quiet')      { @options.quiet = true }
 
    # TO DO - add additional options
 
    opts.on('-u', '--user USER', 'User to sync RSS folders {uid|mail|all}.') do |u|
 
      options.user = u
 
    end
 
    opts.parse!(@arguments) rescue return false
 
 
    process_options
 
    true
 
  end
 
 
  # Performs post-parse processing on options
 
  def process_options
 
    @options.verbose = false if @options.quiet
 
  end
 
 
  def output_options
 
    puts "Options:\\n"
 
 
    @options.marshal_dump.each do |name, val|
 
      puts "  #{name} = { #{val}"
 
    end
 
  end
 
 
  # True if required arguments were provided
 
  def arguments_valid?
 
    # TO DO - implement real logic here
 
    puts "VALIDARGS: #{@arguments}"
 
    puts "ARGV Length: #{@arguments.size}"
 
    true if @arguments.length >= 0
 
  end
 
 
  # Setup the arguments
 
  def process_arguments
 
    # TO DO - place in local vars, etc
 
  end
 
 
  def output_help
 
    output_version
 
    RDoc::usage() #exits app
 
  end
 
 
  def output_usage
 
    RDoc::usage('usage') # gets usage from comments above
 
  end
 
 
  def output_version
 
    puts "#{File.basename(__FILE__)} version #{VERSION}"
 
  end
 
 
  def process_command
 
    # Setup Logger
 
    $logger = Logger.new('rss_folder.log', 'daily')
 
    if @options.verbose
 
      $logger.level = Logger::DEBUG
 
    else
 
      $logger.level = Logger::INFO
 
    end
 
     
 
    # OPEN THE ZMPROV PROMPT
 
     
 
    #$cmdin, $cmdout, $cmderr = Open3.popen3("zmprov")
 
    $cmdin, $cmdout, $cmderr = Open3.popen3("zmprov 2>&1")
 
    puts $cmdout.readpartial(4096)
 
    # Create RSS and Calendar Hashes
 
    feeds=Hash.new
 
    calendars = Hash.new
 
   
 
    $cmdin.puts("sm shares@wiu.edu")
 
    $cmdin.puts("gaf")
 
    $cmdin.puts("sm")
 
    count=0
 
    $cmdout.each do |line|
 
      count += 1 if line == "\n"
 
      line.split("  ").each do |subline|
 
        if subline.include?("Feeds/")
 
          record = subline.split("(")
 
          feeds[record[0].rstrip] = record[1].rstrip.chop
 
        elsif subline.include?("Calendars/")
 
          if subline.include?("(")
 
            record = subline.split("(")
 
            calendars[record[0].rstrip] = record[1].rstrip.chop
 
          else 
 
            calendars[subline.chomp] = "from feed"
 
          end
 
        end
 
      end
 
      break if count == 2
 
    end
 
     
 
    puts "FEEDS: #{feeds.inspect}"
 
    puts "CALENDARS: #{calendars.inspect}"
 
   
 
    # Testing RSS Feeds for Admin COS Users
 
    #users = `zmprov sa zimbraCOSId=5487b59c-de80-4220-a819-07a6a84ed122`.split()
 
    users=[]  # start with an empty array
 
    puts "Fetching employee list..."
 
    employees = Hash.new
 
    employees_array = Array.new(`zmprov sa "(zimbraCOSId=70fadfad-cf1f-4f67-bb58-dd3e44f77942)"`.split() + `zmprov sa "(zimbraCOSId=5487b59c-de80-4220-a819-07a6a84ed122)"`.split())
 
    employees_array.each do |emp|
 
      employees[emp.downcase] = 1
 
    end
 
    f = File.open("testusers.full") or die "Unable to open file..."
 
    f.each_line {|line|
 
      users << line.chomp.downcase
 
    }
 
    #users = ["mr-mencel@wiu.edu","f-seaton@wiu.edu","r-runquist@wiu.edu"]
 
    user_count = users.size()
 
    # Refresh WIU Feeds In Share Account
 
      feeds.each_pair {|folder, feed_url|
 
        folder_path = Pathname.new(folder)
 
        puts "REFRESH FEED #{folder_path}"
 
        refresh_feed("shares@wiu.edu", folder_path, feed_url)
 
      }
 
     
 
      # Refresh WIU Calendars in Share Account
 
      calendars.each do |calendar, calendar_url|
 
        folder_path = Pathname.new(calendar)
 
        puts "REFRESH CALENDAR: #{folder_path}"
 
        if folder_path.to_s.include?("Athletics")
 
          cal = build_calendar_ics("Athletics")
 
          pru(cal, folder_path)
 
        elsif folder_path.to_s.include?("Fine Arts")
 
          cal = build_calendar_ics("Art Gallery, BCA, Fine Arts, Theater")
 
          pru(cal, folder_path)
 
        elsif folder_path.to_s.include?("Registrar")
 
          cal = build_calendar_ics("Registrar")
 
          pru(cal, folder_path)
 
        else
 
          refresh_calendar("shares@wiu.edu", folder_path, calendar_url)
 
        end
 
      end
 
       
 
    # Subscribe users to Feeds and Calendars
 
    user_count = users.size()
 
    t = Time.now
 
    users.each do |user|
 
      puts "Creating Shares for #{user}...#{user_count-=1} remaining"
 
      feeds.each_pair {|folder, feed_url|
 
        folder_path = Pathname.new(folder)
 
        create_share(user, employees, folder_path)
 
      }
 
       
 
      calendars.each_pair do |folder, calendar_url|
 
        folder_path = Pathname.new(folder)
 
        create_share(user, employees, folder_path)
 
      end
 
      if user_count%25 == 0
 
        t2 = Time.new
 
        diff = t2.to_i - t.to_i
 
        puts "#{(diff)*(user_count/25/60)} minutes remaining"
 
        t = Time.new
 
      end
 
    end
 
     
 
 
 
       
 
    #process_standard_input # [Optional]
 
  end
 
 
  def process_standard_input
 
    input = @stdin.read     
 
    # TO DO - process input
 
     
 
    # [Optional]
 
    # @stdin.each do |line|
 
    #  # TO DO - process each line
 
    #end
 
  end
 
end
 
 
 
# TO DO - Add Modules, Classes, etc
 
### FUNCTIONS ###
 
 
#def create_feed_folder(user, folder_path, feed_url)
 
#  $logger.debug("DEBUG: zmmailbox -z -m #{user} createFolder -u '#{feed_url}' '#{folder_path}'")
 
#  $logger.info("Creating missing folder #{folder_path} for #{user}")
 
#  cmd_result = cmd_to_sys("zmmailbox -z -m #{user} cf -u '#{feed_url}' '#{folder_path}'")
 
#  $logger.debug("ERROR?: #{cmd_result[1]}")
 
#  if check_command_result(cmd_result[1], user, feed_url) == "unknown folder"
 
#    $logger.warn(cmd_result[1])
 
#    create_feed_folder(user, folder_path.dirname(), nil)
 
#    $logger.debug("ATTEMPTING TO RECREATE: #{folder_path}")
 
#    cmd_result = cmd_to_sys("zmmailbox -z -m #{user} cf -u '#{feed_url}' '#{folder_path}'")
 
#    check_command_result(cmd_result[1], user, feed_url)
 
#  end
 
#  $logger.debug("Created Folder #{folder_path}")
 
#end
 
 
def build_calendar_ics(cal_list)
 
  # Create a new calendar object
 
  cal = Calendar.new
 
  cal_list.split(",").each do |cal_name|
 
    $all_day = false
 
    case cal_name
 
    when /Art Gallery/  ; source = "http://www.wiu.edu/wiucalendar/xml.sphp?calendar=Art+Gallery"
 
    when /Athletics/  ; source = "http://www.wiuathletics.com/rss.dbml?db_oem_id=12000&media=schedules"
 
    when /BCA/        ; source = "http://www.wiu.edu/wiucalendar/xml.sphp?calendar=Bureau+of+Cultural+Affairs"
 
    when /Fine Arts/  ; source = "http://www.wiu.edu/wiucalendar/xml.sphp?calendar=School+of+Music"
 
    when /Registrar/  ; source = "http://www.wiu.edu/wiucalendar/xml.sphp?calendar=Office+of+the+Registrar" ; $all_day = true
 
    when /Theater/    ; source = "http://www.wiu.edu/wiucalendar/xml.sphp?calendar=Department+of+Theatre+%26+Dance"
 
    end
 
    content = "" # raw content of rss feed will be loaded here
 
    open(source) do |s| content = s.read end
 
    rss = RSS::Parser.parse(content, false)
 
    puts "Fetching #{rss.items.size} RSS items for: #{cal_name}"
 
    #print "number of items: ", rss.items.size, "\n"
 
   
 
    rss.items.each do |item|
 
      result = parse_feeds_for_calendars(item)
 
      event_location = result.split(" :: ")[0]
 
      item.description = result.split(" :: ")[1]
 
           
 
      #puts DateTime.parse(item.date.to_s).new_offset(of=0)
 
      #puts Date.parse(item.date.to_s)
 
      endtime = item.date+(60*60*2)
 
      cal.event do
 
        if $all_day
 
          dtstart Date.parse(item.date.to_s)
 
          dtend  Date.parse(item.date.to_s)
 
        else
 
          dtstart  DateTime.parse(item.date.to_s).new_offset(of=0)
 
          dtend    DateTime.parse(endtime.to_s).new_offset(of=0)
 
        end
 
        summary  item.title
 
        description  item.description
 
        location    event_location
 
        uid      "#{item.link}#{DateTime.parse(item.date.to_s)}"
 
      end
 
    end
 
  end
 
  return cal
 
end
 
 
def parse_feeds_for_calendars(item)
 
  if item.link.include?("wiuathletics")
 
    $all_day = false
 
    #puts "DESC: "+item.description
 
    #puts "LINK: "+item.link
 
    #puts "DATE: #{item.date}"
 
    event_data = item.description.split(" - ")
 
    event_location = event_data[0].split("at ")[1]
 
    event_time = event_data[1].split("-")[0]
 
    if !event_time.include?(":")
 
        event_time = "#{event_time.split(' ')[0]}:00 #{event_time.split(' ')[1]}"
 
    end
 
    if event_time.include?('p.m.')
 
      event_time = "#{event_time.split(' ')[0].split(':')[0].to_i + 12}:#{event_time.split(' ')[0].split(':')[1]}"
 
    elsif event_time.include?("a.m.")
 
      event_time = event_time.split(' ')[0]
 
      event_time = "0#{event_time}" if event_time.split(':')[0].to_i < 10
 
    end
 
    if event_time.include?("TBA")
 
      $all_day = true
 
      item.date = "#{Date.parse(item.date.to_s)}T08:00:00+00:00"
 
    else
 
      item.date = "#{Date.parse(item.date.to_s)}T#{event_time}:00+00:00"
 
    end
 
    item.description = "#{event_location} :: #{item.link}"
 
    #html/body/table/tbody/tr/td/div[2]/div/table/tbody/tr/td[2]/table/tbody/tr[7]/td/table
 
  else
 
    @url = item.link
 
    @response = ''
 
    # open-uri RDoc: http://stdlib.rubyonrails.org/libdoc/open-uri/rdoc/index.html
 
    open(@url, "User-Agent" => "Ruby/#{RUBY_VERSION}",
 
      "From" => "help@wiu.edu",
 
      "Referer" => "http://zimbra.wiu.edu") { |f|
 
        puts "Fetched document: #{f.base_uri}"
 
        #puts "\\t Content Type: #{f.content_type}\\n"
 
        #puts "\\t Charset: #{f.charset}\\n"
 
        #puts "\\t Content-Encoding: #{f.content_encoding}\\n"
 
        #puts "\\t Last Modified: #{f.last_modified}\\n\\n"
 
   
 
        # Save the response body
 
        @response = f.read
 
      }
 
      #Rdoc: http://code.whytheluckystiff.net/hpricot/
 
      doc = Hpricot(@response)
 
 
      event_location = (doc/"/html/body/div/div[4]/div/dl/dd[2]").inner_html.split(': </strong>')[1].strip
 
      item.description = "#{event_location} :: #{item.description}\n\n#{item.link}"
 
    end
 
   
 
end
 
 
 
def create_share(user, employees, folder_path)
 
  if folder_path.to_s.include?("Staff") && !employees.has_key?(user)
 
    puts "Not Staff...continuing with next folder"
 
    return
 
  end
 
  $logger.debug("DEBUG: zmmailbox -z -m #{user} createMountpoint -c purple '#{folder_path}' shares@wiu.edu '#{folder_path}'")
 
  $logger.info("Creating missing share #{folder_path} for #{user}")
 
  cmd_result = sm(user)
 
  cmd_result = cm(user, folder_path)
 
  #puts cmd_result
 
  if cmd_result != nil
 
    case cmd_result
 
    when /ALREADY_EXISTS/ ; return
 
    when /unknown folder/ ; cf(user, folder_path)
 
    when /permission denied/ ; mfg(user, folder_path)
 
    else ; $logger.fatal("Unknown Error: #{cmd_result[1]} on share #{folder_path} for #{user}")
 
end
 
    $logger.debug("ATTEMPTING TO RECREATE SHARE #{folder_path}")
 
    create_share(user, folder_path)
 
  else
 
    $logger.info "Shared #{folder_path} with #{user}"
 
  end
 
end
 
 
def is_integer(to_test)
 
  begin
 
    Integer(to_test)
 
    return true
 
  rescue ArgumentError
 
    return false
 
  end
 
end
 
 
def refresh_calendar(user, folder_path, calendar_url)
 
  $logger.debug("DEBUG: zmmailbox -z -m #{user} syncFolder '#{folder_path}'")
 
  cmd_result = sm(user)
 
  #syncFolder
 
  cmd_result = sf(folder_path)
 
  #puts cmd_result
 
  if cmd_result != nil
 
    case cmd_result
 
    when /unknown folder/ ; puts "Missing or Bad Share!?"; exit
 
  end
 
  else
 
    $logger.info "Refreshed #{folder_path} for #{user}"
 
  end
 
end
 
 
def refresh_feed(user, folder_path, feed_url)
 
  $logger.debug("DEBUG: zmmailbox -z -m #{user} syncFolder '#{folder_path}'")
 
  cmd_result = sm(user)
 
  #Mark and Purge Old Messages
 
  msg_ids_for_deletion = smb(folder_path, "before:-30days")
 
  dm(msg_ids_for_deletion)
 
  msg_ids_for_marking = smb(folder_path, "before:-1day")
 
  if !msg_ids_for_marking.empty?
 
    mmr(msg_ids_for_marking)
 
  end
 
  #syncFolder
 
  cmd_result = sf(folder_path)
 
  #puts cmd_result
 
  if cmd_result != nil
 
    case cmd_result
 
    when /unknown folder/ ; create_feed_folder(user, folder_path, feed_url)
 
  end
 
  else
 
    $logger.info "Refreshed #{folder_path} for #{user}"
 
  end
 
end
 
 
def remove_feeds(user, folder_path, feed_url)
 
  $logger.debug("CMD: zmmailbox -z -m #{user} deleteFolder '#{folder_path}'")
 
  cmd_result = cmd_to_sys("zmmailbox -z -m #{user} df '#{folder_path}'")
 
end
 
 
#createFolder
 
def cf(user, folder_path)
 
  if folder_path.to_s.include?("Feeds")
 
    zmcommand = "cf -c purple '#{folder_path}'"
 
  elsif folder_path.to_s.include?("Calendars")
 
    zmcommand = "cf -c purple -V appointment '#{folder_path}'"
 
  end
 
  #puts zmcommand
 
  $cmdin.puts(zmcommand)
 
  count = 0
 
  while (( line = $cmdout.gets ))
 
    count += 1
 
    #puts "#{count}:: #{line}"
 
    #puts is_integer(line.split.last)
 
    if is_integer(line.split.last)
 
      return
 
    elsif line.include?("unknown folder")
 
      $logger.warn(line)
 
      cf(user, folder_path.dirname)
 
      cm(user, folder_path)
 
      return
 
    else
 
      $logger.fatal(line)
 
      puts "EXITING::  #{line}"
 
      exit
 
    end
 
  end
 
end
 
 
#createMountpoint
 
def cm(user, folder_path)
 
  if folder_path.to_s.include?("Feeds")
 
    zmcommand = "cm -c purple '#{folder_path}' shares@wiu.edu '#{folder_path}'"
 
  elsif folder_path.to_s.include?("Calendars")
 
    zmcommand = "cm -c purple -V appointment '#{folder_path}' shares@wiu.edu '#{folder_path}'"
 
  end
 
  $cmdin.puts(zmcommand)
 
  count=0
 
  while (( line = $cmdout.gets ))
 
    count += 1
 
    #puts "#{count}:: #{line}"
 
    if is_integer(line.split.last)
 
      return
 
    end
 
    case line
 
    when /ALREADY_EXISTS/ ; $logger.warn(line) ; return
 
    when /NO_SUCH_ACCOUNT/ ; $logger.fatal(line) ; puts "EXITING::  #{line}"  ; exit
 
    when /unknown folder/ ; cf(user, folder_path) ; return
 
    when /NO_SUCH_FOLDER/ ; cf(user, folder_path) ; return
 
    when /permission denied/ ; mfg(user, folder_path) ; sm(user) ; cm(user, folder_path) ; return
 
    else ; $logger.fatal(line) ; puts "EXITING::  #{line}" ; exit
 
end
 
  end
 
end
 
 
#deleteMessages
 
def dm(msg_ids_for_deletion)
 
  $cmdin.puts("dm #{msg_ids_for_deletion}")
 
  $cmdin.puts("bogus")
 
  $cmdout.each do |line|
 
    if line.include?("bogus")
 
      $logger.info "Deleted #{msg_ids_for_deletion}"
 
      return
 
    end
 
  end
 
end
 
 
#markFolderRead
 
def mfr(folder_path)
 
  $cmdin.puts("mfr '#{folder_path}'")
 
  $cmdin.puts("bogus")
 
  $cmdout.each do |line|
 
    if line.include?("bogus")
 
      $logger.info "Marked Folder Read: #{folder_path}"
 
      return
 
    end
 
  end
 
end
 
 
#markMessageRead
 
def mmr(msg_ids_for_marking)
 
  $cmdin.puts("mmr #{msg_ids_for_marking} 1")
 
  $cmdin.puts("bogus")
 
  $cmdout.each do |line|
 
    if line.include?("bogus")
 
      $logger.info "Messages Marked Read: #{msg_ids_for_marking}"
 
      return
 
    end
 
  end
 
end
 
 
 
#modifyFolderGrant
 
def mfg(user, folder_path)
 
  sm("shares@wiu.edu")
 
  $cmdin.puts("mfg '#{folder_path}' account #{user} r")
 
  $cmdin.puts("bogus")
 
  $cmdout.each do |line|
 
    if line.include?("ERROR:") and !line.include?("bogus")
 
      $logger.fatal(line)
 
      puts "EXITING: #{line}"
 
      exit
 
    elsif line.include?("bogus")
 
      $logger.info "Granted read permission to #{folder_path} for #{user}"
 
      return
 
    else
 
      $logger.fatal(line)
 
      puts "UNKNOWN ERROR: #{line}"
 
      exit
 
    end
 
  end
 
end
 
 
#postRestUrl
 
def pru(cal, folder_path)
 
  f = File.new("cal.ics", "w") or die "Unable to create file..."
 
  f.puts cal.to_ical
 
  f.close
 
  sm("shares@wiu.edu")
 
  $cmdin.puts("pru \"#{folder_path}\" cal.ics")
 
  $cmdin.puts("bogus")
 
  $cmdout.each do |line|
 
    if line.include?("ERROR:") and !line.include?("bogus")
 
      $logger.fatal(line)
 
      puts "EXITING: #{line}"
 
      exit
 
    elsif line.include?("bogus")
 
      $logger.info "ICS posted to #{folder_path}"
 
      return
 
    else
 
      $logger.fatal(line)
 
      puts "UNKNOWN ERROR: #{line}"
 
      exit
 
    end
 
  end
 
  exit
 
end
 
 
#searchMailbox for messages older than 30 days
 
def smb(folder_path, date_fmt)
 
  msg_ids = Array.new
 
  $cmdin.puts("s -l 1000 -t message 'in:\"#{folder_path}\" #{date_fmt}'")
 
  $cmdin.puts("bogus")
 
  $cmdout.each do |line|
 
    if line.include?("mess")
 
      msg_ids << line.split(' ')[1]
 
    end
 
    if line.include?("bogus")
 
      return msg_ids.join(',')
 
    end
 
  end
 
end
 
 
#selectMailbox
 
def sm(user)
 
  $cmdin.puts("sm #{user}")
 
  $cmdout.each do |line|
 
    if line.include?("mailbox:")
 
      return
 
    elsif line.include?("NO_SUCH_ACCOUNT")
 
      $logger.fatal(line)
 
      puts "EXITING:: #{line}"
 
      exit
 
    else
 
      $logger.fatal(line)
 
      puts "UNKNOWN ERROR: #{line}"
 
      exit
 
    end
 
  end
 
end
 
 
#syncFolder
 
def sf(folder_path)
 
  $cmdin.puts("sf \"#{folder_path}\"")
 
  $cmdin.puts("sm")
 
  count=0
 
  while(( line = $cmdout.gets ))
 
    count+=1
 
    if line.include?("unknown folder:")
 
      $logger.warn(line)
 
      return line
 
      elseif line.include?("ERROR")
 
      $logger.fatal(line)
 
      puts "UNKNOWN ERROR:: #{line}"
 
      exit
 
    end
 
    return if count == 4
 
  end
 
end
 
 
# Create and run the application
 
include Icalendar
 
app = App.new(ARGV, STDIN)
 
app.run
 

Revision as of 04:05, 23 August 2008

Jump to: navigation, search