adhearsion 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -4,8 +4,7 @@ require 'rake/rdoctask'
4
4
  require 'rake/gempackagetask'
5
5
 
6
6
  ADHEARSION_VERSION = File.read('.version').strip
7
- Summary = %{Adhearsion is a professional integration system for
8
- integrating anything and everything.}
7
+ Summary = %{Adhearsion is metaprogramming framework for developing collaboration software.}
9
8
 
10
9
  #task :default => [:test]
11
10
 
@@ -27,14 +26,15 @@ GEM_SPEC = Gem::Specification.new do |s|
27
26
  s.name = 'adhearsion'
28
27
  s.rubyforge_project = 'adhearsion'
29
28
  s.author = 'Jay Phillips'
30
- s.email = 'admin -at- jicksta dot com'
29
+ s.email = 'jay -at- codemecca dot com'
31
30
  s.version = ADHEARSION_VERSION
32
31
  s.summary = Summary
33
32
  s.homepage = 'http://adhearsion.com'
34
33
 
35
34
  s.add_dependency 'activerecord', '>= 1.14.4'
36
35
  s.add_dependency 'rake', '>= 0.7.1'
37
-
36
+ s.add_dependency 'daemons', '>= 1.0.5'
37
+
38
38
  s.platform = Gem::Platform::RUBY
39
39
  s.require_path = 'lib'
40
40
  s.executables = 'ahn'
data/TODO ADDED
@@ -0,0 +1,22 @@
1
+ Port Jason's T2S work into trunk when stable. Jason?
2
+
3
+ Port in new Micromenus browser GUI
4
+
5
+ Support ITAD routing using ENUM lookups.
6
+ Major file structure refactoring!
7
+
8
+ Port in RAI's AMI work.
9
+
10
+ Port in RAI's Rails app initialization and routing integration.
11
+
12
+ Develop a reasonable RSpec testing framework for Adhearsion.
13
+
14
+ Have AGI server optionally powered by mongrel
15
+
16
+ Port Micromenus server over to Camping
17
+
18
+ Adhearsion CLI. Should use the 'breakpoint' library's DRb extension to run an irb session in an external Ruby interpreter (Adhearsion's)
19
+
20
+ Let record() take a block of functionality to record. This feature will probably only be available when an AMI connection is present.
21
+
22
+ Build in hunt-group support into dial()
data/ahn CHANGED
@@ -1,25 +1,24 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # This is the main executable file of Adhearsion.
4
-
5
- # Copyright (c) 2006 Jay Phillips
6
-
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy of
8
- # this software and associated documentation files (the "Software"), to deal in
9
- # the Software without restriction, including without limitation the rights to
10
- # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11
- # of the Software, and to permit persons to whom the Software is furnished to do
12
- # so, subject to the following conditions:
13
-
14
- # The above copyright notice and this permission notice shall be included in all
15
- # copies or substantial portions of the Software.
16
-
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
- # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
- # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3
+ # This is the main executable file.
4
+
5
+ # Adhearsion, open source technology integrator
6
+ # Copyright (C) 2006,2007 Jay Phillips
7
+ #
8
+ # This library is free software; you can redistribute it and/or
9
+ # modify it under the terms of the GNU Lesser General Public
10
+ # License as published by the Free Software Foundation; either
11
+ # version 2.1 of the License, or (at your option) any later version.
12
+ #
13
+ # This library is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ # Lesser General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Lesser General Public
19
+ # License along with this library; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
+ require 'rubygems'
23
22
 
24
23
  usage = "Usage:
25
24
  ahn create /path/to/directory
@@ -33,9 +32,9 @@ Under development:
33
32
  ahn search keyword
34
33
  ahn uninstall/remove helpername"
35
34
 
36
- $: << File.join(File.dirname(__FILE__), 'lib')
35
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), 'lib')
37
36
  ADHEARSION_VERSION = File.read(File.join(File.dirname(__FILE__), '.version')).strip
38
- ARGV.unshift 'start' if ARGV.empty? # Set the default operation
37
+ ARGV.unshift 'start' if ARGV.empty? # Set the default operation
39
38
 
40
39
  require 'yaml'
41
40
 
@@ -103,15 +102,17 @@ Adhearsion project generated!
103
102
 
104
103
  Start your new app with "ahn start #{dest_dir_relative}"
105
104
 
106
- For dial plan management, change the appropriate contexts
107
- in your /etc/asterisk/extensions.conf file to the following:
105
+ If you wish to use Adhearsion to control Asterisk's dialplan,
106
+ change the contexts you wish to be affected in your
107
+ /etc/asterisk/extensions.conf file to the following:
108
108
 
109
109
  [your_context_name]
110
110
  exten => _X.,1,AGI(agi://1.2.3.4) ; This IP here
111
111
 
112
- To use databases edit config/database.yml for the
112
+ To use databases, edit config/database.yml for the
113
113
  connection information and, optionally, config/database.rb
114
- to change the default database object models.
114
+ to change the default database object models. To create your
115
+ tables, you may wish to use config/migration.rb.
115
116
 
116
117
  Asterisk Manager interface integration is highly recommended.
117
118
  Edit your /etc/asterisk/manager.conf file and enable the
@@ -131,12 +132,23 @@ when 'start'
131
132
  target = Dir.pwd
132
133
 
133
134
  arg = ARGV.shift
134
- if arg =~ /daemon(ize)?/
135
+ if arg =~ /daemon(ized)?/
135
136
  $DAEMON = true
136
137
  arg = ARGV.shift
137
138
  end
138
139
  target = File.expand_path(arg || target)
139
140
 
141
+ puts %{\nStarting Adhearsion v#{ADHEARSION_VERSION}
142
+ Written by Jay Phillips of Codemecca LLC, et al.
143
+ http://adhearsion.com\n\n}
144
+
145
+ if $DAEMON
146
+ require 'rubygems'
147
+ require 'daemons'
148
+ puts "Daemonizing now!"
149
+ Daemons.daemonize
150
+ end
151
+
140
152
  Dir.chdir target
141
153
 
142
154
  adhearsion_config = File.join('config', 'adhearsion.yml')
@@ -146,10 +158,7 @@ when 'start'
146
158
  register_logger StandardLogger.new(STDOUT)
147
159
 
148
160
  register_logger StandardLogger.new('logs/adhearsion.log')
149
-
150
- puts %{\nStarting Adhearsion v#{ADHEARSION_VERSION}
151
- Written by Jay Phillips of Codemecca LLC, et al.
152
- http://adhearsion.com\n\n}
161
+
153
162
 
154
163
  %w(rubygems uri open-uri abbrev thread).each { |lib| require lib }
155
164
 
@@ -158,45 +167,52 @@ when 'start'
158
167
  require 'adhearsion'
159
168
  require 'database' if CONFIG['enable_database']
160
169
  require 'servlet_container'
161
- require "constants"
170
+ require 'constants'
171
+
172
+ if CONFIG['drb'] && CONFIG['drb']['enabled']
173
+ require 'drb_server'
174
+ DRbServerManager.start
175
+ end
162
176
 
163
177
  # Load appropriate helpers
164
178
  $HELPERS = {}
165
179
  Contexts::Container.new.run_inside do
166
180
  # Start with compiled helpers
167
- class << Object
168
- aliens = Dir[File.join('helpers', '*.alien.*')]
169
- aliens.each do |f|
170
- f = File.basename f
171
- config_file = File.join %W(config helpers #{f}.yml)
172
- config = File.readable?(config_file) ? YAML.load_file(config_file) : {}
173
- if config.delete('enabled') != false
174
- require 'inline'
175
- lang = f[f.rindex('.')+1..-1]
176
- log "Loading helper #{f} as #{lang.upcase}"
181
+ class Object
182
+ class << self
183
+ aliens = Dir[File.join('helpers', '*.alien.*')]
184
+ aliens.each do |f|
185
+ f = File.basename f
186
+ config_file = File.join %W(config helpers #{f}.yml)
187
+ config = File.readable?(config_file) ? YAML.load_file(config_file) : {}
188
+ if config.delete('enabled') != false
189
+ require 'inline'
190
+ lang = f[f.rindex('.') + 1..-1]
191
+ log "Loading helper #{f} as #{lang.upcase}"
177
192
 
178
- $HELPERS[f] = config
179
- inline do |builder|
180
- builder.send lang, File.read(File.join('helpers', f))
193
+ $HELPERS[f] = config
194
+ inline do |builder|
195
+ builder.send lang, File.read(File.join('helpers', f))
196
+ end
181
197
  end
182
198
  end
183
199
  end
184
- end
185
200
 
186
- # Load Ruby helpers
187
- Dir[File.join('helpers', '*.rb')].each do |f|
188
- name = File.basename(f)[/^[^.]+/]
189
- config_file = File.join %W(config helpers #{name}.yml)
190
- config = File.readable?(config_file) ? YAML.load_file(config_file) : {}
191
- if config.delete('enabled') != false
192
- log "Parsing helper #{name}"
193
- $HELPERS[name] = config
194
- eval File.read(f)
201
+ # Load Ruby helpers
202
+ Dir[File.join('helpers', '*.rb')].each do |f|
203
+ name = File.basename(f)[/^[^.]+/]
204
+ config_file = File.join %W(config helpers #{name}.yml)
205
+ config = File.readable?(config_file) ? YAML.load_file(config_file) : {}
206
+ if config.delete('enabled') != false
207
+ log "Parsing helper #{name}"
208
+ $HELPERS[name] = config
209
+ eval File.read(f)
210
+ end
195
211
  end
196
212
  end
197
213
  end
198
214
 
199
- sc = ServletContainer.new(CONFIG['port'] || 4573)
215
+ sc = ServletContainer.new((CONFIG['port'] || 4573), (CONFIG['host'] || '0.0.0.0'))
200
216
  $HUTDOWN.hook { sc.shutdown }
201
217
 
202
218
  log "Dallas, we have liftoff!"
Binary file
@@ -1,6 +1,7 @@
1
1
  answer_before_call: true
2
2
  hangup_after_call: true
3
3
  enable_database: false
4
+ host: 0.0.0.0
4
5
  port: 4573
5
6
 
6
7
  # This information is completely optional. It may be the
@@ -17,7 +18,57 @@ port: 4573
17
18
  # zip: 77777
18
19
  # country: United States
19
20
 
21
+
22
+ # If you wish to use named conferences in your dial plan,
23
+ # uncomment the lines below. To use, pass the name to
24
+ # the join() method as a Symbol. e.g. join :management
25
+ #
20
26
  # conferences:
21
27
  # management: 1000
22
28
  # marketing: 1001
23
- # development: 1002
29
+ # development: 1002
30
+
31
+ drb:
32
+ enabled: false
33
+ host: 127.0.0.1
34
+ port: 9050
35
+
36
+ deny: all
37
+ allow:
38
+ - 127.0.0.1
39
+ - 192.168.1.*
40
+
41
+ # Set your access control permissions above.
42
+ # Values for deny and allow can be several
43
+ # things:
44
+ #
45
+ # * The 'all' keyword can be used to match
46
+ # everything.
47
+ # * A single IP can be given right after
48
+ # the colon.
49
+ # * A single IP with wildcards can be given
50
+ # * Or, combining all of these, a YAML list
51
+ # can be used to specify many policies.
52
+ # See the comments below for more examples.
53
+ #
54
+ # Also note, the "host" field above may also
55
+ # affect the ability for DRb clients to connect
56
+ # to the server. If you wish you receive
57
+ # connections from the 192.168.1.*, listen on
58
+ # the IP associated with this machine on that
59
+ # subnet.
60
+ #
61
+ #
62
+ # USING YAML LISTS
63
+ #
64
+ # YAML allows lists of items to be created by
65
+ # prepending a hyphen to each list element.
66
+ # These lists can be used to refine your
67
+ # access control list better. Example:
68
+ #
69
+ # deny: all
70
+ # allow:
71
+ # - 192.168.1.123
72
+ # - 192.168.1.99
73
+ # - 66.199.34.44
74
+
@@ -0,0 +1,21 @@
1
+ enabled: false
2
+
3
+ # This is how growl identifies this client.
4
+ app_name: Adhearsion
5
+
6
+ # When dealing with only a single machine, set this
7
+ # to your desktop's IP. If you want multiple servers,
8
+ # you can manually pass the IP address as the second
9
+ # argument to growl() and password as the third.
10
+
11
+ # Leave ip empty if you intend to specify it manually
12
+ ip: localhost
13
+ password: # Leave as-is if none
14
+
15
+ # This is a list of the different types of notifications
16
+ # Growl should expect from this client. These can be
17
+ # anything you want. Names are case sensitive. Note: At
18
+ # least one must exist!
19
+ notifications:
20
+ - Standard Notification
21
+ - Incoming Call
@@ -5,7 +5,8 @@ require 'active_record'
5
5
 
6
6
  # A migration script uses a database configuration and creates tables
7
7
  # very conveniently in a database-agnostic way. Below, add any customizations
8
- # to the sample schema or leave it as-is. When done, execute this script.
8
+ # to the sample schema or leave it as-is. When done, type "rake migrate" to
9
+ # have this schema generated.
9
10
 
10
11
  ActiveRecord::Base.establish_connection YAML.load_file('config/database.yml')
11
12
 
@@ -15,15 +16,14 @@ class CreateUsers < ActiveRecord::Migration
15
16
  def self.up
16
17
  create_table :users do |t|
17
18
  t.column :name, :string
18
- t.column :callerid_name, :string
19
- t.column :callerid_num, :string
20
19
  t.column :group_id, :integer # Foreign key
21
- t.column :ivr_extension, :string
22
20
  t.column :extension, :string
23
- t.column :email, :string
24
- t.column :im_username, :string
25
- t.column :im_provider, :string
26
21
  # t.column :billed_time, :integer, :null => false
22
+
23
+ # Feel free to remove or change this to "email". Gmail offers email,
24
+ # instant messaging, calendars, and so forth -- all of which you
25
+ # can integrate with using one simple username.
26
+ t.column :gmail, :string
27
27
  end
28
28
  end
29
29
 
@@ -47,7 +47,3 @@ class CreateGroups < ActiveRecord::Migration
47
47
  drop_table :groups
48
48
  end
49
49
  end
50
-
51
- # Run "rake migrate" to run this script properly.
52
- # CreateUsers.up
53
- # CreateGroups.up
@@ -0,0 +1,53 @@
1
+ =begin Adhearsion metadata
2
+ name: Adhearsion Growler
3
+ author:
4
+ name: Phil Kates
5
+ email: hawk684 -at- gmail.com
6
+ modified-by: Jay Phillips
7
+ gems:
8
+ - ruby-growl
9
+ =end
10
+
11
+ require 'ruby-growl'
12
+
13
+ GROWL_SERVER = unless $HELPERS['growler']['ip'] then nil else
14
+ Growl.new $HELPERS['growler']['ip'] || 'localhost',
15
+ $HELPERS['growler']['app_name'] || "Adhearsion",
16
+ $HELPERS['growler']['notifications'],
17
+ nil, $HELPERS['growler']['password']
18
+ end
19
+
20
+ # Sends a message to an OSX desktop's Growl notification server. If you
21
+ # intend to only notify a single machine, you can specify the parameters
22
+ # in growler.yml.
23
+ #
24
+ # == Usage:
25
+ #
26
+ # - message: The notification or message you wish to send!
27
+ # - type (optional): The type of notification as specified in the growler.yml
28
+ # config file. This defaults to the first "notifications" entry. If you want
29
+ # growl() to automatically set this for you, simply send it nil.
30
+ # - ip (optional): The desktop's IP address you wish to notify. This
31
+ # by default uses what's in growler.yml or, if unavailable, "localhost".
32
+ # - password (optional): a password if one is needed. Defaults to nothing.
33
+ #
34
+ # == Examples:
35
+ # - growl "Isn't it about time you debugged me?"
36
+ # - growl "Call from #{callerid}!", "Incoming Call"
37
+ # - growl "The caller queue size is #{queue.size}", nil, "192.168.1.133"
38
+ # - growl "Join conference 1234!", nil, "192.168.50.151", "Secretz!"
39
+ def growl message, type=nil, ip=nil, password=nil
40
+ type = $HELPERS['growler']['notifications'].first unless type
41
+
42
+ # Create a new Growl client if an IP was specified, otherwise use
43
+ # our server created when Adhearsion booted.
44
+ svr = unless ip then GROWL_SERVER else
45
+ Growl.new ip, $HELPERS['growler']['app_name'] || "Adhearsion",
46
+ $HELPERS['growler']['notifications'], nil,
47
+ $HELPERS['growler']['password']
48
+ end
49
+
50
+ # TODO support priorities and stickies. May need to use hash-key argments?
51
+ # TODO handle unreachable desktops
52
+ svr.notify type, type, message
53
+ end
@@ -10,25 +10,34 @@ def lookup number
10
10
  hash = {}
11
11
  url = "http://www.whitepages.com/9901/search/ReversePhone?phone=#{number}"
12
12
  doc = Hpricot open(url)
13
+
14
+ # This div contains all the information we need, unless it's an unlisted number
15
+ if (results = doc.at "#results_single_listing") then
16
+ # This div's h3 contains the name of the caller
17
+ hash[:first_name], hash[:last_name] = results.at('h3').inner_html.split(/,\s*/).reverse
18
+
19
+ # Now we just need the rest of the information contained in p's.
20
+ meta = results/'p'
21
+ meta.pop # Discard the useless p element
22
+
23
+ hash[:number] = meta.pop.inner_html
24
+ city_info = meta.pop.inner_html
25
+ city_info = city_info.match /(.+), ([A-Za-z]{2}) (\d{5})/
26
+ hash[:city] = city_info[1]
27
+ hash[:state] = city_info[2]
28
+ hash[:zip] = city_info[3]
29
+
30
+ hash[:address] = meta.map(&:inner_html) * " "
31
+ elsif (results = doc.at "#results_single_phone_info") then
32
+ meta = results/'span'
33
+ hash[:location] = (meta.pop.inner_html.match /Location: (.*)/)[1]
34
+ end
13
35
 
14
- # This div contains all the information we need
15
- results = doc.at "#results_single_listing"
16
-
17
- # This div's h3 contains the name of the caller
18
- hash[:first_name], hash[:last_name] = results.at('h3').inner_html.split(/,\s*/).reverse
19
-
20
- # Now we just need the rest of the information contained in p's.
21
- meta = results/'p'
22
- meta.pop # Discard the useless p element
23
-
24
- hash[:number] = meta.pop.inner_html
25
- city_info = meta.pop.inner_html
26
- city_info = city_info.match /(.+), ([A-Za-z]{2}) (\d{5})/
27
- hash[:city] = city_info[1]
28
- hash[:state] = city_info[2]
29
- hash[:zip] = city_info[3]
30
-
31
- hash[:address] = meta.map(&:inner_html) * " "
36
+ if hash[:first_name] or hash[:last_name] then
37
+ hash[:composite] = "#{hash[:first_name]} #{hash[:last_name]}"
38
+ else
39
+ hash[:composite] = hash[:location]
40
+ end
32
41
 
33
42
  hash
34
43
  end