File Coverage

blib/lib/Mail/Bulkmail/Object.pm
Criterion Covered Total %
statement 170 259 65.6
branch 41 150 27.3
condition 10 50 20.0
subroutine 33 36 91.6
pod 16 17 94.1
total 270 512 52.7


line stmt bran cond sub pod time code
1             package Mail::Bulkmail::Object;
2              
3             #Copyright and (c) 1999, 2000, 2001, 2002, 2003 James A Thomason III (jim@jimandkoka.com). All rights reserved.
4             #Mail::Bulkmail::Object is distributed under the terms of the Perl Artistic License.
5              
6             # SCROLL DOWN TO @conf_files ARRAY TO CONFIGURE IT
7              
8             =pod
9              
10             =head1 NAME
11              
12             Mail::Bulkmail::Object - used to create subclasses for Mail::Bulkmail.
13              
14             =head1 AUTHOR
15              
16             Jim Thomason, jim@jimandkoka.com
17              
18             =head1 DESCRIPTION
19              
20             Older versions of this code used to be contained within the Mail::Bulkmail package itself, but since 3.00 now has
21             all of the code compartmentalized, I couldn't leave this in there. Well, technically I *could*, but I didn't like that.
22             It's wasteful to make Mail::Bulkmail::Server a subclass of Mail::Bulkmail, for instance, since they don't share
23             any methods, attributes, whatever. Well, none beyond the standard object methods that I like to use. Hence this module
24             was born.
25              
26             Of course, you don't have to use this to create subclasses, but you'll run the risk of making something with an inconsistent
27             interface vs. the rest of the system. That'll confuse people and make them unhappy. So I recommend subclassing off of here
28             to be consistent. Of course, you may not like these objects, but they do work well and are consistent. Consistency is
29             very important in interface design, IMHO.
30              
31             =cut
32              
33             $VERSION = '3.12';
34              
35 1     1   3443 use Socket;
  1         20896  
  1         3138  
36 1     1   19 no warnings 'portable';
  1         4  
  1         59  
37 1     1   103 use 5.6.0;
  1         5  
  1         58  
38             #use Data::Dumper ();
39              
40             #sub dump {
41             # my $self = shift;
42             # return Data::Dumper::Dumper($self);
43             #};
44              
45 1     1   6 use strict;
  1         2  
  1         43  
46 1     1   5 use warnings;
  1         2  
  1         303  
47              
48             =pod
49              
50             =head1 SET-UP
51              
52             You'll need to specify your conf files. There is the @conf_files array, toss in as many conf files as you'd like
53              
54             my @conf_files = qw(
55             /etc/mail.bulkmail.cfg
56             /etc/mail.bulkmail.cf2
57             );
58              
59             It'll just silently ignore any conf files that aren't present, so don't expect any errors. That's to allow you
60             to place multiple conf files in for use on multiple servers and then not worry about them.
61              
62             Multiple conf files are in significance order. So if mail.bulkmail.cfg and mail.bulkmail.cf2 both define a value
63             for 'foo', then the one in mail.bulkmail.cfg is used. And so on, conf files listed earlier are more important.
64             There is no way for a program to later look at a less significant conf value.
65              
66             =cut
67              
68             #you'll need to specify your conf files
69             {
70             my @conf_files = qw(
71              
72             );
73              
74             =pod
75              
76             =head1 METHODS
77              
78             =over 11
79              
80             =item conf_files
81              
82             conf_files returns your conf_files array.
83              
84             my @conf_files = $class->conf_files();
85              
86             You can also programmatically add a new conf_file this way.
87              
88             $class->conf_files('/path/to/new/conf.file', '/path/to/other/conf.file'); #, etc
89              
90             However, it'd be better to specify your conf file at use time.
91              
92             use Mail::Bulkmail::Object 3.00 "/path/to/conf.file";
93              
94             This also (naturally) works in all subclasses.
95              
96             use Mail::Bulkmail 3.00 "/path/to/conf.file";
97             use Mail::Bulkmail::Dynamic 3.00 "/path/to/conf/file";
98              
99             and so on.
100              
101             Note that adding on via ->conf_files or importing puts onto the FRONT of the @conf_files array,
102             i.e., those conf files are more significant.
103              
104             So,
105              
106             @conf_files = qw(/path/to/file /path/to/file2);
107              
108             use Mail::Bulkmail::Object 3.00 "/path/to/file3" "/path/to/file4";
109              
110             Mail::Bulkmail::Object->conf_files("/path/to/file5", "/path/to/file6");
111              
112             print Mail::Bulkmail::Object->conf_files;
113             #prints out /path/to/file5 /path/to/file6 /path/to/file3 /path/to/file4 /path/to/file path/to/file2
114              
115             Note that you don't *need* conf files, you can still specify all information at construction time, or
116             via mutators, or whatever. But a conf file can make your life a lot easier.
117              
118             =cut
119              
120             sub conf_files {
121 5     5 1 9 my $self = shift;
122 5         20 unshift @conf_files, $_ foreach reverse @_;
123 5         20 return @conf_files;
124             };
125              
126             # the importer looks to any arguments specified at import and puts them
127             # on the FRONT of the conf_files array.
128             sub import {
129 9     9   926 my $class = shift;
130 9         36 unshift @conf_files, $_ foreach reverse @_;
131 9         25006 return 1;
132             };
133              
134             };
135              
136             # You really probably don't want to change this
137             # If the conf file doesn't have a package defined, then it will assume that it's in the package defined here
138             # in this case, Mail::Bulkmail::Object
139             my $default_package = __PACKAGE__;
140              
141             =item add_attr
142              
143             add_attr adds object attributes to the class.
144              
145             Okay, now we're going to get into some philosophy. First of all, let me state that I *love* Perl's OO implementation.
146             I usually get smacked upside the head when I say that, but I find it really easy to use, work with, manipulate, and so
147             on. And there are things that you can do in Perl's OO that you can't in Java or C++ or the like. Perl, for example, can
148             have *totally* private values that are completely inaccessible (lexicals, natch). private vars in the other languages
149             can be redefined or tweaked or subclassed or otherwise gotten around in some form. Not Perl.
150              
151             And I obviously just adore Perl anyway. I get funny looks when I tell people that I like perl so much because it works
152             the way I think. That bothers people for some reason.
153              
154             Anyway, as much as I like how it works, I don't like the fact that there's no consistent object type. An object is,
155             of course, a blessed ((thingie)) (scalar, array, code, hash, etc) reference. And there are merits to using any of those
156             things, depending upon the situation. Hashes are easy to work with and most similar to traditional objects.
157              
158             $object->{$attribute} = $value;
159              
160             And whatnot. Arrays are much faster (typically 33% in tests I've done), but they suck to work with.
161              
162             $object->[15] = $value; #the hell is '15'?
163              
164             (
165             by the way, you can make this easier with variables defined to return the value, i.e.
166             $object->[$attribute] = $value; #assuming $attribute == 15
167             )
168              
169             Scalars are speciality and coderefs are left to the magicians. Don't get me wrong, coderefs as objects are nifty, but
170             they can be tricky to work with.
171              
172             So, I wanted a consistent interface. I'm not going to claim credit for this idea, since I think I originally read it
173             in Object Oriented Programming in Perl (Damien's book). In fact, I think the error reporting method I use was also
174             originally detailed in there. Anyway, I liked it a lot and decided I'd implement my own version of it.
175              
176             Basically, attributes are accessed and mutated via methods.
177              
178             $object->attribute($value);
179              
180             For all attributes. This way, the internal object can be whatever you'd like. I used to use mainly arrays for the speed
181             boost, but lately I use hashes a lot because of the ease of dumping and reading the structure for debugging purposes.
182             But, with this consistent interface of using methods to wrapper the attributes, I can change the implementation of
183             the object (scalar, array, hash, code, whatever) up in this module and *nothing* else needs to change.
184              
185             Say you implemented a giant system in OO perl. And you chose hashrefs as your "object". But then you needed a big
186             speed boost later, which you could easily get by going to arrays. You'd have to go through your code and change all
187             instances of $object->{$attribute} to $object->[15] or whatever. That's an awful lot of work.
188              
189             With everything wrappered up this way, changes can be made in the super object class and then automagically populate
190             out everywhere with no code changes. Spiffy stuff.
191              
192             There are some disadvantages, there is a little more overhead for doing the additional method call, but it's usually
193             negligible. And you can't do nice things like:
194              
195             $object->{$attribute}++;
196             you'd have to do
197             $object->attribute($object->attribute + 1);
198              
199             Which is annoying. But I think it's offset by the consistent interface regardless of what your underlying object is.
200              
201             Enough with the philosophy, though. You need to know how this works.
202              
203             It's easy enough:
204              
205             package Some::Class;
206              
207             Some::Class->add_attr('foo');
208              
209             Now your Some::Class objects have a foo attribute, which can be accessed as above. If called with a value, it's the mutator
210             which sets the attribute to the new value and returns the new value. If called without one, it's the accessor which
211             returns the value.
212              
213             my $obj = Some::Class->new();
214             $obj->foo('bar');
215             print $obj->foo(); #prints bar
216             print $obj->foo('boo'); #prints boo
217             print $obj->foo(); #prints boo
218              
219             add_attr calls should only be in your module. B. And they really should be defined up at the top.
220              
221             Internally, an add_attr call creates a function inside your package of the name of the attribute which reflects through
222             to the internal _accessor method which handles the mutating and accessing.
223              
224             There is another syntax for add_attr, to define a different internal accessor:
225              
226             Some::Class->add_attr(['foo', 'other_accessor']);
227              
228             This creates method called 'foo' which talks to a separate accessor, in this case "other_accessor" instead of going
229             to _accessor. This is useful if you want to create a validating method on your attribute.
230              
231             Additionally, it creates a normal method going to _accessor called '_foo', which is assumed to be the internal attribute
232             slot your other accessor with use. In generall, for a given "attribute", "_attribute" will be created for internal use.
233              
234             "other_accessor" will get the object as the first arg (as always) and the name of the internal method as the second.
235              
236             Example:
237              
238             Some::Class->add_attr(['foo', 'other_accessor']);
239              
240             $obj->foo('bee');
241              
242             sub other_accessor {
243             my $self = shift;
244             my $method = shift; # "_foo", in this example
245              
246             if (@_){
247             my $val = shift; # "bee", in this example
248             if ($val == 7){
249             return $self->$method($val);
250             }
251             else {
252             return $self->error("Cannot store value...foo must be 7!");
253             };
254             }
255             else {
256             return $self->$method();
257             };
258             };
259              
260             And, finally, you can also pass in additional arguments as static args if desired.
261              
262             Some::Class->add_attr(['foo', 'other_accessor'], 'bar');
263              
264             $obj->foo('bee');
265              
266             sub other_accessor {
267             my $self = shift;
268             my $method = shift;
269             my $static = shift; #'bar' in our example
270              
271             my $value = shift; #'bee' in our example
272             .
273             .
274             .
275             };
276              
277             All easy enough. Refer to any subclasses of this class for further examples.
278              
279             =cut
280              
281             sub add_attr {
282 76     76 1 189 my $pkg = shift;
283 76         100 my $method = shift;
284              
285 76         92 my $accessor = "_accessor";
286              
287 76         104 my @static_args = @_;
288              
289 76 100       141 if (ref $method){
290 8         18 ($method, $accessor) = @$method;
291 1     1   6 no strict 'refs';
  1         3  
  1         49  
292 8         19 my $internal_method = '_' . $method;
293 8         26 $pkg->add_attr($internal_method);
294 1     1   5 no strict 'refs';
  1         2  
  1         77  
295 8     46   31 *{$pkg . "::$method"} = sub {shift->$accessor($internal_method, @static_args, @_)};
  8         38  
  46         167  
296             }
297             else {
298 1     1   4 no strict 'refs';
  1         2  
  1         114  
299 68     427   250 *{$pkg . "::$method"} = sub {shift->$accessor($method, @static_args, @_)};
  68         385  
  427         1112  
300             };
301              
302 76         178 return $method;
303             };
304              
305             =pod
306              
307             =item add_class_attr
308              
309             This is similar to add_attr, but instead of adding object attributes, it adds class attributes. You B have
310             object and class attributes with the same name. This is by design. (error is a special case)
311              
312             Some::Class->add_attr('foo'); #object attribute foo
313             Some::Class->add_class_attr('bar'): #class attribute bar
314              
315             print $obj->foo();
316             print Some::Class->bar();
317              
318             Behaves the same as an object method added with add_attr, mutating with a value, accessing without one. Note
319             that add_class_attr does not have the capability for additional internal methods or static values. If you want
320             those on a class method, you'll have to wrapper the class attribute yourself on a per case basis.
321              
322             Note that you can access class attributes via an object (as expected), but it's frowned upon since it may be
323             confusing.
324              
325             class attributes are automatically initialized to any values in the conf file upon adding, if present.
326              
327             =cut
328              
329             sub add_class_attr {
330 2     2 1 5 my $pkg = shift;
331 2         4 my $method = shift;
332              
333 2         4 my $f = q{
334             {
335             my $attr = undef;
336             sub {
337             my $pkg = shift;
338             $attr = shift if @_;
339             return $attr;
340             }
341             }
342             };
343              
344 1     1   5 no strict 'refs';
  1         1  
  1         191  
345 2 50   1   248 *{$pkg . "::$method"} = eval $f;
  2 50       355  
  1         2  
  1         6  
  1         4  
  32         48  
  32         67  
  32         162  
346              
347             #see if there's anything in the conf file
348              
349 2   50     15 my $conf = $pkg->read_conf_file
350             || die "Conf file error : " . $pkg->error . " " . $pkg->errcode;
351 2 50       11 if ($conf->{$pkg}->{$method}){
352 0         0 $pkg->$method($conf->{$pkg}->{$method});
353             };
354              
355 2 50       5 if (@_){
356 0         0 $pkg->$method(@_);
357             };
358              
359 2         6 return $method;
360             };
361              
362             =pod
363              
364             =item add_tricke_class_attr
365              
366             It's things like this why I really love Perl.
367              
368             add_trickle_class_attr behaves the same as add_class_attr with the addition that it will trickle the attribute down
369             into any class as it is called. This is useful for subclasses.
370              
371             Watch:
372              
373             package SuperClass;
374              
375             SuperClass->add_class_attr('foo');
376             SuperClass->foo('bar');
377              
378             package SubClass;
379             @ISA = qw(SuperClass);
380              
381             print SubClass->foo(); #prints bar
382             print SuperClass->foo(); #prints bar
383              
384             print SuperClass->foo('baz'); #prints baz
385             print SubClass->foo(); #prints baz
386              
387             print SubClass->foo('dee'); #prints dee
388             print SuperClass->foo(); #prints dee
389              
390             See? The attribute is still stored in the super class, so changing it in a subclass changes it in the super class as well.
391             Usually, this behavior is fine, but sometimes you don't want that to happen. That's where add_trickle_class_attr comes
392             in. Its first call will snag the value from the SuperClass, but then it will have its own attribute that's separate.
393              
394             Again, watch:
395              
396              
397             package SuperClass;
398              
399             SuperClass->add_trickle_class_attr('foo');
400             SuperClass->foo('bar');
401              
402             package SubClass;
403             @ISA = qw(SuperClass);
404              
405             print SubClass->foo(); #prints bar
406             print SuperClass->foo(); #prints bar
407              
408             print SuperClass->foo('baz'); #prints baz
409             print SubClass->foo(); #prints bar
410              
411             print SubClass->foo('dee'); #prints dee
412             print SuperClass->foo(); #prints baz
413              
414             This is useful if you have an attribute that should be unique to a class and all subclasses. These are equivalent:
415              
416             package SuperClass;
417             SuperClass->add_class_attr('foo');
418              
419             package SubClass
420             SubClass->add_class_attr('foo');
421              
422             and
423              
424             package SuperClass;
425             SuperClass->add_trickle_class_attr('foo');
426              
427             You'll usually just use add_class_attr. Only use trickle_class_attr if you know you need to, since you rarely would.
428             There is a *slight* bit of additional processing required for trickled accessors.
429              
430             trickled class attributes are automatically initialized to any values in the conf file upon adding, if present.
431              
432             =cut
433              
434             sub add_trickle_class_attr {
435 2     2 0 3 my $pkg = shift;
436 2         4 my $method = shift;
437              
438 2         7 my $f = qq{
439             {
440             my \$attr = undef;
441             my \$internalpkg = "$pkg";
442             my \$method = "$method";
443             sub {
444             my \$pkg = shift;
445             \$pkg = ref \$pkg ? ref \$pkg : \$pkg; #use as a class or regular method
446             if (\@_ && \$pkg ne \$internalpkg){
447             my \$func = \$method;
448             \$pkg->add_trickle_class_attr(\$func);
449             \$pkg->\$func(\$internalpkg->\$func); #inherit the superclass class value
450             return \$pkg->\$func(\@_);
451             }
452             else {
453             \$attr = shift if \@_;
454             return \$attr;
455             }
456             }
457              
458             }
459             };
460              
461 1     1   7 no strict 'refs';
  1         1  
  1         4923  
462 2 0 0 0   1643 *{$pkg . "::$method"} = eval $f;
  2 0 0     16  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
463              
464             #if it's an internal attribute, then don't look in the conf file
465 2 50       16 unless ($method =~ /^_/){
466             #see if there's anything in the conf file
467 0   0     0 my $conf = $pkg->read_conf_file
468             || die "Conf file error : " . $pkg->error . " " . $pkg->errcode;
469 0 0       0 if ($conf->{$pkg}->{$method}){
470 0         0 $pkg->$method($conf->{$pkg}->{$method});
471             };
472              
473 0 0       0 if (@_){
474 0         0 $pkg->$method(@_);
475             };
476             };
477              
478 2         5 return $method;
479             };
480              
481             # _accessor is the main accessor method used in the system. It defines the most simple behavior as to how objects are supposed
482             # to work. If it's called with no arguments, it returns the value of that attribute. If it's called with arguments,
483             # it sets the object attribute value to the FIRST argument passed and ignores the rest
484             #
485             # example:
486             # my $object;
487             # print $object->attribute7(); #prints out the value of attribute7
488             # print $object->attribute7('foo'); #sets the value of attribute7 to 'foo', and prints 'foo'
489             # print $object->attribute7(); #prints out the value of attribute7, which is now known to be foo
490             #
491             # All internal accessor methods should behave similarly, read the documentation for add_attr for more information
492             #
493             # accessor is known to return errorcode MBO001 - not a class attribute, if it is accessed by a class
494              
495             sub _accessor {
496 427     427   460 my $self = shift;
497 427         545 my $prop = shift;
498              
499 427 50       908 return $self->error("Not a class attribute", "MBO001") unless ref $self;
500              
501 427 100       950 $self->{$prop} = shift if @_;
502              
503 427         15565 return $self->{$prop};
504             };
505              
506             =pod
507              
508             =item error and errcode
509              
510             error rocks. All error reporting is set and relayed through error. It's a standard accessor, and an *almost*
511             standard mutator. The difference is that when used as a mutator, it returns undef (or an empty list) instead
512             of the value mutated to.
513              
514             If a method fails, it is expected to return undef (or an empty list) and set error.
515              
516             example:
517              
518             sub someMethod {
519             my $self = shift;
520             my $value = shift;
521              
522             if ($value > 10){
523             return 1; #success
524             }
525             else {
526             return $self->error("Values must be greater than 10");
527             };
528             };
529              
530             $object->someMethod(15) || die $object->error; #succeeds
531             $object->someMethod(5) || die $object->error; #dies with an error..."Values must be greater than 10"
532              
533             Be warned if your method can return '0', this is a valid successful return and shouldn't give an error.
534             But most of the time, you're fine with "true is success, false is failure"
535              
536             As you can see in the example, we mutate the error attribute to the value passed, but it returns undef.
537              
538             However, error messages can change and can be difficult to parse. So we also have an error code, accessed
539             by errcode. This is expected to be consistent and machine parseable. It is mutated by the second argument
540             to ->error
541              
542             example:
543              
544             sub someMethod {
545             my $self = shift;
546             my $value = shift;
547              
548             if ($value > 10){
549             return 1; #success
550             }
551             else {
552             return $self->error("Values must be greater than 10", "ERR77");
553             };
554             };
555              
556             $object->someMethod(15) || die $object->error; #succeeds
557             $object->someMethod(5) || die $object->errcode; #dies with an error code ... "ERR77"
558              
559             If your code is looking for an error, read the errcode. if a human is looking at it, display the error.
560             Easy as pie.
561              
562             Both classes and objects have error methods.
563              
564             my $obj = Some::Class->new() || die Some::Class->error();
565             $obj->foo() || die $obj->error();
566              
567             Note that error is a special method, and not just a normal accessor or class attribute. As such:
568              
569             my $obj = Some::Class->new();
570             Some::Class->error('foo');
571             print $obj->error(); #prints undef
572             print Some::Class->error(); #prints foo
573              
574             i.e., you will B get a class error message by calling ->error on an object.
575              
576             There is also an optional third paramenter..."not logged", which sounds horribly ugly, I know. But it is a bit of an
577             after-market hack, so it's to be expected. The third argument does what you'd think, it prevents the error message from
578             being logged.
579              
580             $self->error("This is an error message", "code", "not logged");
581              
582             Any true value may be passed for the 3rd argument, but something that makes it obvious what it's doing is recommended, hence
583             my use of 'not logged'. This is useful for bubbling up errors.
584              
585             $class->error($self->error, $self->errcode, 'not logged');
586              
587             The reason is that the error was already logged when it was stored in $self. So you'd end up logging it twice in your error
588             file, which is very confusing. So it's recommended to use the three argument form for errors that are bubbling up, but not
589             elsewhere.
590              
591             As of 3.06, if an error is returned in a list context, an empty list will be returned instead of undef. undef is still
592             returned in a scalar context.
593              
594             =cut
595              
596             sub error {
597 32     32 1 143 my $self = shift;
598              
599 32 50       72 my $errormethod = ref $self ? "_obj_error" : "_pkg_error";
600 32 50       54 my $codemethod = ref $self ? "_obj_errcode" : "_pkg_errcode";
601              
602 32 50       57 if (@_){
603 32         35 my $error = shift;
604 32         34 my $code = shift;
605 32   50     103 my $nolog = shift || 0;
606 32         93 $self->$errormethod($error);
607 32 100       102 $self->$codemethod(defined $code ? $code : undef);
608 32 0 33     121 $self->logToFile($self->ERRFILE, "error: $error" . (defined $code ? "\tcode : $code" : '')) if !$nolog && $self->ERRFILE && $error;
    50 33        
609              
610 32         100 return;
611             }
612             else {
613 0         0 return $self->$errormethod();
614             };
615             };
616              
617             =pod
618              
619             =item errcode
620              
621             errcode is an accessor ONLY. You can only mutate the errcode via error, see above.
622              
623             print $obj->errcode;
624              
625             Both objects and classes have errcode methods.
626              
627             my $obj = Some::Class->new() || die Some::Class->errcode();
628             $obj->foo() || die $obj->errcode();
629              
630             Where possible, the pod will note errors that a method is known to be able to return. Please
631             note that this will B be an all inclusive list of all error codes that may possibly
632             ever be returned by this method. Only error codes generated by a particular method will be listed.
633              
634             =cut
635              
636             sub errcode {
637 31     31 1 40 my $self = shift;
638 31 50       73 my $method = ref $self ? "_obj_errcode" : "_pkg_errcode";
639 31         67 return $self->$method(@_);
640             };
641              
642             =pod
643              
644             =item errstring
645              
646             errstring is just a quick alias for:
647              
648             $bulk->error . ": " . $bulk->errcode;
649              
650             Nothing more.
651              
652             =cut
653              
654             sub errstring {
655 0     0 1 0 my $self = shift;
656              
657             return
658 0 0       0 (defined $self->error ? $self->error : '')
    0          
659             . "...with code (" .
660             (defined $self->errcode ? $self->errcode : '')
661             . ")";
662              
663             };
664              
665             =pod
666              
667             =item errvals
668              
669             similar to errstring, but returns the error and errcode in an array. This is great for bubbling
670             up error messages.
671              
672             $attribute = $obj->foo() || return $self->error($obj->errvals);
673              
674             =cut
675              
676             sub errvals {
677 0     0 1 0 my $self = shift;
678              
679 0         0 my @return = ();
680              
681 0 0       0 if (defined $self->error) {
    0          
682 0         0 push @return, $self->error;
683             }
684             elsif (defined $self->errcode) {
685 0         0 push @return, undef;
686             };
687              
688 0 0       0 if (defined $self->errcode) {
689 0         0 push @return, $self->errcode;
690             };
691              
692 0         0 return @return;
693             };
694              
695              
696             =pod
697              
698             =item read_conf_file
699              
700             read_conf_file will read in the conf files specified in the @conf_files array up at the top.
701              
702             You can also pass in a list of conf files to read, in most to least significant order, same as the @conf_files array.
703              
704             my $conf = Mail::Bulkmail::Object->read_conf_file();
705             or
706             my $conf = Mail::Bulkmail::Object->read_conf_file('/other/conf.file');
707              
708             If you pass in a list of conf files, then the internal @conf_files array is bypassed.
709              
710             $conf is a hashref of hashrefs. the main keys are the package names, the values are the hashes of the values
711             for that object.
712              
713             Example:
714              
715             #conf file
716             define package Mail::Bulkmail
717              
718             use_envelope = 1
719             Trusting @= duplicates
720              
721             define package Mail::Bulkmail::Server
722              
723             Smtp = your.smtp.com
724             Port = 25
725              
726             $conf = {
727             'Mail::Bulkmail' => {
728             'use_envelope' => 1,
729             'Trusting' => ['duplicates']
730             },
731             'Mail::Bulkmail::Server' => {
732             'Smtp' => 'your.smtp.com',
733             'Port' => 25
734             }
735             };
736              
737             read_conf_file is called at object initialization. Any defaults for your object are read in at this time.
738             You'll rarely need to read the conf file yourself, since at object creation it is read and parsed and the values passed
739             on.
740              
741             B
742              
743             The conf file is only re-read if it has been modified since the last time it was read.
744              
745             this method is known to be able to return MBO002 - Invalid conf file
746              
747             =cut
748              
749             {
750             my $global_conf = {};
751             my $loaded = {};
752             sub read_conf_file {
753 5     5 1 14 my $class = shift;
754              
755 5 50       40 my @confs = reverse(@_ ? @_ : $class->conf_files());
756 5 50       18 my $conf = @_ ? {} : $global_conf;
757              
758 5         14 foreach my $conf_file (@confs){
759 0 0       0 next unless -e $conf_file ;
760 0 0 0     0 if (! $loaded->{$conf_file} || -M $conf_file <= 0){
761 0         0 my $pkg = $default_package;
762              
763 0 0       0 open (CONF, $conf_file) || next;
764 0         0 while (my $line = ) {
765 0 0 0     0 next if ! defined $line || $line =~ /^\s*#/ || $line =~ /^\s*$/;
      0        
766 0 0       0 if ($line =~ /define package\s+(\S+)/){
767 0         0 $pkg = $1;
768 0         0 next;
769             };
770              
771 0         0 $line =~ s/(?:^\s+|\s+$)//g;
772 0 0       0 $line =~ /^(?:\s*(\d+)\s*:)?\s*(\w+)\s*(@?)=\s*(.+)/
773             || return $class->error("Invalid conf file : $line", "MBO002");
774              
775 0         0 my ($user, $key, $array, $val) = ($1, $2, $3, $4);
776              
777 0 0       0 unless (defined $val){
778 0         0 ($user, $key, $array, $val) = ($user, $key, undef, $array);
779             };
780              
781 0 0       0 unless (defined $array){
782 0         0 ($user, $key, $array, $val) = (undef, $user, $array, $key);
783             };
784              
785 0 0       0 ($user, $key, $val) = (undef, $user, $key) unless defined $val;
786              
787 0 0 0     0 next if defined $user && $user != $>;
788              
789 0 0       0 $val = undef if $val eq 'undef';
790              
791 0 0 0     0 $val = eval qq{return "$val"} if defined $val && $val =~ /^\\/;
792              
793 0 0       0 if ($array) {
794 0   0     0 $conf->{$pkg}->{$key} ||= [];
795 0         0 push @{$conf->{$pkg}->{$key}}, $val;
  0         0  
796             }
797             else {
798 0         0 $conf->{$pkg}->{$key} = $val;
799             };
800             }; #end while
801 0 0       0 $loaded->{$conf_file} = 1 unless @_;
802             }; #end if
803             }; #end foreach
804 5         21 return $conf;
805              
806             }; #end sub
807             };
808              
809             =pod
810              
811             =item gen_handle
812              
813             returns a filehandle in a different package. Useful for when you need to open filehandles and pass 'em around.
814              
815             my $handle = Mail::Bulkmail->gen_handle();
816             open ($handle, "/path/to/my/list");
817              
818             my $bulk = Mail::Bulkmail->new(
819             'LIST' => $handle
820             );
821              
822             You never need to use gen_handle if you don't want to. It's used extensively internally, though.
823              
824             =cut
825              
826             {
827             my $handle = 0;
828              
829             sub gen_handle {
830 1     1   18 no strict 'refs';
  1         4  
  1         1648  
831 2     2 1 3 my $self = shift;
832 2         5 return \*{"Mail::BulkMail::Handle::HANDLE" . $handle++}; #You'll note that I don't want my
  2         20  
833             #namespace polluted either
834             };
835              
836             };
837              
838             =pod
839              
840             =item new
841              
842             Finally! The B. It's very easy, for a minimalist object, do this:
843              
844             my $obj = Class->new() || die Class->error();
845              
846             Ta da! You have an object. Any attributes specified in the conf file will be loaded into your object. So if your
847             conf file defines 'foo' as 'bar', then $obj->foo will now equal 'bar'.
848              
849             If you'd like, you can also pass in method/value pairs to the constructor.
850              
851             my $obj = Class->new(
852             'attribute' => '17',
853             'foo' => 'baz',
854             'method' => '88'
855             ) || die Class->error();
856              
857             This is (roughly) the same as:
858              
859             my $obj = Class->new() || die Class->error();
860              
861             $obj->attribute(17) || die $obj->error();
862             $obj->foo('baz') || die $obj->error();
863             $obj->method(88) || die $obj->error();
864              
865             Any accessors or methods you'd like may be passed to the constructor. Any unknown pairs will be silently ignored.
866             If you pass a method/value pair to the constructor, it will override any equivalent method/value pair in the
867             conf file.
868              
869             Additionally, if you need to set up values in your object, this is the place to do it. Note that setting default
870             values should probably be done in the conf file, but if you need to populate a data structure into a method, do it here.
871              
872             package SubClass;
873             @ISA = qw(SuperClass);
874              
875             sub new {
876             return shift->new(
877             'servers' => [],
878             'connections' => {},
879             @_
880             );
881             };
882              
883             This will cause your SubClass to use the normal constructor, but get default values of the empty data structures
884             specified.
885              
886             =cut
887              
888             sub new {
889 3     3 1 8 my $class = shift;
890 3         11 my $self = bless {}, $class;
891              
892 3   33     22 return $self->init(
893             @_
894             ) || $class->error($self->error, $self->errcode, 'not logged');
895             };
896              
897             =pod
898              
899             =item init
900              
901             The object initializer. Arguably more important than the constructor, but not something you need to worry about.
902             The constructor calls it internally, and you really shouldn't touch it or override it. But I wanted it here so
903             you know what it does.
904              
905             Simply, it iterates through the conf file and mutates any of your object attributes to the value specified in the conf
906             file. It then iterates through the hash you passed to ->new() and does the same thing, overriding any conf values, if
907             necessary.
908              
909             init is smart enough to use all super class values defined in the conf file, in hierarchy order. So if your conf file
910             contains:
911              
912             define package SuperClass
913              
914             foo = 'bar'
915              
916             And you're creating a new SubClass object, then it will get the default of foo = 'bar' as in the conf file, despite
917             the fact that it was not defined for your own package. Naturally, the more significant definition is used.
918              
919             define package SuperClass
920              
921             foo = 'bar'
922              
923             define package SubClass
924              
925             foo = 'baz'
926              
927             SuperClass objects will default foo to 'bar', SubClass objects will default foo to 'baz'
928              
929             this method is known to be able to return
930              
931             MBO003 - could not initialize value to conf value
932             MBO004 - could not initialize value to constructor value
933             MBO006 - odd number of elements in hash assignment
934              
935             =cut
936              
937             sub init {
938 3     3 1 6 my $self = shift;
939 3         13 my $class = ref $self;
940              
941             # my %init = @_;
942              
943 3   50     18 my $conf = $self->read_conf_file
944             || die "Conf file error : " . $self->error . " " . $self->errcode;
945              
946             #initialize our defaults from the conf file
947 3 50       5 foreach my $pkg (@{$class->isa_path() || []}){
  3         19  
948 8         11 foreach my $method (keys %{$conf->{$pkg}}){
  8         37  
949 0 0       0 if ($self->can($method)){
950 0         0 $self->error(undef);
951 0         0 $self->errcode(undef);
952 0 0       0 my $return = $self->$method($conf->{$pkg}->{$method}) if $self->can($method);
953 0 0       0 my $value = defined $conf->{$pkg}->{$method} ? $conf->{$pkg}->{$method} : 'value is undef';
954 0 0 0     0 return $self->error("Could not initilize method ($method) to value ($value)"
    0          
955             . (defined $self->error ? " : " . $self->error : '')
956             , ($self->errcode || "MBO003")
957             ) unless defined $return;
958             };
959             };
960             };
961              
962             #initialize our defaults as passed in to the constructor
963             # foreach my $method (keys %init){
964              
965 3         10 while (@_) {
966 31         48 my $method = shift;
967 31         31 my $value = undef;
968              
969 31 50       55 if (@_){
970 31         43 $value = shift;
971             }
972             else {
973 0         0 return $self->error("Odd number of elements in hash assignment", "MBO006");
974             };
975              
976 31 50       183 if ($self->can($method)){
977 31         2075 $self->error(undef);
978 31         103 $self->errcode(undef);
979             #my $return = $self->$method($init{$method});
980 31         96 my $return = $self->$method($value);
981             #my $value = defined $init{$method} ? $init{$method} : 'value is undef';
982 31 50       1183 my $errval = defined $value ? $value : 'value is undef';
983 31 0 0     111 return $self->error("Could not initilize method ($method) to value ($errval)"
    50          
984             . (defined $self->error ? " : " . $self->error : '')
985             , ($self->errcode || "MBO004")
986             ) unless defined $return;
987             };
988             };
989              
990 3         26 return $self;
991             };
992              
993             =pod
994              
995             =item isa_path
996              
997             This is mainly used by the conf reader, but I wanted to make it publicly accessible. Given a class, it
998             will return an arrayref containing all of the superclasses of that class, in inheritence order.
999              
1000             Note that once a path is looked up for a class, it is cached. So if you dynamically change @ISA, it won't be reflected in the return of isa_path.
1001             Obviously, dynamically changing @ISA is frowned upon as a result.
1002              
1003             =cut
1004              
1005             {
1006             my $paths = {};
1007              
1008             sub isa_path {
1009 6     6 1 12 my $class = shift;
1010 6   100     38 my $seen = shift || {};
1011              
1012 6 50       29 return undef if $seen->{$class}++;
1013              
1014 6 100       24 return $paths->{$class} if $paths->{$class};
1015              
1016 1     1   10 no strict 'refs';
  1         3  
  1         2199  
1017 4         6 my @i = @{$class . "::ISA"};
  4         27  
1018              
1019 4         10 my @s = ($class);
1020 4         6 foreach my $super (@i){
1021 3 50       10 next if $seen->{$super};
1022             #my $super_isa = $super->can('isa_path') ? $super->isa_path($seen) : [];
1023 3         9 my $super_isa = isa_path($super, $seen);
1024 3         13 push @s, @$super_isa;
1025             };
1026              
1027 4         7 @s = reverse @s; #we want to look at least significant first
1028              
1029 4         10 $paths->{$class} = \@s;
1030              
1031 4         15 return \@s;
1032              
1033             };
1034              
1035             };
1036              
1037             # _file_accessor is an internal accessor for accessing external information. Said external information can be in
1038             # the form of a file (either a globref or a string containing the path/to/the/file), an arrayref, or a coderef
1039             # It will open up path/to/file strings and create an internal filehandle. it also makes sure that all filehandles
1040             # are piping hot. Look at getNextLine and logToFile to see examples of how to deal with a value that is
1041             # set via _file_accessor
1042             #
1043             # _file_accessor expects a token to tell it which way the IO goes, either "<", ">", or ">>"
1044             #
1045             # i.e., __PACKAGE__->add_attr(["LIST", '_file_accessor'], "<");
1046             # i.e., __PACKAGE__->add_attr(["GOOD", '_file_accessor'], ">>");
1047              
1048             sub _file_accessor {
1049 36     36   47 my $self = shift;
1050 36         45 my $prop = shift;
1051 36         41 my $IO = shift;
1052 36         39 my $file = shift;
1053              
1054 36 100       74 if (defined $file){
1055 3 50       22 if (! ref $file) {
    50          
1056 0         0 my $handle = $self->gen_handle();
1057 0 0       0 if ($IO =~ /^(?:>>?|<)$/){
1058 0 0       0 open ($handle, $IO . $file)
1059             || return $self->error("Could not open file $file : $!", "MB702");
1060 0         0 select((select($handle), $| = 1)[0]); #Make sure the file is piping hot!
1061 0         0 return $self->$prop($handle);
1062             }
1063             else {
1064 0         0 return $self->error("Invalid IO : $IO, must be '>', '>>', '<'", "MB703");
1065             };
1066             }
1067             elsif (ref ($file) =~ /^(?:GLOB|ARRAY|CODE)$/){
1068 3 50       13 select((select($file), $| = 1)[0]) if ref $file eq "GLOB"; #Make sure the file is piping hot!
1069 3         11 return $self->$prop($file);
1070             }
1071             else {
1072 0         0 return $self->error("File error. I don't know what a $file is", "MB701");
1073             };
1074             }
1075             else {
1076 33         83 return $self->$prop();
1077             };
1078              
1079             };
1080              
1081             =pod
1082              
1083             =item getNextLine
1084              
1085             getNextLine is called on either a filehandleref, an arrayref, or a coderef
1086              
1087             $obj->getNextLine(\*FOO);
1088              
1089             will return the next line off of FOO;
1090              
1091             $obj->getNextLine(\@foo);
1092              
1093             will shift the next line off of @foo and return it.
1094              
1095             $obj->getNextLine(\&foo);
1096              
1097             will call foo($obj) and return whatever the function returns.
1098              
1099             Note that your bulkmail object is the first argument passed to your function. It's not called as a method, but
1100             the object is still the first argument passed.
1101              
1102             This is mainly used with attribues going through _file_accessor.
1103              
1104             package SomeClass;
1105              
1106             SomeClass->add_attr(['FOO', '_file_accessor'], "<");
1107             my $obj = SomeClass->new(
1108             FOO => \&foo
1109             ) || die SomeClass->error();
1110              
1111             my $val = $obj->getNextLine($obj->FOO);
1112              
1113             =cut
1114              
1115             sub getNextLine {
1116 4     4 1 8 my $self = shift;
1117              
1118 4   50     21 my $list = shift || $self->LIST() || return $self->error("Cannot get next line w/o list", "MB045");
1119              
1120 4 50       20 if (ref $list eq "GLOB"){
    50          
    0          
1121 0         0 my $email = scalar <$list>;
1122 0 0       0 return undef unless defined $email;
1123 0         0 chomp $email;
1124 0         0 return $email;
1125             }
1126             elsif (ref $list eq "ARRAY"){
1127 4         26 return shift @$list;
1128             }
1129             elsif (ref $list eq "CODE"){
1130 0         0 return $list->($self);
1131             }
1132             else {
1133 0         0 return $self->error("Cannot get next line...don't know what a $list is", "MB046");
1134             };
1135              
1136             };
1137              
1138             =pod
1139              
1140             =item logToFile
1141              
1142             logToFile is the opposite of getNextLine, it writes out a value instead of reading it.
1143              
1144             logToFile is called on either a filehandleref, an arrayref, or a coderef
1145              
1146             $obj->logToFile(\*FOO, "bar");
1147              
1148             will append a new line to FOO, "bar"
1149              
1150             $obj->logToFile(\@foo, "bar");
1151              
1152             will push the value "bar" onto the end of @foo
1153              
1154             $obj->logToFile(\&foo, "bar");
1155              
1156             will call foo($obj, "bar")
1157              
1158             Note that your bulkmail object is the first argument passed to your function. It's not called as a method, but
1159             the object is still the first argument passed.
1160              
1161             This is mainly used with attribues going through _file_accessor.
1162              
1163             package SomeClass;
1164              
1165             SomeClass->add_attr(['FOO', '_file_accessor'], ">>");
1166             my $obj = SomeClass->new(
1167             FOO => \&foo
1168             ) || die SomeClass->error();
1169              
1170             my $val = $obj->logToFile($obj->FOO, "valid address);
1171              
1172             Internally, logToFile calls convert_to_scalar on the value it is called with.
1173              
1174             This method is known to be able to return:
1175              
1176             MBO005 - cannot log to file
1177              
1178             =cut
1179              
1180             sub logToFile {
1181 3     3 1 6 my $self = shift;
1182 3   50     10 my $file = shift || return $self->error("Cannot log to file w/o file", "MB047");
1183              
1184 3         5 my $value = shift;
1185              
1186 3         14 $value = $self->convert_to_scalar($value);
1187              
1188 3 50       20 if (ref $file eq "GLOB"){
    50          
    50          
1189 0 0       0 print $file $value, "\015\012" if $value;
1190 0         0 return 1;
1191             }
1192             elsif (ref $file eq 'ARRAY'){
1193 0         0 push @$file, $value;
1194 0         0 return 1;
1195             }
1196             elsif (ref $file eq "CODE"){
1197 3         19 $file->($self, $value);
1198 3         207 return 1;
1199             }
1200             else {
1201 0         0 return $self->error("Cannot log to file...don't know what a $file is", "MBO005");
1202             };
1203              
1204             };
1205              
1206             =pod
1207              
1208             =item convert_to_scalar
1209              
1210             called by logToFile. used to convert the value passed to a scalar.
1211              
1212             Mail::Bulkmail::Object's convert_to_scalar method will only handle scalars, it will dereference
1213             scalarrefs, or return scalar values. This method will also strip out any carriage returns or newlines
1214             within the scalar before returning it. If passed by reference, your original variable will not be modified.
1215              
1216             This is useful to subclass if you ever want to log values other than simple scalars
1217              
1218             =cut
1219              
1220             sub convert_to_scalar {
1221 3     3 1 6 my $self = shift;
1222 3         4 my $value = shift;
1223              
1224 3 50       11 my $v2 = ref $value ? $$value : $value;
1225              
1226 3 50       13 $v2 =~ s/[\015\012]//g if defined $v2;
1227              
1228 3         7 return $v2;
1229             };
1230              
1231             #internal attributes, for storing error information
1232              
1233             # _obj_error is the object attribute slot for storing the most recent error that occurred. It is
1234             # set via the first argument to the ->error method when called with an object.
1235             # i.e., $obj->error('foo', 'bar'); #_obj_error is 'foo'
1236             __PACKAGE__->add_attr('_obj_error');
1237              
1238             # _obj_errcode is the object attribute slot for storing the most recent error code that occurred. It is
1239             # set via the second argument to the ->error method when called with an object.
1240             # i.e., $obj->error('foo', 'bar'); #_obj_errcode is 'bar'
1241             __PACKAGE__->add_attr('_obj_errcode');
1242              
1243             # _pkg_error is the class attribute slot for storing the most recent error that occurred. It is
1244             # set via the first argument to the ->error method when called with a class.
1245             # i.e., $class->error('foo', 'bar'); #_pkg_error is 'foo'
1246             __PACKAGE__->add_trickle_class_attr('_pkg_error');
1247              
1248             # _pkg_errcode is the class attribute slot for storing the most recent error code that occurred. It is
1249             # set via the second argument to the ->error method when called with a class.
1250             # i.e., $class->error('foo', 'bar'); #_pkg_errcode is 'bar'
1251             __PACKAGE__->add_trickle_class_attr('_pkg_errcode');
1252              
1253             #and for logging errors, if desired
1254              
1255             # _ERRFILE internally stores the ERRFILE parameter, if it is set. See the documentation for ERRFILE, below.
1256             # _ERRFILE needs to exist because add_class_attr and add_trickle_class_attr do not have add_attr's additional
1257             # powers to create attributes with non-standard accessors.
1258             __PACKAGE__->add_class_attr('_ERRFILE');
1259              
1260             =pod
1261              
1262             =item ERRFILE
1263              
1264             This is an optional log file to keep track of any errors that occur.
1265              
1266             ERRFILE may be either a coderef, globref, arrayref, or string literal.
1267              
1268             If a string literal, then Mail::Bulkmail::Object will attempt to open that file (in append mode) as your log:
1269              
1270             $bulk->ERRFILE("/path/to/my/error.file");
1271              
1272             If a globref, it is assumed to be an open filehandle in append mode:
1273              
1274             open (E, ">>/path/to/my/error.file");
1275             $bulk->ERRFILE(\*E);
1276              
1277             if a coderef, it is assumed to be a function to call with the address as an argument:
1278              
1279             sub E { print "ERROR : ", shift, "\n"}; #or whatever your code is
1280             $bulk->ERRFILE(\&E);
1281              
1282             if an arrayref, then bad addresses will be pushed on to the end of it
1283              
1284             $bulk->ERRFILE(\@errors);
1285              
1286             Use whichever item is most convenient, and Mail::Bulkmail::Object will take it from there.
1287              
1288             It is recommended you turn on ERRFILE in a debugging envrionment, and leave it off in production. You probably shouldn't
1289             be getting errors in a production environment, but there may be internal errors that you're not even aware of, so
1290             you'll end up filling up that file. And there's the slight additional overhead.
1291              
1292             Keep it on in production if you know what you're doing, off otherwise.
1293              
1294             =cut
1295              
1296             sub ERRFILE {
1297 32     32 1 39 my $self = shift;
1298 32 50       61 if (@_){
1299 0         0 my $file = shift;
1300 0         0 $self->_file_accessor("_ERRFILE", ">>", $file);
1301             }
1302             else {
1303 32         1056 return $self->_ERRFILE();
1304             };
1305             };
1306              
1307             1;
1308              
1309             __END__