whm_xml 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,88 @@
1
+ = WHM XML-API Ruby Wrapper
2
+
3
+ This is a Ruby wrapper for the cPanel WHM XML-API interface. It will allow you to perform multiple functions available on your cPanel WHM server. For more information on the XML-API, see the cPanel website at http://twiki.cpanel.net/twiki/bin/view/AllDocumentation/AutomationIntegration/XmlApi.
4
+
5
+ == Requirements
6
+
7
+ The following Ruby gems are required to be installed in order to make use this gem:
8
+
9
+ xml-simple (>= 1.0.12):: http://xml-simple.rubyforge.org
10
+ activesupport (>= 2.3.2):: http://as.rubyonrails.org
11
+ curb (>= 0.3.2):: http://curb.rubyforge.org
12
+ validatable (>= 1.6.7):: http://validatable.rubyforge.org
13
+
14
+ == Usage
15
+
16
+ First off, you must have root access to a cPanel WHM server. With this gem, you can either use <b>password</b> or <b>remote access key</b> authentication. To get to the remote access key in WHM (which is likely the more secure method of connecting), go under "Cluster/Remote Access", and click on "Setup Remote Access Key". You can either copy the pre-generated one, or re-generate it.
17
+
18
+ ==== Installation
19
+
20
+ You can install this gem simply by doing the following:
21
+
22
+ $ gem sources -a http://gems.github.com
23
+ $ gem install ivanoats-whm_xml_api_ruby
24
+
25
+ You can also include it in a Rails project:
26
+
27
+ $ script/plugin install git://github.com/ivanoats/whm_xml_api_ruby.git
28
+
29
+ ==== Connecting
30
+
31
+ To access the functions of the server, all you need to do is initialize a new Server class:
32
+ require 'whm'
33
+
34
+ server = Whm::Server.new(
35
+ :username => "root",
36
+ :remote_key => "sd00fsd2i3rj...",
37
+ :host => "dedicated.server.com"
38
+ )
39
+
40
+ server.version
41
+ => "11.24.2"
42
+
43
+ == Currently Available Methods
44
+
45
+ As of WHM version 11.24.2, these are the methods that are available via this gem:
46
+
47
+ * <tt>account_summary</tt>
48
+ * <tt>change_account_password</tt>
49
+ * <tt>change_package</tt>
50
+ * <tt>create_account</tt>
51
+ * <tt>generate_ssl_certificate</tt>
52
+ * <tt>hostname</tt>
53
+ * <tt>limit_bandwidth_usage</tt>
54
+ * <tt>list_accounts</tt>
55
+ * <tt>list_packages</tt>
56
+ * <tt>modify_account</tt>
57
+ * <tt>suspend_account</tt>
58
+ * <tt>terminate_account</tt>
59
+ * <tt>unsuspend_account</tt>
60
+ * <tt>version</tt>
61
+
62
+ == Authors and credits
63
+
64
+ Authors:: Ivan Storck, Josh Delsman, Padraic McGee
65
+ Home page:: http://github.com/ivanoats/whm_xml_api_ruby
66
+
67
+ == License
68
+
69
+ Copyright (c) 2008-2009 Ivan Storck
70
+
71
+ Permission is hereby granted, free of charge, to any person obtaining
72
+ a copy of this software and associated documentation files (the
73
+ 'Software'), to deal in the Software without restriction, including
74
+ without limitation the rights to use, copy, modify, merge, publish,
75
+ distribute, sublicense, and/or sell copies of the Software, and to
76
+ permit persons to whom the Software is furnished to do so, subject to
77
+ the following conditions:
78
+
79
+ The above copyright notice and this permission notice shall be
80
+ included in all copies or substantial portions of the Software.
81
+
82
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
83
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
84
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
85
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
86
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
87
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
88
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rake/rdoctask'
3
+
4
+ desc 'Generate documentation for whm_xml_api_ruby'
5
+ Rake::RDocTask.new do |rd|
6
+ rd.rdoc_dir = 'html'
7
+ rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
8
+ rd.main = "README.rdoc"
9
+ rd.title = "whm_xml_api_ruby -- A Ruby wrapper for cPanel's WHM"
10
+ rd.options << "--all"
11
+ end
@@ -0,0 +1,67 @@
1
+ module Whm #:nodoc:
2
+ # Allows for parameter requirements and validations for methods
3
+ module Parameters
4
+ # Check the included hash for the included parameters, and ensure they aren't blank.
5
+ #
6
+ # ==== Example
7
+ #
8
+ # class User
9
+ # def initialize
10
+ # requires!(options, :username, :password)
11
+ # end
12
+ # end
13
+ #
14
+ # >> User.new
15
+ # ArgumentError: Missing required parameter: username
16
+ #
17
+ # >> User.new(:username => "john")
18
+ # ArgumentError: Missing required parameter: password
19
+ def requires!(hash, *params)
20
+ params.each do |param|
21
+ if param.is_a?(Array)
22
+ raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash.has_key?(param.first)
23
+ raise ArgumentError.new("Required parameter cannot be blank: #{param.first}") if hash[param.first].blank?
24
+ else
25
+ raise ArgumentError.new("Missing required parameter: #{param}") unless hash.has_key?(param)
26
+ raise ArgumentError.new("Required parameter cannot be blank: #{param}") if hash[param].blank?
27
+ end
28
+ end
29
+ end
30
+
31
+ # Checks to see if supplied params (which are booleans) contain
32
+ # either a 1 ("Yes") or 0 ("No") value.
33
+ def booleans!(hash, *params)
34
+ params.each do |param|
35
+ if param.is_a?(Array)
36
+ raise ArgumentError.new("Boolean parameter must be \"1\" or \"0\": #{param.first}") unless hash[param.first].to_s.match(/(1|0)/)
37
+ else
38
+ raise ArgumentError.new("Boolean parameter must be \"1\" or \"0\": #{param}") unless hash[param].to_s.match(/(1|0)/)
39
+ end
40
+ end
41
+ end
42
+
43
+ # Checks the hash to see if the hash includes any parameter
44
+ # which is not included in the list of valid parameters.
45
+ #
46
+ # ==== Example
47
+ #
48
+ # class User
49
+ # def initialize
50
+ # valid_options!(options, :username)
51
+ # end
52
+ # end
53
+ #
54
+ # >> User.new(:username => "josh")
55
+ # => #<User:0x18a1190 @username="josh">
56
+ #
57
+ # >> User.new(:username => "josh", :credit_card => "5105105105105100")
58
+ # ArgumentError: Not a valid parameter: credit_card
59
+ def valid_options!(hash, *params)
60
+ keys = hash.keys
61
+
62
+ keys.each do |key|
63
+ raise ArgumentError.new("Not a valid parameter: #{key}") unless params.include?(key)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,20 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'rubygems'
4
+ require 'curb' # As opposed to Net::HTTP (for faster requests)
5
+ require 'xmlsimple' # For simple XML parsing
6
+ require 'active_support' # For stringifying keys, etc.
7
+ require 'parameters' # For parameter requirements in methods
8
+ require 'validatable' # For object validation
9
+
10
+ WHM_DIRECTORY = File.join(File.dirname(__FILE__),'whm')
11
+
12
+ require File.join(WHM_DIRECTORY,'exceptions')
13
+ require File.join(WHM_DIRECTORY,'server')
14
+ require File.join(WHM_DIRECTORY,'account')
15
+ require File.join(WHM_DIRECTORY,'package')
16
+
17
+
18
+ module Whm
19
+ VERSION = '0.3.2'
20
+ end
@@ -0,0 +1,64 @@
1
+ module Whm
2
+ class Account #:nodoc:
3
+ include Parameters, Validatable
4
+
5
+ validates_presence_of :username, :domain, :groups => :creation
6
+ validates_format_of :savepkg, :with => /(1|0)/, :message => "must be 1 or 0", :groups => :creation
7
+
8
+ attr_accessor :server
9
+ attr_accessor :attributes
10
+ attr_accessor :writable_attributes
11
+
12
+
13
+ @@default_attributes = {}
14
+ @@writable_attributes = %w(username domain plan pkgname savepkg featurelist quota password ip cgi frontpage hasshell contactemail cpmod maxftp maxsql maxpop maxlst maxsub maxpark maxaddon bwlimit customip language useregns hasuseregns reseller)
15
+ @@readonly_attributes = %w(disklimit diskused email ip owner partition plan startdate suspended suspendreason theme unix_startdate user)
16
+
17
+ def initialize(attributes = {})
18
+ self.attributes = attributes
19
+ self.writable_attributes = {}
20
+ end
21
+
22
+ def user
23
+ self.attributes['user']
24
+ end
25
+ alias :name :user
26
+
27
+ (@@readonly_attributes).each do |attribute|
28
+ define_method attribute do
29
+ self.attributes[attribute.to_s]
30
+ end
31
+ end
32
+
33
+ (@@writable_attributes).each do |attribute|
34
+ define_method attribute do
35
+ self.writable_attributes[attribute.to_s] || self.attributes[attribute.to_s]
36
+ end
37
+ define_method "#{attribute}=" do |*parameters|
38
+ raise ArgumentError, "expected 1 parameter" unless parameters.length == 1
39
+ self.writable_attributes[attribute.to_s] = parameters.first
40
+ end
41
+ end
42
+
43
+ def password=(password)
44
+ server.change_account_password(:user => user, :pass => password)
45
+ end
46
+
47
+ def suspend!( reason = '')
48
+ server.suspend_account(:user => user, :reason => reason)
49
+ end
50
+
51
+ def unsuspend!
52
+ server.unsuspend_account(:user => user)
53
+ end
54
+
55
+ def terminate!( keepdns = "n")
56
+ server.terminate_account(:user => user,:keepdns => keepdns)
57
+ end
58
+
59
+ def package=( new_package)
60
+ server.change_package(:user => user, :pkg => new_package)
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,4 @@
1
+ module Whm #:nodoc:
2
+ class CommandFailedError < StandardError #:nodoc:
3
+ end
4
+ end
@@ -0,0 +1,17 @@
1
+ module Whm
2
+ class Package #:nodoc:
3
+ include Parameters, Validatable
4
+
5
+ validates_presence_of :username, :domain, :groups => :creation
6
+ validates_format_of :savepkg, :with => /(1|0)/, :message => "must be 1 or 0", :groups => :creation
7
+
8
+ attr_accessor :server
9
+ attr_accessor :attributes
10
+
11
+
12
+ def initialize(attributes = {})
13
+ self.attributes = attributes
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,372 @@
1
+ module Whm #:nodoc:
2
+ # The Server class initializes a new connection with the cPanel WHM server, and
3
+ # contains all functions that can be run on a cPanel WHM server as of version 11.24.2.
4
+ class Server
5
+ include Parameters
6
+
7
+ # Hostname of the WHM server (e.g., <tt>dedicated.server.com</tt>)
8
+ attr_reader :host
9
+
10
+ # WHM XML-API username
11
+ attr_reader :username
12
+
13
+ # WHM XML-API password. Use this, or the remote key, to authenticate with the server
14
+ attr_reader :password
15
+
16
+ # WHM XML-API remote key. Use this, or the password, to authenticate with the server
17
+ attr_reader :remote_key
18
+
19
+ # If you'd like increased verbosity of commands, set this to <tt>true</tt>. Defaults to <tt>false</tt>
20
+ attr_accessor :debug
21
+
22
+ # By default, SSL is enable. Set to <tt>false</tt> to disable it.
23
+ attr_accessor :ssl
24
+
25
+ # By default, we connect on port 2087. Set this to another integer to change it.
26
+ attr_accessor :port
27
+
28
+ attr_accessor :attributes
29
+
30
+ # Initialize the connection with WHM using the hostname,
31
+ # user and password/remote key. Will default to asking for
32
+ # a password, but remote_key is required if a password
33
+ # is not used.
34
+ #
35
+ # ==== Example
36
+ #
37
+ # Password authentication with debugging enabled:
38
+ #
39
+ # Whm::Server.new(
40
+ # :host => "dedicated.server.com",
41
+ # :username => "root",
42
+ # :password => "s3cUr3!p@5sw0rD",
43
+ # :debug => true
44
+ # )
45
+ #
46
+ # Remote key authentication with port 8000, and SSL to off (defaults to port 2087, and SSL on):
47
+ #
48
+ # Whm::Server.new(
49
+ # :host => "dedicated.server.com",
50
+ # :username => "root",
51
+ # :remote_key => "cf975b8930b0d0da69764c5d8dc8cf82 ...",
52
+ # :port => 8000,
53
+ # :ssl => false
54
+ # )
55
+ def initialize(options = {})
56
+ requires!(options, :host, :username)
57
+ requires!(options, :password) unless options[:remote_key]
58
+
59
+ @host = options[:host]
60
+ @username = options[:username] || "root"
61
+ @remote_key = options[:remote_key].gsub(/(\r|\n)/, "") unless options[:password]
62
+ @password = options[:password] unless options[:remote_key]
63
+ @debug = options[:debug] || false
64
+ @port = options[:port] || 2087
65
+ @ssl = options[:ssl] || true
66
+ end
67
+
68
+ # Finds all accounts
69
+ #
70
+ def accounts(options = {})
71
+ summary = self.list_accounts(options)
72
+ summary = [summary] unless summary.is_a? Array
73
+ summary.collect { |attributes| Account.new(attributes) }
74
+ end
75
+
76
+ # Find an account
77
+ #
78
+ # ==== Options
79
+ # * <tt>:user</tt> - Username associated with the acount to display (string)
80
+ def account(name)
81
+ summary = self.account_summary(:user => name)
82
+ build_account(summary)
83
+ end
84
+
85
+ # Finds all packages
86
+ #
87
+ def packages(options = {})
88
+ summary = self.list_packages
89
+ summary = [summary] unless summary.is_a? Array
90
+ summary.collect { |attributes| Package.new(attributes)}
91
+ end
92
+
93
+ # Displays pertient account information for a specific account.
94
+ #
95
+ # ==== Options
96
+ # * <tt>:user</tt> - Username associated with the acount to display (string)
97
+ def account_summary(options = {})
98
+ requires!(options, :user)
99
+
100
+ data = get_xml(:url => "accountsummary", :params => options)
101
+ check_for_cpanel_errors_on(data)["acct"]
102
+ end
103
+
104
+ # Displays the total bandwidth used (in bytes) used by an account
105
+ # ==== Options
106
+ # * <tt>:user</tt> - username associtated with the account to display (string)
107
+ def account_total_bandwidth(options = {})
108
+ requires!(options, :user)
109
+
110
+ params = { :searchtype => 'user', :search => options[:user] }
111
+ data = get_xml(:url => "showbw", :params => params)
112
+ check_for_cpanel_errors_on(data)["bandwidth"]["totalused"]
113
+ end
114
+
115
+ # Changes the password of a domain owner (cPanel) or reseller (WHM) account.
116
+ #
117
+ # ==== Options
118
+ # * <tt>:user</tt> - Username of the user whose password should be changed (string)
119
+ # * <tt>:pass</tt> - New password for that user (string)
120
+ def change_account_password(options = {})
121
+ requires!(options, :user, :pass)
122
+
123
+ data = get_xml(:url => "passwd", :params => options)
124
+ check_for_cpanel_errors_on(data)["passwd"]
125
+ end
126
+
127
+ # Changes the hosting package associated with an account.
128
+ # Returns <tt>true</tt> if it is successful, or
129
+ # <tt>false</tt> if it is not.
130
+ #
131
+ # ==== Options
132
+ # * <tt>:user</tt> - Username of the account to change the package for (string)
133
+ # * <tt>:pkg</tt> - Name of the package that the account should use (string)
134
+ def change_package(options = {})
135
+ requires!(options, :user, :pkg)
136
+
137
+ data = get_xml(:url => "changepackage", :params => options)
138
+ check_for_cpanel_errors_on(data)
139
+
140
+ data["status"] == "1" ? true : false
141
+ end
142
+
143
+ # Creates a hosting account and sets up it's associated domain information.
144
+ #
145
+ # ==== Options
146
+ # * <tt>:username</tt> - Username of the account (string)
147
+ # * <tt>:domain</tt> - Domain name (string)
148
+ # * <tt>:pkgname</tt> - Name of a new package to be created based on the settings used (string)
149
+ # * <tt>:savepkg</tt> - Save the settings used as a new package (boolean)
150
+ # * <tt>:featurelist</tt> - Name of the feature list to be used when creating a new package (string)
151
+ # * <tt>:quota</tt> - Disk space quota in MB. Must be between 0-999999, with 0 being unlimited (integer)
152
+ # * <tt>:password</tt> - User's password to access cPanel (string)
153
+ # * <tt>:ip</tt> - Whether or not the domain has a dedicated IP address, either <tt>"y"</tt> (Yes) or <tt>"n"</tt> (No) (string)
154
+ # * <tt>:cgi</tt> - Whether or not the domain has CGI access (boolean)
155
+ # * <tt>:frontpage</tt> - Whether or not the domain has FrontPage extensions installed (boolean)
156
+ # * <tt>:hasshell</tt> - Whether or not the domain has shell/SSH access (boolean)
157
+ # * <tt>:contactemail</tt> - Contact email address for the account (string)
158
+ # * <tt>:cpmod</tt> - cPanel theme name (string)
159
+ # * <tt>:maxftp</tt> - Maximum number of FTP accounts the user can create. Must be between 0-999999, with 0 being unlimited (integer)
160
+ # * <tt>:maxsql</tt> - Maximum number of SQL databases the user can create. Must be between 0-999999, with 0 being unlimited (integer)
161
+ # * <tt>:maxpop</tt> - Maximum number of email accounts the user can create. Must be between 0-999999, with 0 being unlimited (integer)
162
+ # * <tt>:maxlst</tt> - Maximum number of mailing lists the user can create. Must be between 0-999999, with 0 being unlimited (integer)
163
+ # * <tt>:maxsub</tt> - Maximum number of subdomains the user can create. Must be between 0-999999, with 0 being unlimited (integer)
164
+ # * <tt>:maxpark</tt> - Maximum number of parked domains the user can create. Must be between 0-999999, with 0 being unlimited (integer)
165
+ # * <tt>:maxaddon</tt> - Maximum number of addon domains the user can create. Must be between 0-999999, with 0 being unlimited (integer)
166
+ # * <tt>:bwlimit</tt> - Bandwidth limit in MB. Must be between 0-999999, with 0 being unlimited (integer)
167
+ # * <tt>:customip</tt> - Specific IP for the site (string)
168
+ # * <tt>:language</tt> - Language to use in the account's cPanel interface (string)
169
+ # * <tt>:useregns</tt> - Use the registered nameservers for the domain instead of the ones configured on the server (boolean)
170
+ # * <tt>:hasuseregns</tt> - Must be set to <tt>1</tt> if the above <tt>:useregns</tt> is set to <tt>1</tt> (boolean)
171
+ # * <tt>:reseller</tt> - Give reseller privileges to the account (boolean)
172
+ def create_account(options = {})
173
+ requires!(options, :username)
174
+
175
+ data = get_xml(:url => "createacct", :params => options)
176
+ check_for_cpanel_errors_on(data)
177
+ end
178
+
179
+ # Generates an SSL certificate
180
+ #
181
+ # ==== Options
182
+ # * <tt>:xemail</tt> - Email address of the domain owner (string)
183
+ # * <tt>:host</tt> - Domain the SSL certificate is for, or the SSL host (string)
184
+ # * <tt>:country</tt> - Country the organization is located in (string)
185
+ # * <tt>:state</tt> - State the organization is located in (string)
186
+ # * <tt>:city</tt> - City the organization is located in (string)
187
+ # * <tt>:co</tt> - Name of the organization/company (string)
188
+ # * <tt>:cod</tt> - Name of the department (string)
189
+ # * <tt>:email</tt> - Email to send the certificate to (string)
190
+ # * <tt>:pass</tt> - Certificate password (string)
191
+ def generate_ssl_certificate(options = {})
192
+ requires!(options, :city, :co, :cod, :country, :email, :host, :pass, :state, :xemail)
193
+ data = get_xml(:url => "generatessl", :params => options)
194
+ check_for_cpanel_errors_on(data)
195
+ end
196
+
197
+ # Displays the server's hostname.
198
+ def hostname
199
+ data = get_xml(:url => "gethostname")
200
+ check_for_cpanel_errors_on(data)["hostname"]
201
+ end
202
+
203
+ # Modifies the bandwidth usage (transfer) limit for a specific account.
204
+ #
205
+ # ==== Options
206
+ # * <tt>:user</tt> - Name of user to modify the bandwidth usage (transfer) limit for (string)
207
+ # * <tt>:bwlimit</tt> - Bandwidth usage (transfer) limit in MB (string)
208
+ def limit_bandwidth_usage(options = {})
209
+ requires!(options, :user, :bwlimit)
210
+
211
+ data = get_xml(:url => "limitbw", :params => options)
212
+ check_for_cpanel_errors_on(data)["bwlimit"]
213
+ end
214
+
215
+ # Lists all accounts on the server, or allows you to search for
216
+ # a specific account or set of accounts.
217
+ #
218
+ # ==== Options
219
+ # * <tt>:searchtype</tt> - Type of account search (<tt>"domain"</tt>, <tt>"owner"</tt>, <tt>"user"</tt>, <tt>"ip"</tt> or <tt>"package"</tt>)
220
+ # * <tt>:search</tt> - Search criteria, in Perl regular expression format (string)
221
+ def list_accounts(options = {})
222
+ data = get_xml(:url => "listaccts", :params => options)
223
+ check_for_cpanel_errors_on(data)["acct"]
224
+ end
225
+
226
+ # Lists all hosting packages that are available for use by
227
+ # the current WHM user. If the current user is a reseller,
228
+ # they may not see some packages that exist if those packages
229
+ # are not available to be used for account creation at this time.
230
+ def list_packages
231
+ data = get_xml(:url => "listpkgs")
232
+ check_for_cpanel_errors_on(data)["package"]
233
+ end
234
+
235
+ # Modifies account specific settings. We recommend changing the
236
+ # account's package instead with change_package. If the account
237
+ # is associated with a package, the account's settings will be
238
+ # changed whenever the package is changed. That may overwrite
239
+ # any changes you make with this function.
240
+ #
241
+ # ==== Options
242
+ # * <tt>:CPTHEME</tt> - cPanel theme name (string)
243
+ # * <tt>:domain</tt> - Domain name (string)
244
+ # * <tt>:HASCGI</tt> - Whether or not the domain has CGI access (boolean)
245
+ # * <tt>:LANG</tt> - Language to use in the account's cPanel interface (boolean)
246
+ # * <tt>:MAXFTP</tt> - Maximum number of FTP accounts the user can create. Must be between 0-999999, with 0 being unlimited (integer)
247
+ # * <tt>:MAXSQL</tt> - Maximum number of SQL databases the user can create. Must be between 0-999999, with 0 being unlimited (integer)
248
+ # * <tt>:MAXPOP</tt> - Maximum number of email accounts the user can create. Must be between 0-999999, with 0 being unlimited (integer)
249
+ # * <tt>:MAXLST</tt> - Maximum number of mailing lists the user can create. Must be between 0-999999, with 0 being unlimited (integer)
250
+ # * <tt>:MAXSUB</tt> - Maximum number of subdomains the user can create. Must be between 0-999999, with 0 being unlimited (integer)
251
+ # * <tt>:MAXPARK</tt> - Maximum number of parked domains the user can create. Must be between 0-999999, with 0 being unlimited (integer)
252
+ # * <tt>:MAXADDON</tt> - Maximum number of addon domains the user can create. Must be between 0-999999, with 0 being unlimited (integer)
253
+ # * <tt>:shell</tt> - Whether or not the domain has shell/SSH access (boolean)
254
+ # * <tt>:user</tt> - User name of the account (string)
255
+ def modify_account(options = {})
256
+ booleans!(options, :HASCGI, :LANG, :shell)
257
+ requires!(options, :user, :domain, :HASCGI, :CPTHEME, :LANG, :MAXPOP, :MAXFTP, :MAXLST, :MAXSUB,
258
+ :MAXPARK, :MAXADDON, :MAXSQL, :shell)
259
+
260
+ data = get_xml(:url => "modifyacct", :params => options)
261
+
262
+ check_for_cpanel_errors_on(data)
263
+ end
264
+
265
+ # Suspend an account. Returns <tt>true</tt> if it is successful,
266
+ # or <tt>false</tt> if it is not.
267
+ #
268
+ # ==== Options
269
+ # * <tt>:user</tt> - Username to suspend (string)
270
+ # * <tt>:reason</tt> - Reason for suspension (string)
271
+ def suspend_account(options = {})
272
+ requires!(options, :user, :reason)
273
+
274
+ data = get_xml(:url => "suspendacct", :params => options)
275
+ check_for_cpanel_errors_on(data)
276
+
277
+ data["status"] == "1" ? true : false
278
+ end
279
+
280
+ # Terminates a hosting account. <b>Please note that this action is irreversible!</b>
281
+ #
282
+ # ==== Options
283
+ # * <tt>:user</tt> - Username to terminate (string)
284
+ # * <tt>:keepdns</tt> - Keep DNS entries for the domain ("y" or "n")
285
+ def terminate_account(options = {})
286
+ requires!(options, :user)
287
+
288
+ data = get_xml(:url => "removeacct", :params => {
289
+ :user => options[:user],
290
+ :keepdns => options[:keepdns] || "n"
291
+ })
292
+
293
+ check_for_cpanel_errors_on(data)
294
+ end
295
+
296
+ # Unsuspend a suspended account. Returns <tt>true</tt> if it
297
+ # is successful, or <tt>false</tt> if it is not.
298
+ #
299
+ # ==== Options
300
+ # * <tt>:user</tt> - Username to unsuspend (string)
301
+ def unsuspend_account(options = {})
302
+ requires!(options, :user)
303
+
304
+ data = get_xml(:url => "unsuspendacct", :params => options)
305
+ check_for_cpanel_errors_on(data)
306
+
307
+ data["status"] == "1" ? true : false
308
+ end
309
+
310
+ # Returns the cPanel WHM version.
311
+ def version
312
+ data = get_xml(:url => 'version')
313
+ check_for_cpanel_errors_on(data)["version"]
314
+ end
315
+
316
+ private
317
+
318
+ # Grabs the XML response for a command to the server, and parses it.
319
+ #
320
+ # ==== Options
321
+ # * <tt>:url</tt> - URL of the XML API function (string)
322
+ # * <tt>:params</tt> - Passed in parameter hash (hash)
323
+ def get_xml(options = {})
324
+ requires!(options, :url)
325
+
326
+ prefix = @ssl ? "https" : "http"
327
+ params = []
328
+
329
+ unless options[:params].nil?
330
+ for key, value in options[:params]
331
+ params << Curl::PostField.content(key.to_s, value)
332
+ end
333
+ end
334
+
335
+ request = Curl::Easy.new("#{prefix}://#{@host}:#{@port}/xml-api/#{options[:url]}") do |connection|
336
+ puts "WHM: Requesting #{options[:url]}..." if @debug
337
+
338
+ connection.userpwd = "#{@username}:#{@password}" if @password
339
+ connection.headers["Authorization"] = "WHM #{@username}:#{@remote_key}" if @remote_key
340
+ connection.verbose = true if @debug
341
+ connection.timeout = 60
342
+ end
343
+
344
+ if request.http_post(params)
345
+ puts "Response: #{request.body_str}" if @debug
346
+ xml = XmlSimple.xml_in(request.body_str, { 'ForceArray' => false })
347
+ xml["result"].nil? ? xml : xml["result"]
348
+ end
349
+ end
350
+
351
+ # Returns the data, unless a <tt>status</tt> is equal to <tt>0</tt>,
352
+ # in which case a CommandFailedError exception is
353
+ # thrown with the <tt>statusmsg</tt> from the fetched XML.
354
+ #
355
+ # If the command does not support status messaging,
356
+ # then just return the raw data.
357
+ def check_for_cpanel_errors_on(data)
358
+ result = data["result"].nil? ? data : data["result"]
359
+ if result["status"] == "0"
360
+ raise CommandFailedError, result["statusmsg"]
361
+ else
362
+ result
363
+ end
364
+ end
365
+
366
+ def build_account(attributes) #:nodoc:
367
+ account = Account.new(attributes)
368
+ account.server = self
369
+ account
370
+ end
371
+ end
372
+ end