Chewie71-Notes

Revision as of 04:04, 23 August 2008 by Chewie71 (talk | contribs) (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 ...)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
  1. !/usr/local/bin/ruby
  1. == Synopsis
  2. This application updates RSS Feed folders in Zmibra user accounts.
  3. == Examples
  4. This command does RSS folder updates.
  5. update_feeds
  6. Other examples:
  7. ruby_cl_skeleton -q bar.doc
  8. ruby_cl_skeleton --verbose foo.html
  9. == Usage
  10. update_feeds [options]
  11. For help use: update_feeds -h
  12. == Options
  13. -u, --user User to synchronize {uid|email|all}
  14. -h, --help Displays help message
  15. -t, --test Displays test/debug information and logs DEBUG messages
  16. -v, --version Display the version, then exit
  17. -q, --quiet Output as little as possible, overrides verbose
  18. -V, --verbose Verbose output
  19. TO DO - add additional options
  20. == Author
  21. Matt Mencel
  22. == Copyright
  23. 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


  1. TO DO - Add Modules, Classes, etc
      1. FUNCTIONS ###
  1. def create_feed_folder(user, folder_path, feed_url)
  2. $logger.debug("DEBUG: zmmailbox -z -m #{user} createFolder -u '#{feed_url}' '#{folder_path}'")
  3. $logger.info("Creating missing folder #{folder_path} for #{user}")
  4. cmd_result = cmd_to_sys("zmmailbox -z -m #{user} cf -u '#{feed_url}' '#{folder_path}'")
  5. $logger.debug("ERROR?: #{cmd_result[1]}")
  6. if check_command_result(cmd_result[1], user, feed_url) == "unknown folder"
  7. $logger.warn(cmd_result[1])
  8. create_feed_folder(user, folder_path.dirname(), nil)
  9. $logger.debug("ATTEMPTING TO RECREATE: #{folder_path}")
  10. cmd_result = cmd_to_sys("zmmailbox -z -m #{user} cf -u '#{feed_url}' '#{folder_path}'")
  11. check_command_result(cmd_result[1], user, feed_url)
  12. end
  13. $logger.debug("Created Folder #{folder_path}")
  14. 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

  1. 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

  1. 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

  1. 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

  1. 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

  1. 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


  1. 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

  1. 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

  1. 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

  1. 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

  1. 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

  1. Create and run the application

include Icalendar app = App.new(ARGV, STDIN) app.run

Jump to: navigation, search