filemaker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +17 -0
  5. data/.travis.yml +4 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +116 -0
  9. data/Rakefile +6 -0
  10. data/diagram.png +0 -0
  11. data/filemaker.gemspec +30 -0
  12. data/lib/filemaker.rb +13 -0
  13. data/lib/filemaker/api.rb +13 -0
  14. data/lib/filemaker/api/query_commands/delete.rb +16 -0
  15. data/lib/filemaker/api/query_commands/dup.rb +22 -0
  16. data/lib/filemaker/api/query_commands/edit.rb +26 -0
  17. data/lib/filemaker/api/query_commands/find.rb +46 -0
  18. data/lib/filemaker/api/query_commands/findall.rb +34 -0
  19. data/lib/filemaker/api/query_commands/findany.rb +26 -0
  20. data/lib/filemaker/api/query_commands/findquery.rb +84 -0
  21. data/lib/filemaker/api/query_commands/new.rb +21 -0
  22. data/lib/filemaker/api/query_commands/view.rb +11 -0
  23. data/lib/filemaker/configuration.rb +28 -0
  24. data/lib/filemaker/core_ext/hash.rb +32 -0
  25. data/lib/filemaker/database.rb +29 -0
  26. data/lib/filemaker/error.rb +391 -0
  27. data/lib/filemaker/layout.rb +38 -0
  28. data/lib/filemaker/metadata/field.rb +71 -0
  29. data/lib/filemaker/record.rb +64 -0
  30. data/lib/filemaker/resultset.rb +124 -0
  31. data/lib/filemaker/script.rb +9 -0
  32. data/lib/filemaker/server.rb +197 -0
  33. data/lib/filemaker/store/database_store.rb +21 -0
  34. data/lib/filemaker/store/layout_store.rb +23 -0
  35. data/lib/filemaker/store/script_store.rb +23 -0
  36. data/lib/filemaker/version.rb +3 -0
  37. data/spec/filemaker/api/query_commands/compound_find_spec.rb +69 -0
  38. data/spec/filemaker/error_spec.rb +257 -0
  39. data/spec/filemaker/layout_spec.rb +229 -0
  40. data/spec/filemaker/metadata/field_spec.rb +62 -0
  41. data/spec/filemaker/record_spec.rb +47 -0
  42. data/spec/filemaker/resultset_spec.rb +65 -0
  43. data/spec/filemaker/server_spec.rb +106 -0
  44. data/spec/filemaker/store/database_store_spec.rb +34 -0
  45. data/spec/filemaker/store/layout_store_spec.rb +31 -0
  46. data/spec/filemaker/store/script_store_spec.rb +31 -0
  47. data/spec/spec_helper.rb +84 -0
  48. data/spec/support/responses/dbnames.xml +34 -0
  49. data/spec/support/responses/employment.xml +55 -0
  50. data/spec/support/responses/jobs.xml +199 -0
  51. data/spec/support/responses/layoutnames.xml +39 -0
  52. data/spec/support/responses/portal.xml +108 -0
  53. data/spec/support/responses/scriptnames.xml +29 -0
  54. data/spec/support/xml_loader.rb +29 -0
  55. metadata +227 -0
@@ -0,0 +1,84 @@
1
+ module Filemaker
2
+ module Api
3
+ module QueryCommands
4
+ # Find records using compound find query command.
5
+ #
6
+ # query(status: 'open', title: 'web') => (q0,q1)
7
+ # query(status: %w(open closed)) => (q0);(q1)
8
+ #
9
+ def query(array_hash)
10
+ compound_find = CompoundFind.new(array_hash)
11
+
12
+ query_hash = compound_find.key_values.merge(
13
+ '-query' => compound_find.key_maps_string
14
+ )
15
+
16
+ findquery(query_hash)
17
+ end
18
+
19
+ # Raw -findquery if you want to construct your own.
20
+ def findquery(query_hash, options = {})
21
+ perform_request('-findquery', query_hash, options)
22
+ end
23
+
24
+ # Convenient compound find query builder
25
+ class CompoundFind
26
+ attr_reader :key_values, :key_maps_string
27
+
28
+ def initialize(query)
29
+ @query = query
30
+ @key_values = {}
31
+ @key_maps = []
32
+ @key_maps_string = ''
33
+ @counter = 0
34
+
35
+ become_array(@query).each do |hash|
36
+ build_key_map(build_key_values(hash))
37
+ end
38
+
39
+ translate_key_maps
40
+ end
41
+
42
+ private
43
+
44
+ def build_key_values(hash)
45
+ q_tag_array = []
46
+ omit = hash.delete('-omit')
47
+
48
+ hash.each do |key, value|
49
+ q_tag = []
50
+ become_array(value).each do |v|
51
+ @key_values["-q#{@counter}"] = key
52
+ @key_values["-q#{@counter}.value"] = v
53
+ q_tag << "q#{@counter}"
54
+ @counter += 1
55
+ end
56
+ q_tag_array << q_tag
57
+ end
58
+
59
+ (q_tag_array << '-omit') if omit
60
+ q_tag_array
61
+ end
62
+
63
+ def build_key_map(q_tag_array)
64
+ omit = q_tag_array.delete('-omit')
65
+ len = q_tag_array.length
66
+ result = q_tag_array.flatten.combination(len).select do |c|
67
+ q_tag_array.all? { |a| (a & c).size > 0 }
68
+ end.each { |c| c.unshift('-omit') if omit }
69
+ @key_maps.concat result
70
+ end
71
+
72
+ def translate_key_maps
73
+ @key_maps_string << @key_maps.map do |a|
74
+ "#{'!' if a.delete('-omit')}(#{a.join(',')})"
75
+ end.join(';')
76
+ end
77
+
78
+ def become_array(value)
79
+ value.is_a?(Array) ? value : [value]
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,21 @@
1
+ module Filemaker
2
+ module Api
3
+ module QueryCommands
4
+ # Add new record.
5
+ #
6
+ # -script
7
+ # -script.param
8
+ # -relatedsets.filter
9
+ # -relatedsets.max
10
+ #
11
+ def new(values, options = {})
12
+ valid_options(options,
13
+ :script,
14
+ :relatedsets_filter,
15
+ :relatedsets_max)
16
+
17
+ perform_request('-new', values, options)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module Filemaker
2
+ module Api
3
+ module QueryCommands
4
+ # Retrieves <metadata> section of XML.
5
+ #
6
+ def view
7
+ perform_request('-view', {}, {})
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ module Filemaker
2
+ class Configuration
3
+ attr_accessor :host, :account_name, :password, :ssl, :endpoint
4
+ attr_accessor :log
5
+
6
+ def initialize
7
+ @endpoint = '/fmi/xml/fmresultset.xml'
8
+ end
9
+
10
+ def not_configurable?
11
+ host_missing? || account_name_missing? || password_missing?
12
+ end
13
+
14
+ %w(host account_name password).each do |name|
15
+ define_method "#{name}_missing?" do
16
+ (send(name.to_sym) || '').empty?
17
+ end
18
+ end
19
+
20
+ def connection_options
21
+ ssl.is_a?(Hash) ? { ssl: ssl } : {}
22
+ end
23
+
24
+ def url
25
+ (ssl.is_a?(Hash) || ssl == true) ? "https://#{host}" : "http://#{host}"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,32 @@
1
+ class Hash
2
+ def transform_keys
3
+ return enum_for(:transform_keys) unless block_given?
4
+ result = self.class.new
5
+ each_key do |key|
6
+ result[yield(key)] = self[key]
7
+ end
8
+ result
9
+ end
10
+
11
+ def stringify_keys
12
+ transform_keys { |key| key.to_s }
13
+ end
14
+ end
15
+
16
+ module Filemaker
17
+ class HashWithIndifferentAndCaseInsensitiveAccess < Hash
18
+ def []=(key, value)
19
+ super(convert_key(key), value)
20
+ end
21
+
22
+ def [](key)
23
+ super(convert_key(key))
24
+ end
25
+
26
+ protected
27
+
28
+ def convert_key(key)
29
+ key.to_s.downcase
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Filemaker
2
+ class Database
3
+ # @return [String] database name
4
+ attr_reader :name
5
+
6
+ # @return [Filemaker::Server] the server
7
+ attr_reader :server
8
+
9
+ # @return [Filemaker::Store::LayoutStore] the layout store
10
+ attr_reader :layouts
11
+ alias_method :layout, :layouts
12
+ alias_method :lay, :layouts
13
+
14
+ # @return [Filemaker::Store::ScriptStore] the script store
15
+ attr_reader :scripts
16
+
17
+ def initialize(name, server)
18
+ @name = name
19
+ @server = server
20
+ @layouts = Store::LayoutStore.new(server, self)
21
+ @scripts = Store::ScriptStore.new(server, self)
22
+ end
23
+
24
+ # A very convenient way to access some layout from this database
25
+ def [](layout_name)
26
+ layouts[layout_name]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,391 @@
1
+ module Filemaker
2
+ module Error
3
+ class CommunicationError < StandardError; end
4
+ class AuthenticationError < StandardError; end
5
+ class ParameterError < StandardError; end
6
+ class CoerceError < StandardError; end
7
+
8
+ class FilemakerError < StandardError
9
+ attr_reader :code
10
+
11
+ def initialize(code, message = nil)
12
+ @code = code
13
+ super(message)
14
+ end
15
+ end
16
+
17
+ class SystemError < FilemakerError; end
18
+
19
+ class UnknownError < SystemError; end
20
+ class UserCancelledError < SystemError; end
21
+ class MemoryError < SystemError; end
22
+ class CommandNotAvailableError < SystemError; end
23
+ class CommandUnknownError < SystemError; end
24
+ class CommandInvalidError < SystemError; end
25
+ class FileReadOnlyError < SystemError; end
26
+ class OutOfMemoryError < SystemError; end
27
+ class EmptyResultError < SystemError; end
28
+ class InsufficientPrivilegesError < SystemError; end
29
+ class RequestedDataMissingError < SystemError; end
30
+
31
+ class MissingError < FilemakerError; end
32
+ class FileMissingError < MissingError; end
33
+ class RecordMissingError < MissingError; end
34
+ class FieldMissingError < MissingError; end
35
+ class ScriptMissingError < MissingError; end
36
+ class LayoutMissingError < MissingError; end
37
+ class TableMissingError < MissingError; end
38
+
39
+ class SecurityError < FilemakerError; end
40
+ class RecordAccessDeniedError < SecurityError; end
41
+ class FieldCannotBeModifiedError < SecurityError; end
42
+ class FieldAccessDeniedError < SecurityError; end
43
+
44
+ class ConcurrencyError < FilemakerError; end
45
+ class FileLockedError < ConcurrencyError; end
46
+ class RecordInUseError < ConcurrencyError; end
47
+ class TableInUseError < ConcurrencyError; end
48
+ class RecordModificationIdMismatchError < ConcurrencyError; end
49
+
50
+ class GeneralError < FilemakerError; end
51
+ class FindCriteriaEmptyError < GeneralError; end
52
+ class NoRecordsFoundError < GeneralError; end
53
+
54
+ class ValidationError < FilemakerError; end
55
+ class DateValidationError < ValidationError; end
56
+ class TimeValidationError < ValidationError; end
57
+ class NumberValidationError < ValidationError; end
58
+ class RangeValidationError < ValidationError; end
59
+ class UniquenessValidationError < ValidationError; end
60
+ class ExistingValidationError < ValidationError; end
61
+ class ValueListValidationError < ValidationError; end
62
+ class CalculationValidationError < ValidationError; end
63
+ class InvalidFindModeValueValidationError < ValidationError; end
64
+ class MaximumCharactersValidationError < ValidationError; end
65
+
66
+ class FileError < FilemakerError; end
67
+ class UnableToCreateFileError < FileError; end
68
+ class UnableToCreateTempFileError < FileError; end
69
+ class UnableToOpenFileError < FileError; end
70
+
71
+ def self.raise_error_by_code(code)
72
+ msg = error_message_by_code(code)
73
+ error_class = find_error_class_by_code(code)
74
+ raise error_class.new(code, msg)
75
+ end
76
+
77
+ def self.error_message_by_code(code)
78
+ "FileMaker Error: #{code} (#{DESCRIPTION.fetch(code.to_s) { '??' }})"
79
+ end
80
+
81
+ def self.find_error_class_by_code(code)
82
+ case code
83
+ when -1 then UnknownError
84
+ when 1..99
85
+ if code == 1; UserCancelledError
86
+ elsif code == 2; MemoryError
87
+ elsif code == 3; CommandNotAvailableError
88
+ elsif code == 4; CommandUnknownError
89
+ elsif code == 5; CommandInvalidError
90
+ elsif code == 6; FileReadOnlyError
91
+ elsif code == 7; OutOfMemoryError
92
+ elsif code == 8; EmptyResultError
93
+ elsif code == 9; InsufficientPrivilegesError
94
+ elsif code == 10; RequestedDataMissingError
95
+ else SystemError; end
96
+ when 100..199
97
+ if code == 100; FileMissingError
98
+ elsif code == 101; RecordMissingError
99
+ elsif code == 102; FieldMissingError
100
+ elsif code == 104; ScriptMissingError
101
+ elsif code == 105; LayoutMissingError
102
+ elsif code == 106; TableMissingError
103
+ else MissingError; end
104
+ when 200..299
105
+ if code == 200; RecordAccessDeniedError
106
+ elsif code == 201; FieldCannotBeModifiedError
107
+ elsif code == 202; FieldAccessDeniedError
108
+ else SecurityError; end
109
+ when 300..399
110
+ if code == 300; FileLockedError
111
+ elsif code == 301; RecordInUseError
112
+ elsif code == 302; TableInUseError
113
+ elsif code == 306; RecordModificationIdMismatchError
114
+ else ConcurrencyError; end
115
+ when 400..499
116
+ if code == 400; FindCriteriaEmptyError
117
+ elsif code == 401; NoRecordsFoundError
118
+ else; GeneralError; end
119
+ when 500..599
120
+ if code == 500; DateValidationError
121
+ elsif code == 501; TimeValidationError
122
+ elsif code == 502; NumberValidationError
123
+ elsif code == 503; RangeValidationError
124
+ elsif code == 504; UniquenessValidationError
125
+ elsif code == 505; ExistingValidationError
126
+ elsif code == 506; ValueListValidationError
127
+ elsif code == 507; CalculationValidationError
128
+ elsif code == 508; InvalidFindModeValueValidationError
129
+ elsif code == 511; MaximumCharactersValidationError
130
+ else; ValidationError; end
131
+ when 800..899
132
+ if code == 800; UnableToCreateFileError
133
+ elsif code == 801; UnableToCreateTempFileError
134
+ elsif code == 802; UnableToOpenFileError
135
+ elsif code == 804; FileReadOnlyError
136
+ else; FileError; end
137
+ else
138
+ UnknownError
139
+ end
140
+ end
141
+
142
+ DESCRIPTION = {
143
+ '-1' => 'Unknown error',
144
+ '1' => 'User cancelled action',
145
+ '2' => 'Memory error',
146
+ '3' => 'Command is unavailable (for example, wrong operating system, wrong mode, etc.)',
147
+ '4' => 'Command is unknown',
148
+ '5' => 'Command is invalid (for example, a Set Field script step does not have a calculation specified)',
149
+ '6' => 'File is read-only',
150
+ '7' => 'Running out of memory',
151
+ '8' => 'Empty result',
152
+ '9' => 'Insufficient privileges',
153
+ '10' => 'Requested data is missing',
154
+ '11' => 'Name is not valid',
155
+ '12' => 'Name already exists',
156
+ '13' => 'File or object is in use',
157
+ '14' => 'Out of range',
158
+ '15' => 'Can\'t divide by zero',
159
+ '16' => 'Operation failed, request retry (for example, a user query)',
160
+ '17' => 'Attempt to convert foreign character set to UTF-16 failed',
161
+ '18' => 'Client must provide account information to proceed',
162
+ '19' => 'String contains characters other than A-Z, a-z, 0-9 (ASCII)',
163
+ '20' => 'Command or operation cancelled by triggered script',
164
+ '21' => 'Request not supported (for example, when creating a hard link on a file system that does not support hard links)',
165
+ '100' => 'File is missing',
166
+ '101' => 'Record is missing',
167
+ '102' => 'Field is missing',
168
+ '103' => 'Relationship is missing',
169
+ '104' => 'Script is missing',
170
+ '105' => 'Layout is missing',
171
+ '106' => 'Table is missing',
172
+ '107' => 'Index is missing',
173
+ '108' => 'Value list is missing',
174
+ '109' => 'Privilege set is missing',
175
+ '110' => 'Related tables are missing',
176
+ '111' => 'Field repetition is invalid',
177
+ '112' => 'Window is missing',
178
+ '113' => 'Function is missing',
179
+ '114' => 'File reference is missing',
180
+ '115' => 'Menu set is missing',
181
+ '116' => 'Layout object is missing',
182
+ '117' => 'Data source is missing',
183
+ '118' => 'Theme is missing',
184
+ '130' => 'Files are damaged or missing and must be reinstalled',
185
+ '131' => 'Language pack files are missing (such as Starter Solutions)',
186
+ '200' => 'Record access is denied',
187
+ '201' => 'Field cannot be modified',
188
+ '202' => 'Field access is denied',
189
+ '203' => 'No records in file to print, or password doesn\'t allow print access',
190
+ '204' => 'No access to field(s) in sort order',
191
+ '205' => 'User does not have access privileges to create new records; import will overwrite existing data',
192
+ '206' => 'User does not have password change privileges, or file is not modifiable',
193
+ '207' => 'User does not have sufficient privileges to change database schema, or file is not modifiable',
194
+ '208' => 'Password does not contain enough characters',
195
+ '209' => 'New password must be different from existing one',
196
+ '210' => 'User account is inactive',
197
+ '211' => 'Password has expired',
198
+ '212' => 'Invalid user account and/or password. Please try again',
199
+ '213' => 'User account and/or password does not exist',
200
+ '214' => 'Too many login attempts',
201
+ '215' => 'Administrator privileges cannot be duplicated',
202
+ '216' => 'Guest account cannot be duplicated',
203
+ '217' => 'User does not have sufficient privileges to modify administrator account',
204
+ '218' => 'Password and verify password do not match',
205
+ '300' => 'File is locked or in use',
206
+ '301' => 'Record is in use by another user',
207
+ '302' => 'Table is in use by another user',
208
+ '303' => 'Database schema is in use by another user',
209
+ '304' => 'Layout is in use by another user',
210
+ '306' => 'Record modification ID does not match',
211
+ '307' => 'Transaction could not be locked because of a communication error with the host',
212
+ '308' => 'Theme is locked and in use by another user',
213
+ '400' => 'Find criteria are empty',
214
+ '401' => 'No records match the request',
215
+ '402' => 'Selected field is not a match field for a lookup',
216
+ '403' => 'Exceeding maximum record limit for trial version of FileMaker Pro',
217
+ '404' => 'Sort order is invalid',
218
+ '405' => 'Number of records specified exceeds number of records that can be omitted',
219
+ '406' => 'Replace/Reserialize criteria are invalid',
220
+ '407' => 'One or both match fields are missing (invalid relationship)',
221
+ '408' => 'Specified field has inappropriate data type for this operation',
222
+ '409' => 'Import order is invalid',
223
+ '410' => 'Export order is invalid',
224
+ '412' => 'Wrong version of FileMaker Pro used to recover file',
225
+ '413' => 'Specified field has inappropriate field type',
226
+ '414' => 'Layout cannot display the result',
227
+ '415' => 'One or more required related records are not available',
228
+ '416' => 'A primary key is required from the data source table',
229
+ '417' => 'Database is not a supported data source',
230
+ '418' => 'Internal failure in INSERT operation into a field',
231
+ '500' => 'Date value does not meet validation entry options',
232
+ '501' => 'Time value does not meet validation entry options',
233
+ '502' => 'Number value does not meet validation entry options',
234
+ '503' => 'Value in field is not within the range specified in validation entry options',
235
+ '504' => 'Value in field is not unique as required in validation entry options',
236
+ '505' => 'Value in field is not an existing value in the database file as required in validation entry options',
237
+ '506' => 'Value in field is not listed on the value list specified in validation entry option',
238
+ '507' => 'Value in field failed calculation test of validation entry option',
239
+ '508' => 'Invalid value entered in Find mode',
240
+ '509' => 'Field requires a valid value',
241
+ '510' => 'Related value is empty or unavailable',
242
+ '511' => 'Value in field exceeds maximum field size',
243
+ '512' => 'Record was already modified by another user',
244
+ '513' => 'No validation was specified but data cannot fit into the field',
245
+ '600' => 'Print error has occurred',
246
+ '601' => 'Combined header and footer exceed one page',
247
+ '602' => 'Body doesn\'t fit on a page for current column setup',
248
+ '603' => 'Print connection lost',
249
+ '700' => 'File is of the wrong file type for import',
250
+ '706' => 'EPSF file has no preview image',
251
+ '707' => 'Graphic translator cannot be found',
252
+ '708' => 'Can\'t import the file or need color monitor support to import file',
253
+ '709' => 'QuickTime movie import failed',
254
+ '710' => 'Unable to update QuickTime file reference because the database file is read-only',
255
+ '711' => 'Import translator cannot be found',
256
+ '714' => 'Password privileges do not allow the operation',
257
+ '715' => 'Specified Excel worksheet or named range is missing',
258
+ '716' => 'A SQL query using DELETE, INSERT, or UPDATE is not allowed for ODBC import',
259
+ '717' => 'There is not enough XML/XSL information to proceed with the import or export',
260
+ '718' => 'Error in parsing XML file (from Xerces)',
261
+ '719' => 'Error in transforming XML using XSL (from Xalan)',
262
+ '720' => 'Error when exporting; intended format does not support repeating fields',
263
+ '721' => 'Unknown error occurred in the parser or the transformer',
264
+ '722' => 'Cannot import data into a file that has no fields',
265
+ '723' => 'You do not have permission to add records to or modify records in the target table',
266
+ '724' => 'You do not have permission to add records to the target table',
267
+ '725' => 'You do not have permission to modify records in the target table',
268
+ '726' => 'There are more records in the import file than in the target table. Not all records were imported',
269
+ '727' => 'There are more records in the target table than in the import file. Not all records were updated',
270
+ '729' => 'Errors occurred during import. Records could not be imported',
271
+ '730' => 'Unsupported Excel version (convert file to Excel 2007/2008 format or a later supported version and try again)',
272
+ '731' => 'File you are importing from contains no data',
273
+ '732' => 'This file cannot be inserted because it contains other files',
274
+ '733' => 'A table cannot be imported into itself',
275
+ '734' => 'This file type cannot be displayed as a picture',
276
+ '735' => 'This file type cannot be displayed as a picture. It will be inserted and displayed as a file',
277
+ '736' => 'There is too much data to be exported to this format. It will be truncated.',
278
+ '737' => 'Bento table you are importing is missing',
279
+ '738' => 'The theme you are importing already exists',
280
+ '800' => 'Unable to create file on disk',
281
+ '801' => 'Unable to create temporary file on System disk',
282
+ '802' => 'Unable to open file',
283
+ '803' => 'File is single user or host cannot be found',
284
+ '804' => 'File cannot be opened as read-only in its current state',
285
+ '805' => 'File is damaged; use Recover command',
286
+ '806' => 'File cannot be opened with this version of FileMaker Pro',
287
+ '807' => 'File is not a FileMaker Pro file or is severely damaged',
288
+ '808' => 'Cannot open file because access privileges are damaged',
289
+ '809' => 'Disk/volume is full',
290
+ '810' => 'Disk/volume is locked',
291
+ '811' => 'Temporary file cannot be opened as FileMaker Pro file',
292
+ '812' => 'Exceeded host\'s capacity',
293
+ '813' => 'Record Synchronization error on network',
294
+ '814' => 'File(s) cannot be opened because maximum number is open',
295
+ '815' => 'Couldn\'t open lookup file',
296
+ '816' => 'Unable to convert file',
297
+ '817' => 'Unable to open file because it does not belong to this solution',
298
+ '819' => 'Cannot save a local copy of a remote file',
299
+ '820' => 'File is in the process of being closed',
300
+ '821' => 'Host forced a disconnect',
301
+ '822' => 'FMI files not found; reinstall missing files',
302
+ '823' => 'Cannot set file to single-user, guests are connected',
303
+ '824' => 'File is damaged or not a FileMaker file',
304
+ '825' => 'File is not authorized to reference the protected file',
305
+ '826' => 'File path specified is not a valid file path',
306
+ '850' => 'Path is not valid for the operating system',
307
+ '851' => 'Cannot delete an external file from disk',
308
+ '852' => 'Cannot write a file to the external storage',
309
+ '853' => 'One or more containers failed to transfer',
310
+ '900' => 'General spelling engine error',
311
+ '901' => 'Main spelling dictionary not installed',
312
+ '902' => 'Could not launch the Help system',
313
+ '903' => 'Command cannot be used in a shared file',
314
+ '905' => 'No active field selected; command can only be used if there is an active field',
315
+ '906' => 'Current file is not shared; command can be used only if the file is shared',
316
+ '920' => 'Can\'t initialize the spelling engine',
317
+ '921' => 'User dictionary cannot be loaded for editing',
318
+ '922' => 'User dictionary cannot be found',
319
+ '923' => 'User dictionary is read-only',
320
+ '951' => 'An unexpected error occurred',
321
+ '954' => 'Unsupported XML grammar',
322
+ '955' => 'No database name',
323
+ '956' => 'Maximum number of database sessions exceeded',
324
+ '957' => 'Conflicting commands',
325
+ '958' => 'Parameter missing in query',
326
+ '959' => 'Custom Web Publishing technology is disabled',
327
+ '960' => 'Parameter is invalid',
328
+ '1200' => 'Generic calculation error',
329
+ '1201' => 'Too few parameters in the function',
330
+ '1202' => 'Too many parameters in the function',
331
+ '1203' => 'Unexpected end of calculation',
332
+ '1204' => 'Number, text constant, field name or "(" expected',
333
+ '1205' => 'Comment is not terminated with "*/"',
334
+ '1206' => 'Text constant must end with a quotation mark',
335
+ '1207' => 'Unbalanced parenthesis',
336
+ '1208' => 'Operator missing, function not found or "(" not expected',
337
+ '1209' => 'Name (such as field name or layout name) is missing',
338
+ '1210' => 'Plug-in function has already been registered',
339
+ '1211' => 'List usage is not allowed in this function',
340
+ '1212' => 'An operator (for example, +, -, *) is expected here',
341
+ '1213' => 'This variable has already been defined in the Let function',
342
+ '1214' => 'AVERAGE, COUNT, EXTEND, GETREPETITION, MAX, MIN, NPV, STDEV, SUM and GETSUMMARY: expression found where a field alone is needed',
343
+ '1215' => 'This parameter is an invalid Get function parameter',
344
+ '1216' => 'Only Summary fields allowed as first argument in GETSUMMARY',
345
+ '1217' => 'Break field is invalid',
346
+ '1218' => 'Cannot evaluate the number',
347
+ '1219' => 'A field cannot be used in its own formula',
348
+ '1220' => 'Field type must be normal or calculated',
349
+ '1221' => 'Data type must be number, date, time, or timestamp',
350
+ '1222' => 'Calculation cannot be stored',
351
+ '1223' => 'Function referred to is not yet implemented',
352
+ '1224' => 'Function referred to does not exist',
353
+ '1225' => 'Function referred to is not supported in this context',
354
+ '1300' => 'The specified name can\'t be used',
355
+ '1301' => 'One of the parameters of the function being imported or pasted has the same name as a function already in the file',
356
+ '1400' => 'ODBC client driver initialization failed; make sure the ODBC client drivers are properly installed',
357
+ '1401' => 'Failed to allocate environment (ODBC)',
358
+ '1402' => 'Failed to free environment (ODBC)',
359
+ '1403' => 'Failed to disconnect (ODBC)',
360
+ '1404' => 'Failed to allocate connection (ODBC)',
361
+ '1405' => 'Failed to free connection (ODBC)',
362
+ '1406' => 'Failed check for SQL API (ODBC)',
363
+ '1407' => 'Failed to allocate statement (ODBC)',
364
+ '1408' => 'Extended error (ODBC)',
365
+ '1409' => 'Extended error (ODBC)',
366
+ '1410' => 'Extended error (ODBC)',
367
+ '1411' => 'Extended error (ODBC)',
368
+ '1412' => 'Extended error (ODBC)',
369
+ '1413' => 'Extended error (ODBC)',
370
+ '1414' => 'SQL statement is too long',
371
+ '1450' => 'Action requires PHP privilege extension',
372
+ '1451' => 'Action requires that current file be remote',
373
+ '1501' => 'SMTP authentication failed',
374
+ '1502' => 'Connection refused by SMTP server',
375
+ '1503' => 'Error with SSL',
376
+ '1504' => 'SMTP server requires the connection to be encrypted',
377
+ '1505' => 'Specified authentication is not supported by SMTP server',
378
+ '1506' => 'Email message(s) could not be sent successfully',
379
+ '1507' => 'Unable to log in to the SMTP server',
380
+ '1550' => 'Cannot load the plug-in or the plug-in is not a valid plug-in',
381
+ '1551' => 'Cannot install the plug-in. Cannot delete an existing plug-in or cannot write to the folder or disk',
382
+ '1626' => 'Protocol is not supported',
383
+ '1627' => 'Authentication failed',
384
+ '1628' => 'There was an error with SSL',
385
+ '1629' => 'Connection timed out; the timeout value is 60 seconds',
386
+ '1630' => 'URL format is incorrect',
387
+ '1631' => 'Connection failed',
388
+ '8003' => 'Lock conflict with database users or other error'
389
+ }
390
+ end
391
+ end