butzopower-cups 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/ext/cups.c +457 -0
  2. data/ext/extconf.rb +15 -0
  3. data/ext/ruby_cups.h +10 -0
  4. metadata +56 -0
data/ext/cups.c ADDED
@@ -0,0 +1,457 @@
1
+ #include <ruby_cups.h>
2
+
3
+ static int num_options;
4
+ static cups_option_t *options;
5
+ cups_dest_t *dests, *dest;
6
+ VALUE rubyCups, printJobs;
7
+
8
+
9
+ /*
10
+ * call-seq:
11
+ * PrintJob.new(filename, printer=nil)
12
+ *
13
+ * Initializes a new PrintJob object. If no target printer/class is specified, the default is chosen.
14
+ * Note the specified file does not have to exist until print is called.
15
+ */
16
+ static VALUE job_init(int argc, VALUE* argv, VALUE self)
17
+ {
18
+ VALUE filename, printer;
19
+
20
+ rb_scan_args(argc, argv, "11", &filename, &printer);
21
+
22
+ rb_iv_set(self, "@filename", filename);
23
+
24
+ if (NIL_P(printer)) {
25
+
26
+ // Fall back to default printer
27
+ VALUE def_p = rb_funcall(rubyCups, rb_intern("default_printer"), 0);
28
+ rb_iv_set(self, "@printer", def_p);
29
+
30
+ } else {
31
+ // First call Cups#show_destinations
32
+ VALUE dest_list = rb_funcall(rubyCups, rb_intern("show_destinations"), 0);
33
+ // Then check the printer arg is included in the returned array...
34
+ if (rb_ary_includes(dest_list, printer)) {
35
+ rb_iv_set(self, "@printer", printer);
36
+ } else {
37
+ rb_raise(rb_eRuntimeError, "The printer or destination doesn't exist!");
38
+ }
39
+ }
40
+ return self;
41
+ }
42
+
43
+ /*
44
+ * call-seq:
45
+ * print_job.print -> Fixnum
46
+ *
47
+ * Submit a print job to the selected printer or class. Returns true on success.
48
+ */
49
+ static VALUE cups_print(VALUE self, VALUE file, VALUE printer)
50
+ {
51
+ int job_id;
52
+ file = rb_iv_get(self, "@filename");
53
+ printer = rb_iv_get(self, "@printer");
54
+
55
+ char *fname = RSTRING_PTR(file); // Filename
56
+ char *target = RSTRING_PTR(printer); // Target printer string
57
+
58
+ FILE *fp = fopen(fname,"r");
59
+ // Check @filename actually exists...
60
+ if( fp ) {
61
+ fclose(fp);
62
+ job_id = cupsPrintFile(target, fname, "rCUPS", num_options, options); // Do it.
63
+ rb_iv_set(self, "@job_id", INT2NUM(job_id));
64
+ return Qtrue;
65
+ } else {
66
+ // and if it doesn't...
67
+ rb_raise(rb_eRuntimeError, "Couldn't find file");
68
+ return self;
69
+ }
70
+ }
71
+
72
+ /*
73
+ * call-seq:
74
+ * Cups.show_destinations -> Array
75
+ *
76
+ * Show all destinations on the default server
77
+ */
78
+ static VALUE cups_show_dests(VALUE self)
79
+ {
80
+ VALUE dest_list;
81
+ int i;
82
+ int num_dests = cupsGetDests(&dests); // Size of dest_list array
83
+ dest_list = rb_ary_new2(num_dests);
84
+
85
+ for (i = num_dests, dest = dests; i > 0; i --, dest ++) {
86
+ VALUE destination = rb_str_new2(dest->name);
87
+ rb_ary_push(dest_list, destination); // Add this testination name to dest_list string
88
+ }
89
+ return dest_list;
90
+ }
91
+
92
+ /*
93
+ * call-seq:
94
+ * Cups.default_printer -> String or nil
95
+ *
96
+ * Get default printer or class. Returns a string or false if there is no default
97
+ */
98
+ static VALUE cups_get_default(VALUE self)
99
+ {
100
+ const char *default_printer;
101
+ default_printer = cupsGetDefault();
102
+
103
+ if (default_printer != NULL) {
104
+ VALUE def_p = rb_str_new2(default_printer);
105
+ return def_p;
106
+ }
107
+ }
108
+
109
+ /*
110
+ * call-seq:
111
+ * print_job.cancel -> true or false
112
+ *
113
+ * Cancel the current job. Returns true if successful, false otherwise.
114
+ */
115
+ static VALUE cups_cancel(VALUE self)
116
+ {
117
+ VALUE printer, job_id;
118
+ printer = rb_iv_get(self, "@printer");
119
+ job_id = rb_iv_get(self, "@job_id");
120
+
121
+ if (NIL_P(job_id)) {
122
+ return Qfalse; // If @job_id is nil
123
+ } else { // Otherwise attempt to cancel
124
+ int job = NUM2INT(job_id);
125
+ char *target = RSTRING_PTR(printer); // Target printer string
126
+ int cancellation;
127
+ cancellation = cupsCancelJob(target, job);
128
+ return Qtrue;
129
+ }
130
+ }
131
+
132
+ /*
133
+ * call-seq:
134
+ * print_job.failed? -> true or false
135
+ *
136
+ * Did this job fail?
137
+ */
138
+ static VALUE cups_job_failed(VALUE self)
139
+ {
140
+ VALUE job_id = rb_iv_get(self, "@job_id");
141
+
142
+ if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
143
+ return Qfalse;
144
+ } else {
145
+ return Qtrue;
146
+ }
147
+ }
148
+
149
+ /*
150
+ * call-seq:
151
+ * print_job.error_reason -> String
152
+ *
153
+ * Get the last human-readable error string
154
+ */
155
+ static VALUE cups_get_error_reason(VALUE self)
156
+ {
157
+ VALUE job_id = rb_iv_get(self, "@job_id");
158
+
159
+ if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
160
+ return Qnil;
161
+ } else {
162
+ VALUE error_exp = rb_str_new2(cupsLastErrorString());
163
+ return error_exp;
164
+ }
165
+ }
166
+
167
+ /*
168
+ * call-seq:
169
+ * print_job.error_code -> Fixnum
170
+ *
171
+ * Get the last IPP error code.
172
+ */
173
+ static VALUE cups_get_error_code(VALUE self)
174
+ {
175
+ VALUE job_id = rb_iv_get(self, "@job_id");
176
+
177
+ if (NIL_P(job_id) || !NUM2INT(job_id) == 0) {
178
+ return Qnil;
179
+ } else {
180
+ VALUE ipp_error_code = INT2NUM(cupsLastError());
181
+ return ipp_error_code;
182
+ }
183
+ }
184
+
185
+ /*
186
+ * call-seq:
187
+ * print_job.state -> String
188
+ *
189
+ * Get human-readable state of current job.
190
+ */
191
+ static VALUE cups_get_job_state(VALUE self)
192
+ {
193
+ VALUE job_id = rb_iv_get(self, "@job_id");
194
+ VALUE printer = rb_iv_get(self, "@printer");
195
+ VALUE jstate;
196
+
197
+ int num_jobs;
198
+ cups_job_t *jobs;
199
+ ipp_jstate_t job_state = IPP_JOB_PENDING;
200
+ int i;
201
+ char *printer_arg = RSTRING_PTR(printer);
202
+
203
+ if (NIL_P(job_id)) {
204
+ return Qnil;
205
+ } else {
206
+ num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
207
+
208
+ for (i = 0; i < num_jobs; i ++) {
209
+ if (jobs[i].id == NUM2INT(job_id)) {
210
+ job_state = jobs[i].state;
211
+ break;
212
+ }
213
+ }
214
+
215
+ // Free job array
216
+ cupsFreeJobs(num_jobs, jobs);
217
+
218
+ switch (job_state) {
219
+ case IPP_JOB_PENDING :
220
+ jstate = rb_str_new2("Pending...");
221
+ break;
222
+ case IPP_JOB_HELD :
223
+ jstate = rb_str_new2("Held");
224
+ break;
225
+ case IPP_JOB_PROCESSING :
226
+ jstate = rb_str_new2("Processing...");
227
+ break;
228
+ case IPP_JOB_STOPPED :
229
+ jstate = rb_str_new2("Stopped");
230
+ break;
231
+ case IPP_JOB_CANCELED :
232
+ jstate = rb_str_new2("Cancelled");
233
+ break;
234
+ case IPP_JOB_ABORTED :
235
+ jstate = rb_str_new2("Aborted");
236
+ break;
237
+ case IPP_JOB_COMPLETED :
238
+ jstate = rb_str_new2("Completed");
239
+ break;
240
+ default:
241
+ jstate = rb_str_new2("Unknown Job Code...");
242
+ }
243
+
244
+ return jstate;
245
+ }
246
+ }
247
+
248
+ /*
249
+ * call-seq:
250
+ * print_job.completed? -> true or false
251
+ *
252
+ * Has the job completed?
253
+ */
254
+ static VALUE cups_job_completed(VALUE self)
255
+ {
256
+ VALUE job_id = rb_iv_get(self, "@job_id");
257
+ VALUE printer = rb_iv_get(self, "@printer");
258
+ VALUE jstate;
259
+
260
+ int num_jobs;
261
+ cups_job_t *jobs;
262
+ ipp_jstate_t job_state = IPP_JOB_PENDING;
263
+ int i;
264
+ char *printer_arg = RSTRING_PTR(printer);
265
+
266
+ if (NIL_P(job_id)) {
267
+ return Qfalse;
268
+ } else {
269
+ num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
270
+ // job_state = IPP_JOB_COMPLETED;
271
+
272
+ for (i = 0; i < num_jobs; i ++) {
273
+ if (jobs[i].id == NUM2INT(job_id)) {
274
+ job_state = jobs[i].state;
275
+ break;
276
+ }
277
+
278
+ // Free job array
279
+ cupsFreeJobs(num_jobs, jobs);
280
+
281
+ if (job_state == IPP_JOB_COMPLETED) {
282
+ return Qtrue;
283
+ } else {
284
+ return Qfalse;
285
+ }
286
+
287
+ }
288
+ }
289
+ }
290
+
291
+ /*
292
+ * call-seq:
293
+ * Cups.all_jobs(printer) -> Hash
294
+ *
295
+ * Get all jobs from default CUPS server. Takes a single printer/class string argument.
296
+ * Returned hash keys are CUPS job ids, and the values are hashes of job info
297
+ * with keys:
298
+ *
299
+ * [:title, :submitted_by, :size, :format, :state]
300
+ */
301
+ static VALUE cups_get_jobs(VALUE self, VALUE printer)
302
+ {
303
+ VALUE job_list, job_info_hash, jid, jtitle, juser, jsize, jformat, jstate;
304
+ int job_id;
305
+ int num_jobs;
306
+ cups_job_t *jobs;
307
+ ipp_jstate_t state;
308
+ int i;
309
+ char *printer_arg = RSTRING_PTR(printer);
310
+
311
+ num_jobs = cupsGetJobs(&jobs, printer_arg, 1, -1); // Get jobs
312
+ job_list = rb_hash_new();
313
+
314
+ for (i = 0; i < num_jobs; i ++) { // Construct a hash of individual job info
315
+ job_info_hash = rb_hash_new();
316
+ jid = INT2NUM(jobs[i].id);
317
+ jtitle = rb_str_new2(jobs[i].title);
318
+ juser = rb_str_new2(jobs[i].user);
319
+ jsize = INT2NUM(jobs[i].size);
320
+ jformat = rb_str_new2(jobs[i].format);
321
+
322
+ // Let's elaborate on that job state...
323
+ switch (jobs[i].state) {
324
+ case IPP_JOB_PENDING :
325
+ jstate = rb_str_new2("Pending...");
326
+ break;
327
+ case IPP_JOB_HELD :
328
+ jstate = rb_str_new2("Held");
329
+ break;
330
+ case IPP_JOB_PROCESSING :
331
+ jstate = rb_str_new2("Processing...");
332
+ break;
333
+ case IPP_JOB_STOPPED :
334
+ jstate = rb_str_new2("Stopped");
335
+ break;
336
+ case IPP_JOB_CANCELED :
337
+ jstate = rb_str_new2("Cancelled");
338
+ break;
339
+ case IPP_JOB_ABORTED :
340
+ jstate = rb_str_new2("Aborted");
341
+ break;
342
+ case IPP_JOB_COMPLETED :
343
+ jstate = rb_str_new2("Completed");
344
+ }
345
+
346
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("title")), jtitle);
347
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("submitted_by")), juser);
348
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("size")), jsize);
349
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("format")), jformat);
350
+ rb_hash_aset(job_info_hash, ID2SYM(rb_intern("state")), jstate);
351
+
352
+ rb_hash_aset(job_list, jid, job_info_hash); // And push it all into job_list hash
353
+ }
354
+
355
+ // Free job array
356
+ cupsFreeJobs(num_jobs, jobs);
357
+
358
+ return job_list;
359
+ }
360
+
361
+ /*
362
+ * call-seq:
363
+ * Cups.options_for(name) -> Hash or nil
364
+ *
365
+ * Get all options from CUPS server with name. Returns a hash with key/value pairs
366
+ * based on server options, or nil if no server with name.
367
+ */
368
+ static VALUE cups_get_options(VALUE self, VALUE printer)
369
+ {
370
+ VALUE options_list;
371
+ int i;
372
+ char *printer_arg = RSTRING_PTR(printer);
373
+
374
+ options_list = rb_hash_new();
375
+
376
+ cups_dest_t *dests;
377
+ int num_dests = cupsGetDests(&dests);
378
+ cups_dest_t *dest = cupsGetDest(printer_arg, NULL, num_dests, dests);
379
+
380
+ if (dest == NULL) {
381
+ cupsFreeDests(num_dests, dests);
382
+ return Qnil;
383
+ } else {
384
+ for(i =0; i< dest->num_options; i++) {
385
+ rb_hash_aset(options_list, rb_str_new2(dest->options[i].name), rb_str_new2(dest->options[i].value));
386
+ }
387
+
388
+ cupsFreeDests(num_dests, dests);
389
+ return options_list;
390
+ }
391
+
392
+ }
393
+
394
+ // TODO
395
+ // int ipp_state_to_string(int state)
396
+ // {
397
+ // // char *jstate;
398
+ // switch (state) {
399
+ // case IPP_JOB_PENDING :
400
+ // // jstate = rb_str_new2("Pending...");
401
+ // // char jstate[] = "Pending...";
402
+ // break;
403
+ // case IPP_JOB_HELD :
404
+ // // jstate = rb_str_new2("Held");
405
+ // // char jstate[] = "Held";
406
+ // break;
407
+ // case IPP_JOB_PROCESSING :
408
+ // // jstate = rb_str_new2("Processing...");
409
+ // // char jstate[] = "Processing...";
410
+ // break;
411
+ // case IPP_JOB_STOPPED :
412
+ // // jstate = rb_str_new2("Stopped");
413
+ // // char jstate[] = "Stopped";
414
+ // break;
415
+ // case IPP_JOB_CANCELED :
416
+ // // jstate = rb_str_new2("Cancelled");
417
+ // // char jstate[] = "Cancelled";
418
+ // break;
419
+ // case IPP_JOB_ABORTED :
420
+ // // jstate = rb_str_new2("Aborted");
421
+ // // char jstate[] = "Aborted";
422
+ // break;
423
+ // case IPP_JOB_COMPLETED :
424
+ // // jstate = rb_str_new2("Completed");
425
+ // break;
426
+ // }
427
+ // return 0;
428
+ // }
429
+
430
+ /*
431
+ */
432
+
433
+ void Init_cups() {
434
+ rubyCups = rb_define_module("Cups");
435
+ printJobs = rb_define_class_under(rubyCups, "PrintJob", rb_cObject);
436
+
437
+ // Cups::PrintJob Attributes
438
+ rb_define_attr(printJobs, "printer", 1, 0);
439
+ rb_define_attr(printJobs, "filename", 1, 0);
440
+ rb_define_attr(printJobs, "job_id", 1, 0);
441
+
442
+ // Cups::PrintJob Methods
443
+ rb_define_method(printJobs, "initialize", job_init, -1);
444
+ rb_define_method(printJobs, "print", cups_print, 0);
445
+ rb_define_method(printJobs, "cancel", cups_cancel, 0);
446
+ rb_define_method(printJobs, "state", cups_get_job_state, 0);
447
+ rb_define_method(printJobs, "completed?", cups_job_completed, 0);
448
+ rb_define_method(printJobs, "failed?", cups_job_failed, 0);
449
+ rb_define_method(printJobs, "error_reason", cups_get_error_reason, 0);
450
+ rb_define_method(printJobs, "error_code", cups_get_error_code, 0);
451
+
452
+ // Cups Module Methods
453
+ rb_define_singleton_method(rubyCups, "show_destinations", cups_show_dests, 0);
454
+ rb_define_singleton_method(rubyCups, "default_printer", cups_get_default, 0);
455
+ rb_define_singleton_method(rubyCups, "all_jobs", cups_get_jobs, 1);
456
+ rb_define_singleton_method(rubyCups, "options_for", cups_get_options, 1);
457
+ }
data/ext/extconf.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "mkmf"
2
+
3
+ unless have_library("cups") && find_executable("cups-config")
4
+ puts "Couldn't find CUPS libraries on your system. Check they're installed and in your path."
5
+ exit
6
+ end
7
+
8
+ cups_cflags = `cups-config --cflags`.chomp || ""
9
+ cups_libs = `cups-config --libs`.chomp || ""
10
+
11
+ with_cflags(cups_cflags) {
12
+ with_ldflags(cups_libs) {
13
+ create_makefile("cups")
14
+ }
15
+ }
data/ext/ruby_cups.h ADDED
@@ -0,0 +1,10 @@
1
+ #include <cups/cups.h>
2
+ #ifdef __APPLE__
3
+ #include <ruby/ruby.h>
4
+ #else
5
+ #include <ruby.h>
6
+ #endif
7
+
8
+ #ifndef MAXOPTS
9
+ #define MAXOPTS 100
10
+ #endif
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: butzopower-cups
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Chris Mowforth
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Ruby CUPS provides a wrapper for the Common UNIX Printing System, allowing rubyists to perform basic tasks like printer discovery, job submission & querying.
17
+ email:
18
+ - chris@mowforth.com
19
+ executables: []
20
+
21
+ extensions:
22
+ - ext/extconf.rb
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - ext/cups.c
27
+ - ext/ruby_cups.h
28
+ - ext/extconf.rb
29
+ has_rdoc: true
30
+ homepage: http://cups.rubyforge.org/
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ version:
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ requirements: []
49
+
50
+ rubyforge_project: cups
51
+ rubygems_version: 1.2.0
52
+ signing_key:
53
+ specification_version: 2
54
+ summary: A lightweight Ruby library for printing.
55
+ test_files: []
56
+