73a0f4ef3aa77e82b786a583058ce4fa2d8c397d
[enigma2.git] / lib / service / iservice.h
1 #ifndef __lib_dvb_iservice_h
2 #define __lib_dvb_iservice_h
3
4 #include <lib/python/swig.h>
5 #include <lib/python/python.h>
6 #include <lib/base/object.h>
7 #include <string>
8 #include <connection.h>
9 #include <list>
10
11 class eServiceEvent;
12
13 class eServiceReference
14 {
15 public:
16         enum
17         {
18                 idInvalid=-1,
19                 idStructure,    // service_id == 0 is root
20                 idDVB,
21                 idFile,
22                 idUser=0x1000
23         };
24         int type;
25
26         enum
27         {
28                 isDirectory=1,          // SHOULD enter  (implies mustDescent)
29                 mustDescent=2,          // cannot be played directly - often used with "isDirectory" (implies canDescent)
30                 /*
31                         for example:
32                                 normal services have none of them - they can be fed directly into the "play"-handler.
33                                 normal directories have both of them set - you cannot play a directory directly and the UI should descent into it.
34                                 playlists have "mustDescent", but not "isDirectory" - you don't want the user to browse inside the playlist (unless he really wants)
35                                 services with sub-services have none of them, instead the have the "canDecsent" flag (as all of the above)
36                 */
37                 canDescent=4,                   // supports enterDirectory/leaveDirectory
38                 flagDirectory=isDirectory|mustDescent|canDescent,
39                 shouldSort=8,                   // should be ASCII-sorted according to service_name. great for directories.
40                 hasSortKey=16,          // has a sort key in data[3]. not having a sort key implies 0.
41                 sort1=32,                                       // sort key is 1 instead of 0
42                 isMarker=64                     // Marker
43         };
44         int flags; // flags will NOT be compared.
45
46         inline int getSortKey() const { return (flags & hasSortKey) ? data[3] : ((flags & sort1) ? 1 : 0); }
47
48 #ifndef SWIG
49         int data[8];
50         std::string path;
51 #endif
52         std::string getPath() { return path; }
53         void setPath( const std::string &n ) { path=n; }
54
55         unsigned int getUnsignedData(unsigned int num) const
56         {
57                 if ( num < sizeof(data)/sizeof(int) )
58                         return data[num];
59                 return 0;
60         }
61
62         int getData(unsigned int num) const
63         {
64                 if ( num < sizeof(data)/sizeof(int) )
65                         return data[num];
66                 return 0;
67         }
68
69         void setUnsignedData(unsigned int num, unsigned int val)
70         {
71                 if ( num < sizeof(data)/sizeof(int) )
72                         data[num] = val;
73         }
74
75         void setData(unsigned int num, int val)
76         {
77                 if ( num < sizeof(data)/sizeof(int) )
78                         data[num] = val;
79         }
80
81 // only for override service names in bouquets or to give servicerefs a name which not have a
82 // real existing service ( for dvb eServiceDVB )
83 #ifndef SWIG
84         std::string name;
85 #endif
86         std::string getName() { return name; }
87         void setName( const std::string &n ) { name=n; }
88
89         eServiceReference()
90                 : type(idInvalid), flags(0)
91         {
92                 memset(data, 0, sizeof(data));
93         }
94 #ifndef SWIG
95         eServiceReference(int type, int flags)
96                 : type(type), flags(flags)
97         {
98                 memset(data, 0, sizeof(data));
99         }
100         eServiceReference(int type, int flags, int data0)
101                 : type(type), flags(flags)
102         {
103                 memset(data, 0, sizeof(data));
104                 data[0]=data0;
105         }
106         eServiceReference(int type, int flags, int data0, int data1)
107                 : type(type), flags(flags)
108         {
109                 memset(data, 0, sizeof(data));
110                 data[0]=data0;
111                 data[1]=data1;
112         }
113         eServiceReference(int type, int flags, int data0, int data1, int data2)
114                 : type(type), flags(flags)
115         {
116                 memset(data, 0, sizeof(data));
117                 data[0]=data0;
118                 data[1]=data1;
119                 data[2]=data2;
120         }
121         eServiceReference(int type, int flags, int data0, int data1, int data2, int data3)
122                 : type(type), flags(flags)
123         {
124                 memset(data, 0, sizeof(data));
125                 data[0]=data0;
126                 data[1]=data1;
127                 data[2]=data2;
128                 data[3]=data3;
129         }
130         eServiceReference(int type, int flags, int data0, int data1, int data2, int data3, int data4)
131                 : type(type), flags(flags)
132         {
133                 memset(data, 0, sizeof(data));
134                 data[0]=data0;
135                 data[1]=data1;
136                 data[2]=data2;
137                 data[3]=data3;
138                 data[4]=data4;
139         }
140         eServiceReference(int type, int flags, const std::string &path)
141                 : type(type), flags(flags), path(path)
142         {
143                 memset(data, 0, sizeof(data));
144         }
145 #endif
146         eServiceReference(const std::string &string);
147         std::string toString() const;
148         std::string toCompareString() const;
149         bool operator==(const eServiceReference &c) const
150         {
151                 if (type != c.type)
152                         return 0;
153                 return (memcmp(data, c.data, sizeof(int)*8)==0) && (path == c.path);
154         }
155         bool operator!=(const eServiceReference &c) const
156         {
157                 return !(*this == c);
158         }
159         bool operator<(const eServiceReference &c) const
160         {
161                 if (type < c.type)
162                         return 1;
163
164                 if (type > c.type)
165                         return 0;
166
167                 int r=memcmp(data, c.data, sizeof(int)*8);
168                 if (r)
169                         return r < 0;
170                 return path < c.path;
171         }
172         operator bool() const
173         {
174                 return valid();
175         }
176         
177         int valid() const
178         {
179                 return type != idInvalid;
180         }
181 };
182
183 SWIG_ALLOW_OUTPUT_SIMPLE(eServiceReference);
184
185 extern PyObject *New_eServiceReference(const eServiceReference &ref); // defined in enigma_python.i
186
187 typedef long long pts_t;
188
189         /* the reason we have the servicereference as additional argument is
190            that we don't have to create one object for every entry in a possibly
191            large list, provided that no state information is nessesary to deliver
192            the required information. Anyway - ref *must* be the same as the argument
193            to the info() or getIServiceInformation call! */
194
195         /* About the usage of SWIG_VOID:
196            SWIG_VOID(real_returntype_t) hides a return value from swig. This is used for
197            the "superflouus" RESULT return values.
198            
199            Python code has to check the returned pointer against 0. This works,
200            as all functions returning instances in smartpointers AND having a 
201            RESULT have to BOTH return non-zero AND set the pointer to zero.
202            
203            Python code thus can't check for the reason, but the reason isn't
204            user-servicable anyway. If you want to return a real reason which
205            goes beyong "it just doesn't work", use extra variables for this,
206            not the RESULT.
207            
208            Hide the result only if there is another way to check for failure! */
209            
210 TEMPLATE_TYPEDEF(ePtr<eServiceEvent>, eServiceEventPtr);
211         
212 class iStaticServiceInformation: public iObject
213 {
214 #ifdef SWIG
215         iStaticServiceInformation();
216         ~iStaticServiceInformation();
217 #endif
218 public:
219         virtual SWIG_VOID(RESULT) getName(const eServiceReference &ref, std::string &SWIG_OUTPUT)=0;
220         
221                 // doesn't need to be implemented, should return -1 then.
222         virtual int getLength(const eServiceReference &ref);
223         virtual SWIG_VOID(RESULT) getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time=-1);
224                 // returns true when not implemented
225         virtual bool isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
226
227         virtual int getInfo(const eServiceReference &ref, int w);
228         virtual std::string getInfoString(const eServiceReference &ref,int w);
229
230         virtual int setInfo(const eServiceReference &ref, int w, int v);
231         virtual int setInfoString(const eServiceReference &ref, int w, const char *v);
232 };
233
234 TEMPLATE_TYPEDEF(ePtr<iStaticServiceInformation>, iStaticServiceInformationPtr);
235
236 class iServiceInformation: public iObject
237 {
238 #ifdef SWIG
239         iServiceInformation();
240         ~iServiceInformation();
241 #endif
242 public:
243         virtual SWIG_VOID(RESULT) getName(std::string &SWIG_OUTPUT)=0;
244         virtual SWIG_VOID(RESULT) getEvent(ePtr<eServiceEvent> &SWIG_OUTPUT, int nownext);
245
246         enum {
247                 sIsCrypted,  /* is encrypted (no indication if decrypt was possible) */
248                 sAspect,     /* aspect ratio: 0=4:3, 1=16:9, 2=whatever we need */
249                 sIsMultichannel, /* multichannel *available* (probably not selected) */
250                 
251                         /* "user serviceable info" - they are not reliable. Don't use them for anything except the service menu!
252                            that's also the reason why they are so globally defined. 
253                            
254                            
255                            again - if somebody EVER tries to use this information for anything else than simply displaying it,
256                            i will change this to return a user-readable text like "zero x zero three three" (and change the
257                            exact spelling in every version) to stop that!
258                         */
259                 sVideoPID,
260                 sAudioPID,
261                 sPCRPID,
262                 sPMTPID,
263                 sTXTPID,
264                 
265                 sSID,
266                 sONID,
267                 sTSID,
268                 sNamespace,
269                 sProvider,
270                 
271                 sDescription,
272                 sServiceref,
273                 sTimeCreate,    // unix time or string
274                 
275                 sTitle,
276                 sArtist,
277                 sAlbum,
278                 sComment,
279                 sTracknumber,
280                 sGenre,
281                 sCAIDs,
282                 sVideoType,  // MPEG2 MPEG4
283                 
284                 sTags,  /* space seperated list of tags */
285         };
286         enum { resNA = -1, resIsString = -2, resIsPyObject = -3 };
287
288         virtual int getInfo(int w);
289         virtual std::string getInfoString(int w);
290         virtual PyObject *getInfoObject(int w);
291         
292         virtual int setInfo(int w, int v);
293         virtual int setInfoString(int w, const char *v);
294 };
295
296 TEMPLATE_TYPEDEF(ePtr<iServiceInformation>, iServiceInformationPtr);
297
298 class iFrontendInformation: public iObject
299 {
300 #ifdef SWIG
301         iFrontendInformation();
302         ~iFrontendInformation();
303 #endif
304 public:
305         enum {
306                 bitErrorRate,
307                 signalPower,
308                 signalQuality,
309                 lockState,
310                 syncState,
311                 frontendNumber
312         };
313         virtual int getFrontendInfo(int w)=0;
314         virtual PyObject *getFrontendData(bool original=false)=0;
315 };
316
317 TEMPLATE_TYPEDEF(ePtr<iFrontendInformation>, iFrontendInformationPtr);
318
319 class iPauseableService: public iObject
320 {
321 #ifdef SWIG
322         iPausableService();
323         ~iPausableService();
324 #endif
325 public:
326         virtual RESULT pause()=0;
327         virtual RESULT unpause()=0;
328         
329                 /* hm. */
330         virtual RESULT setSlowMotion(int ratio=0)=0;
331         virtual RESULT setFastForward(int ratio=0)=0;
332 };
333
334 TEMPLATE_TYPEDEF(ePtr<iPauseableService>, iPauseableServicePtr);
335
336 class iSeekableService: public iObject
337 {
338 #ifdef SWIG
339         iSeekableService();
340         ~iSeekableService();
341 #endif
342 public:
343         virtual RESULT getLength(pts_t &SWIG_OUTPUT)=0;
344         virtual RESULT seekTo(pts_t to)=0;
345         enum { dirForward = +1, dirBackward = -1 };
346         virtual RESULT seekRelative(int direction, pts_t to)=0;
347         virtual RESULT getPlayPosition(pts_t &SWIG_OUTPUT)=0;
348                 /* if you want to do several seeks in a row, you can enable the trickmode. 
349                    audio will be switched off, sync will be disabled etc. */
350         virtual RESULT setTrickmode(int trick=0)=0;
351         virtual RESULT isCurrentlySeekable()=0;
352 };
353
354 TEMPLATE_TYPEDEF(ePtr<iSeekableService>, iSeekableServicePtr);
355
356 struct iAudioTrackInfo
357 {
358 #ifndef SWIG
359         std::string m_description;
360         std::string m_language; /* iso639 */
361 #endif
362         std::string getDescription() { return m_description; }
363         std::string getLanguage() { return m_language; }
364 };
365
366 SWIG_ALLOW_OUTPUT_SIMPLE(iAudioTrackInfo);
367
368 class iAudioTrackSelection: public iObject
369 {
370 #ifdef SWIG
371         iAudioTrackSelection();
372         ~iAudioTrackSelection();
373 #endif
374 public:
375         virtual int getNumberOfTracks()=0;
376         virtual RESULT selectTrack(unsigned int i)=0;
377         virtual SWIG_VOID(RESULT) getTrackInfo(struct iAudioTrackInfo &SWIG_OUTPUT, unsigned int n)=0;
378 };
379
380 TEMPLATE_TYPEDEF(ePtr<iAudioTrackSelection>, iAudioTrackSelectionPtr);
381
382 class iAudioChannelSelection: public iObject
383 {
384 #ifdef SWIG
385         iAudioChannelSelection();
386         ~iAudioChannelSelection();
387 #endif
388 public:
389         enum { LEFT, STEREO, RIGHT };
390         virtual int getCurrentChannel()=0;
391         virtual RESULT selectChannel(int i)=0;
392 };
393
394 TEMPLATE_TYPEDEF(ePtr<iAudioChannelSelection>, iAudioChannelSelectionPtr);
395
396 class iAudioDelay: public iObject
397 {
398 #ifdef SWIG
399         iAudioDelay();
400         ~iAudioDelay();
401 #endif
402 public:
403         virtual int getAC3Delay()=0;
404         virtual int getPCMDelay()=0;
405         virtual void setAC3Delay(int)=0;
406         virtual void setPCMDelay(int)=0;
407 };
408
409 TEMPLATE_TYPEDEF(ePtr<iAudioDelay>, iAudioDelayPtr);
410
411 class iRadioText: public iObject
412 {
413 #ifdef SWIG
414         iRadioText();
415         ~iRadioText();
416 #endif
417 public:
418         virtual std::string getRadioText(int x=0)=0;
419 };
420
421 TEMPLATE_TYPEDEF(ePtr<iRadioText>, iRadioTextPtr);
422
423 class iSubserviceList: public iObject
424 {
425 #ifdef SWIG
426         iSubserviceList();
427         ~iSubserviceList();
428 #endif
429 public:
430         virtual int getNumberOfSubservices()=0;
431         virtual SWIG_VOID(RESULT) getSubservice(eServiceReference &SWIG_OUTPUT, unsigned int n)=0;
432 };
433
434 TEMPLATE_TYPEDEF(ePtr<iSubserviceList>, iSubserviceListPtr);
435
436 class iTimeshiftService: public iObject
437 {
438 #ifdef SWIG
439         iTimeshiftService();
440         ~iTimeshiftService();
441 #endif
442 public:
443         virtual RESULT startTimeshift()=0;
444         virtual RESULT stopTimeshift()=0;
445         
446         virtual int isTimeshiftActive()=0;
447                         /* this essentially seeks to the relative end of the timeshift buffer */
448         virtual RESULT activateTimeshift()=0;
449 };
450
451 TEMPLATE_TYPEDEF(ePtr<iTimeshiftService>, iTimeshiftServicePtr);
452
453         /* not related to eCueSheet */
454 class iCueSheet: public iObject
455 {
456 #ifdef SWIG
457         iCueSheet();
458         ~iCueSheet();
459 #endif
460 public:
461                         /* returns a list of (pts, what)-tuples */
462         virtual PyObject *getCutList() = 0;
463         virtual void setCutList(PyObject *list) = 0;
464         virtual void setCutListEnable(int enable) = 0;
465         enum { cutIn = 0, cutOut = 1, cutMark = 2 };
466 };
467
468 TEMPLATE_TYPEDEF(ePtr<iCueSheet>, iCueSheetPtr);
469
470 class eWidget;
471 class PyList;
472
473 class iSubtitleOutput: public iObject
474 {
475 public:
476         virtual RESULT enableSubtitles(eWidget *parent, PyObject *entry)=0;
477         virtual RESULT disableSubtitles(eWidget *parent)=0;
478         virtual PyObject *getSubtitleList()=0;
479         virtual PyObject *getCachedSubtitle()=0;
480 };
481
482 TEMPLATE_TYPEDEF(ePtr<iSubtitleOutput>, iSubtitleOutputPtr);
483
484 class iPlayableService: public iObject
485 {
486 #ifdef SWIG
487         iPlayableService();
488         ~iPlaybleService();
489 #endif
490         friend class iServiceHandler;
491 public:
492         enum
493         {
494                         /* these first two events are magical, and should only
495                            be generated if you know what you're doing. */
496                 evStart,
497                 evEnd,
498                 
499                 evTuneFailed,
500                         // when iServiceInformation is implemented:
501                 evUpdatedEventInfo,
502                 evUpdatedInfo,
503
504                         /* when seek() is implemented: */               
505                 evSeekableStatusChanged, /* for example when timeshifting */
506                 
507                 evEOF,
508                 evSOF, /* bounced against start of file (when seeking backwards) */
509                 
510                         /* only when cueSheet is implemented */
511                 evCuesheetChanged,
512
513                 evUpdatedRadioText
514         };
515         virtual RESULT connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)=0;
516         virtual RESULT start()=0;
517         virtual RESULT stop()=0;
518                         /* might have to be changed... */
519         virtual RESULT setTarget(int target)=0;
520         virtual SWIG_VOID(RESULT) seek(ePtr<iSeekableService> &SWIG_OUTPUT)=0;
521         virtual SWIG_VOID(RESULT) pause(ePtr<iPauseableService> &SWIG_OUTPUT)=0;
522         virtual SWIG_VOID(RESULT) info(ePtr<iServiceInformation> &SWIG_OUTPUT)=0;
523         virtual SWIG_VOID(RESULT) audioTracks(ePtr<iAudioTrackSelection> &SWIG_OUTPUT)=0;
524         virtual SWIG_VOID(RESULT) audioChannel(ePtr<iAudioChannelSelection> &SWIG_OUTPUT)=0;
525         virtual SWIG_VOID(RESULT) subServices(ePtr<iSubserviceList> &SWIG_OUTPUT)=0;
526         virtual SWIG_VOID(RESULT) frontendInfo(ePtr<iFrontendInformation> &SWIG_OUTPUT)=0;
527         virtual SWIG_VOID(RESULT) timeshift(ePtr<iTimeshiftService> &SWIG_OUTPUT)=0;
528         virtual SWIG_VOID(RESULT) cueSheet(ePtr<iCueSheet> &SWIG_OUTPUT)=0;
529         virtual SWIG_VOID(RESULT) subtitle(ePtr<iSubtitleOutput> &SWIG_OUTPUT)=0;
530         virtual SWIG_VOID(RESULT) audioDelay(ePtr<iAudioDelay> &SWIG_OUTPUT)=0;
531         virtual SWIG_VOID(RESULT) radioText(ePtr<iRadioText> &SWIG_OUTPUT)=0;
532 };
533
534 TEMPLATE_TYPEDEF(ePtr<iPlayableService>, iPlayableServicePtr);
535
536 class iRecordableService: public iObject
537 {
538 #ifdef SWIG
539         iRecordableService();
540         ~iRecordableService();
541 #endif
542 public:
543         enum
544         {
545                 evStart,
546                 evStop,
547                 evTunedIn,
548                 evTuneFailed,
549                 evRecordRunning,
550                 evNewProgramInfo,
551                 evRecordFailed
552 //              evDiskFull
553         };
554         enum
555         {
556                 NoError=0,
557                 errOpenRecordFile=-1,
558                 errNoDemuxAvailable=-2,
559                 errNoTsRecorderAvailable=-3,
560                 errDiskFull=-4,
561                 errTuneFailed=-255
562         };
563         virtual RESULT getError(int &)=0;
564         virtual RESULT connectEvent(const Slot2<void,iRecordableService*,int> &event, ePtr<eConnection> &connection)=0;
565         virtual RESULT prepare(const char *filename, time_t begTime=-1, time_t endTime=-1, int eit_event_id=-1)=0;
566         virtual RESULT start()=0;
567         virtual RESULT stop()=0;
568         virtual SWIG_VOID(RESULT) frontendInfo(ePtr<iFrontendInformation> &SWIG_OUTPUT)=0;
569 };
570
571 TEMPLATE_TYPEDEF(ePtr<iRecordableService>, iRecordableServicePtr);
572
573 // TEMPLATE_TYPEDEF(std::list<eServiceReference>, eServiceReferenceList);
574
575 class iMutableServiceList: public iObject
576 {
577 #ifdef SWIG
578         iMutableServiceList();
579         ~iMutableServiceList();
580 #endif
581 public:
582                 /* flush changes */
583         virtual RESULT flushChanges()=0;
584                 /* adds a service to a list */
585         virtual RESULT addService(eServiceReference &ref, eServiceReference before=eServiceReference())=0;
586                 /* removes a service from a list */
587         virtual RESULT removeService(eServiceReference &ref)=0;
588                 /* moves a service in a list, only if list suppports a specific sort method. */
589                 /* pos is the new, absolute position from 0..size-1 */
590         virtual RESULT moveService(eServiceReference &ref, int pos)=0;
591                 /* set name of list, for bouquets this is the visible bouquet name */
592         virtual RESULT setListName(const std::string &name)=0;
593 };
594
595 TEMPLATE_TYPEDEF(ePtr<iMutableServiceList>, iMutableServiceListPtr);
596
597 class iListableService: public iObject
598 {
599 #ifdef SWIG
600         iListableService();
601         ~iListableService();
602 #endif
603 public:
604                 /* legacy interface: get a list */
605         virtual RESULT getContent(std::list<eServiceReference> &list, bool sorted=false)=0;
606         virtual PyObject *getContent(const char* format, bool sorted=false)=0;
607
608                 /* new, shiny interface: streaming. */
609         virtual SWIG_VOID(RESULT) getNext(eServiceReference &SWIG_OUTPUT)=0;
610         
611                 /* use this for sorting. output is not sorted because of either
612                  - performance reasons: the whole list must be buffered or
613                  - the interface would be restricted to a list. streaming
614                    (as well as a future "active" extension) won't be possible.
615                 */
616         virtual int compareLessEqual(const eServiceReference &, const eServiceReference &)=0;
617         
618         virtual SWIG_VOID(RESULT) startEdit(ePtr<iMutableServiceList> &SWIG_OUTPUT)=0;
619 };
620
621 TEMPLATE_TYPEDEF(ePtr<iListableService>, iListableServicePtr);
622
623 #ifndef SWIG
624         /* a helper class which can be used as argument to stl's sort(). */
625 class iListableServiceCompare
626 {
627         ePtr<iListableService> m_list;
628 public:
629         iListableServiceCompare(iListableService *list): m_list(list) { }
630         bool operator()(const eServiceReference &a, const eServiceReference &b)
631         {
632                 return m_list->compareLessEqual(a, b);
633         }
634 };
635 #endif
636
637 class iServiceOfflineOperations: public iObject
638 {
639 #ifdef SWIG
640         iServiceOfflineOperations();
641         ~iServiceOfflineOperations();
642 #endif
643 public:
644                 /* to delete a service, forever. */
645         virtual RESULT deleteFromDisk(int simulate=1)=0;
646         
647                 /* for transferring a service... */
648         virtual SWIG_VOID(RESULT) getListOfFilenames(std::list<std::string> &SWIG_OUTPUT)=0;
649         
650                 // TODO: additional stuff, like a conversion interface?
651 };
652
653 TEMPLATE_TYPEDEF(ePtr<iServiceOfflineOperations>, iServiceOfflineOperationsPtr);
654
655 class iServiceHandler: public iObject
656 {
657 #ifdef SWIG
658         iServiceHandler();
659         ~iServiceHandler();
660 #endif
661 public:
662         virtual SWIG_VOID(RESULT) play(const eServiceReference &, ePtr<iPlayableService> &SWIG_OUTPUT)=0;
663         virtual SWIG_VOID(RESULT) record(const eServiceReference &, ePtr<iRecordableService> &SWIG_OUTPUT)=0;
664         virtual SWIG_VOID(RESULT) list(const eServiceReference &, ePtr<iListableService> &SWIG_OUTPUT)=0;
665         virtual SWIG_VOID(RESULT) info(const eServiceReference &, ePtr<iStaticServiceInformation> &SWIG_OUTPUT)=0;
666         virtual SWIG_VOID(RESULT) offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &SWIG_OUTPUT)=0;
667 };
668
669 TEMPLATE_TYPEDEF(ePtr<iServiceHandler>, iServiceHandlerPtr);
670
671 #endif