summaryrefslogtreecommitdiffabout
path: root/src
authorMichael Krelin <hacker@klever.net>2009-03-08 20:09:21 (UTC)
committer Michael Krelin <hacker@klever.net>2009-03-08 20:09:21 (UTC)
commitaadaa8b5d7eda23e72dbded9d6437b40358353f3 (patch) (side-by-side diff)
tree0bff6fdde1e2b9be02b48aaf7d03f095604718e1 /src
downloadiii-0.0.zip
iii-0.0.tar.gz
iii-0.0.tar.bz2
Inital commit to public repository0.0
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/.gitignore10
-rw-r--r--src/Makefile.am32
-rw-r--r--src/eyefi.h47
-rw-r--r--src/eyefiservice.cc186
-rw-r--r--src/eyefiworker.cc26
-rw-r--r--src/eyefiworker.h15
-rw-r--r--src/eyekinfig.cc67
-rw-r--r--src/eyekinfig.h25
-rw-r--r--src/eyetil.cc103
-rw-r--r--src/eyetil.h48
-rw-r--r--src/iiid.cc86
11 files changed, 645 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..425033a
--- a/dev/null
+++ b/src/.gitignore
@@ -0,0 +1,10 @@
+/.deps
+eyefi.nsmap
+soapC.cpp
+soapH.h
+soapStub.h
+soapeyefiService.cpp
+soapeyefiService.h
+*.o
+/iiid
+/COPYING.cc
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..09f698e
--- a/dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,32 @@
+sbin_PROGRAMS=iiid
+noinst_HEADERS = \
+ eyefi.h \
+ eyekinfig.h eyetil.h \
+ eyefiworker.h
+
+AM_CPPFLAGS = ${CPPFLAGS_DEBUG} \
+ -DEYEKIN_CONF_DIR=\"${sysconfdir}/${PACKAGE}\"
+DEFAULT_INCLUDES = -I${top_builddir} -I${builddir} -I${srcdir}
+INCLUDES = ${MODULES_CFLAGS}
+
+iiid_SOURCES = iiid.cc \
+ eyekinfig.cc eyetil.cc \
+ eyefiservice.cc eyefiworker.cc
+nodist_iiid_SOURCES = \
+ ${builddir}/soapC.cpp ${builddir}/soapeyefiService.cpp \
+ COPYING.cc
+iiid_LDADD = ${MODULES_LIBS}
+
+COPYING.cc: ${top_srcdir}/COPYING
+ echo "const char * COPYING = " >$@ || (rm $@;exit 1)
+ sed -e 's/"/\\"/g' -e 's/^/\"/' -e 's/$$/\\n\"/' $< >>$@ || (rm $@;exit 1)
+ echo ';' >>$@ || (rm $@;exit 1)
+
+${srcdir}/eyefiservice.cc: ${builddir}/soapeyefiService.h
+${srcdir}/iiid.cc: ${builddir}/eyefi.nsmap
+
+${builddir}soapC.cpp ${builddir}/soapeyefiService.cpp ${builddir}/eyefi.nsmap ${builddir}/soapeyefiService.h: ${srcdir}/eyefi.h
+ ${SOAPCPP2} -d${builddir} -S -L -a -i -w -x $<
+
+clean-local:
+ rm -f soap{{H,Stub,eyefiService}.h,{C,eyefiService}.cpp} eyefi.nsmap COPYING.cc
diff --git a/src/eyefi.h b/src/eyefi.h
new file mode 100644
index 0000000..70e918d
--- a/dev/null
+++ b/src/eyefi.h
@@ -0,0 +1,47 @@
+//gsoap efs service name: eyefi
+//gsoap efs service location: http://api.eye.fi/api/soap/eyefilm/v1
+//gsoap efs service namespace: EyeFi/SOAP/EyeFilm
+//gsoap efs service method-action: StartSession "urn:StartSession"
+//gsoap efs service method-action: GetPhotoStatus "urn:GetPhotoStatus"
+//gsoap efs service method-action: MarkLastPhotoInRoll "urn:MarkLastPhotoInRoll"
+//gsoap rns service namespace: http://localhost/api/soap/eyefilm
+
+struct rns__StartSessionResponse {
+ std::string credential;
+ std::string snonce;
+ int transfermode;
+ unsigned int transfermodetimestamp;
+ bool upsyncallowed;
+};
+
+int efs__StartSession(
+ std::string macaddress,std::string cnonce,
+ int transfermode,long transfermodetimestamp,
+ struct rns__StartSessionResponse &r );
+
+struct rns__GetPhotoStatusResponse {
+ int fileid;
+ long offset;
+};
+
+int efs__GetPhotoStatus(
+ std::string credential, std::string macaddress,
+ std::string filename, long filesize, std::string filesignature,
+ struct rns__GetPhotoStatusResponse &r );
+
+struct rns__MarkLastPhotoInRollResponse {
+};
+
+int efs__MarkLastPhotoInRoll(
+ std::string macaddress, int mergedelta,
+ struct rns__MarkLastPhotoInRollResponse &r );
+
+struct rns__UploadPhotoResponse {
+ bool success;
+};
+
+int efs__UploadPhoto(
+ int fileid, std::string macaddress,
+ std::string filename, long filesize, std::string filesignature,
+ std::string encryption, int flags,
+ struct rns__UploadPhotoResponse& r );
diff --git a/src/eyefiservice.cc b/src/eyefiservice.cc
new file mode 100644
index 0000000..30c06fa
--- a/dev/null
+++ b/src/eyefiservice.cc
@@ -0,0 +1,186 @@
+#include <cassert>
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include <iterator>
+#include <syslog.h>
+#include <sys/wait.h>
+#include <autosprintf.h>
+#include "eyekinfig.h"
+#include "eyetil.h"
+#include "soapeyefiService.h"
+
+static bool detached_child() {
+ pid_t p = fork();
+ if(p<0) throw std::runtime_error("failed to fork()");
+ if(!p) {
+ p = fork();
+ if(p<0) {
+ syslog(LOG_ERR,"Failed to re-fork child process");
+ _exit(-1);
+ }
+ if(!p) {
+ setsid();
+ for(int i=getdtablesize();i>=0;--i) close(i);
+ int i=open("/dev/null",O_RDWR); assert(i==0);
+ i = dup(i); assert(i==1);
+ i = dup(i); assert(i==2);
+ return true;
+ }
+ _exit(0);
+ }
+ int rc;
+ if(waitpid(p,&rc,0)<0) throw std::runtime_error("failed to waitpid()");
+ if(!WIFEXITED(rc)) throw std::runtime_error("error in forked process");
+ if(WEXITSTATUS(rc)) throw std::runtime_error("forked process signalled error");
+ return false;
+}
+
+int eyefiService::StartSession(
+ std::string macaddress,std::string cnonce,
+ int transfermode,long transfermodetimestamp,
+ struct rns__StartSessionResponse &r ) {
+#ifndef NDEBUG
+ syslog(LOG_DEBUG,
+ "StartSession request from %s with cnonce=%s, transfermode=%d, transfermodetimestamp=%ld",
+ macaddress.c_str(), cnonce.c_str(), transfermode, transfermodetimestamp );
+#endif
+ r.credential = binary_t(macaddress+cnonce+eyekinfig_t(macaddress).get_upload_key()).md5().hex();
+ /* TODO: better nonce generator */
+ time_t t = time(0);
+ r.snonce = binary_t(&t,sizeof(t)).md5().hex();
+ r.transfermode=2;
+ r.transfermodetimestamp=t;
+ r.upsyncallowed=false;
+
+ std::string cmd = eyekinfig_t(macaddress).get_on_start_session();
+ if(!cmd.empty()) {
+ if(detached_child()) {
+ putenv( gnu::autosprintf("EYEFI_MACADDRESS=%s",macaddress.c_str()) );
+ putenv( gnu::autosprintf("EYEFI_TRANSFERMODE=%d",transfermode) );
+ putenv( gnu::autosprintf("EYEFI_TRANSFERMODETIMESTAMP=%ld",transfermodetimestamp) );
+ char *argv[] = { (char*)"/bin/sh", (char*)"-c", (char*)cmd.c_str(), 0 };
+ execv("/bin/sh",argv);
+ syslog(LOG_ERR,"Failed to execute '%s'",cmd.c_str());
+ _exit(-1);
+ }
+ }
+ return SOAP_OK;
+}
+
+int eyefiService::GetPhotoStatus(
+ std::string credential, std::string macaddress,
+ std::string filename, long filesize, std::string filesignature,
+ struct rns__GetPhotoStatusResponse &r ) {
+#ifndef NDEBUG
+ syslog(LOG_DEBUG,
+ "GetPhotoStatus request from %s with credential=%s, filename=%s, filesize=%ld, filesignature=%s",
+ macaddress.c_str(), credential.c_str(), filename.c_str(), filesize, filesignature.c_str() );
+#endif
+ r.fileid = 1; r.offset = 0;
+ return SOAP_OK;
+}
+
+int eyefiService::MarkLastPhotoInRoll(
+ std::string macaddress, int mergedelta,
+ struct rns__MarkLastPhotoInRollResponse &r ) {
+#ifndef NDEBUG
+ syslog(LOG_DEBUG,
+ "MarkLastPhotoInRoll request from %s with mergedelta=%d",
+ macaddress.c_str(), mergedelta );
+#endif
+ std::string cmd = eyekinfig_t(macaddress).get_on_mark_last_photo_in_roll();
+ if(!cmd.empty()) {
+ if(detached_child()) {
+ putenv( gnu::autosprintf("EYEFI_MACADDRESS=%s",macaddress.c_str()) );
+ putenv( gnu::autosprintf("EYEFI_MERGEDELTA=%d",mergedelta) );
+ char *argv[] = { (char*)"/bin/sh", (char*)"-c", (char*)cmd.c_str(), 0 };
+ execv("/bin/sh",argv);
+ syslog(LOG_ERR,"Failed to execute '%s'",cmd.c_str());
+ _exit(-1);
+ }
+ }
+ return SOAP_OK;
+}
+
+int eyefiService::UploadPhoto(
+ int fileid, std::string macaddress,
+ std::string filename, long filesize, std::string filesignature,
+ std::string encryption, int flags,
+ struct rns__UploadPhotoResponse& r ) {
+#ifndef NDEBUG
+ syslog(LOG_DEBUG,
+ "UploadPhoto request from %s with fileid=%d, filename=%s, filesize=%ld,"
+ " filesignature=%s, encryption=%s, flags=%04X",
+ macaddress.c_str(), fileid, filename.c_str(), filesize,
+ filesignature.c_str(), encryption.c_str(), flags );
+#endif
+ eyekinfig_t eyekinfig(macaddress);
+
+ umask(eyekinfig.get_umask());
+
+ std::string td = eyekinfig.get_targetdir();
+ /* TODO: try to create, if needed */
+ tmpdir_t indir(td+"/.incoming.XXXXXX");
+
+ for(soap_multipart::iterator i=mime.begin(),ie=mime.end();i!=ie;++i) {
+#ifndef NDEBUG
+ syslog(LOG_DEBUG,
+ " MIME attachment with id=%s, type=%s, size=%ld",
+ (*i).id, (*i).type, (long)(*i).size );
+#endif
+
+#ifndef NDEBUG
+ if((*i).id && !strcmp((*i).id,"INTEGRITYDIGEST")) {
+ std::string idigest((*i).ptr,(*i).size);
+ syslog(LOG_DEBUG, " INTEGRITYDIGEST=%s", idigest.c_str());
+ }
+#endif
+ if( (*i).id && !strcmp((*i).id,"FILENAME") ) {
+ assert( (*i).type && !strcmp((*i).type,"application/x-tar") );
+#ifdef III_SAVE_TARS
+ std::string tarfile = indir.get_file(filename);
+ {
+ std::ofstream(tarfile.c_str(),std::ios::out|std::ios::binary).write((*i).ptr,(*i).size);
+ }
+#endif
+ tarchive_t a((*i).ptr,(*i).size);
+ if(!a.read_next_header())
+ throw std::runtime_error("failed to tarchive_t::read_next_header())");
+ std::string jf = indir.get_file(a.entry_pathname());
+ std::string::size_type ls = jf.rfind('/');
+ std::string jbn = (ls==std::string::npos)?jf:jf.substr(ls+1);
+ int fd=open(jf.c_str(),O_CREAT|O_WRONLY,0666);
+ assert(fd>0);
+ a.read_data_into_fd(fd);
+ close(fd);
+ std::string tf = td+'/'+jbn;
+ bool success = false;
+ if(!link(jf.c_str(), tf.c_str())) {
+ unlink(jf.c_str()); success = true;
+ }else{
+ for(int i=1;i<32767;++i) {
+ tf = (const char*)gnu::autosprintf( "%s/(%05d)%s",
+ td.c_str(), i, jbn.c_str() );
+ if(!link(jf.c_str(), tf.c_str())) {
+ unlink(jf.c_str()); success = true;
+ break;
+ }
+ }
+ }
+ std::string cmd = eyekinfig.get_on_upload_photo();
+ if(success && !cmd.empty()) {
+ if(detached_child()) {
+ putenv( gnu::autosprintf("EYEFI_MACADDRESS=%s",macaddress.c_str()) );
+ putenv( gnu::autosprintf("EYEFI_UPLOADED=%s",tf.c_str()) );
+ char *argv[] = { (char*)"/bin/sh", (char*)"-c", (char*)cmd.c_str(), 0 };
+ execv("/bin/sh",argv);
+ syslog(LOG_ERR,"Failed to execute '%s'",cmd.c_str());
+ _exit(-1);
+ }
+ }
+ }
+ }
+ r.success = true;
+ return SOAP_OK;
+}
diff --git a/src/eyefiworker.cc b/src/eyefiworker.cc
new file mode 100644
index 0000000..d87c36e
--- a/dev/null
+++ b/src/eyefiworker.cc
@@ -0,0 +1,26 @@
+#include <sys/wait.h>
+#include <stdexcept>
+#include "eyefiworker.h"
+
+eyefiworker::eyefiworker()
+ : eyefiService(SOAP_IO_STORE|SOAP_IO_KEEPALIVE) {
+ bind_flags = SO_REUSEADDR; max_keep_alive = 0;
+ }
+
+int eyefiworker::run(int port) {
+ if(!soap_valid_socket(bind(0,port,5)))
+ throw std::runtime_error("failed to bind()");
+ while(true) {
+ while(waitpid(-1,0,WNOHANG)>0);
+ if(!soap_valid_socket(accept()))
+ throw std::runtime_error("failed to accept()");
+ pid_t p = fork();
+ if(p<0) throw std::runtime_error("failed to fork()");
+ if(!p) {
+ (void)serve();
+ soap_destroy(this); soap_end(this); soap_done(this);
+ _exit(0);
+ }
+ close(socket); socket = SOAP_INVALID_SOCKET;
+ }
+}
diff --git a/src/eyefiworker.h b/src/eyefiworker.h
new file mode 100644
index 0000000..c08ec8b
--- a/dev/null
+++ b/src/eyefiworker.h
@@ -0,0 +1,15 @@
+#ifndef __EYEFIWORKER_H
+#define __EYEFIWORKER_H
+
+#include "soapeyefiService.h"
+
+class eyefiworker : public eyefiService {
+ public:
+
+ eyefiworker();
+
+ int run(int port);
+
+};
+
+#endif /* __EYEFIWORKER_H */
diff --git a/src/eyekinfig.cc b/src/eyekinfig.cc
new file mode 100644
index 0000000..27a5a56
--- a/dev/null
+++ b/src/eyekinfig.cc
@@ -0,0 +1,67 @@
+#include <cassert>
+#include <stdexcept>
+#include <autosprintf.h>
+#include "eyekinfig.h"
+
+#include "config.h"
+
+eyekinfig_t::eyekinfig_t(const std::string& ma)
+ : macaddress(ma) {
+ static cfg_opt_t opts[] = {
+ CFG_STR((char*)"targetdir",(char*)"/var/lib/" PACKAGE "/%s",CFGF_NONE),
+ CFG_STR((char*)"uploadkey",(char*)"",CFGF_NONE),
+ CFG_STR((char*)"on-start-session",(char*)"",CFGF_NONE),
+ CFG_STR((char*)"on-upload-photo",(char*)"",CFGF_NONE),
+ CFG_STR((char*)"on-mark-last-photo-in-roll",(char*)"",CFGF_NONE),
+ CFG_INT((char*)"umask",022,CFGF_NONE),
+ CFG_END()
+ };
+ cfg = cfg_init(opts,CFGF_NONE);
+ if(!cfg)
+ throw std::runtime_error("failed to cfg_init()");
+ std::string::size_type ls = macaddress.rfind('/');
+ if(cfg_parse(cfg,gnu::autosprintf(
+ EYEKIN_CONF_DIR "/%s.conf",
+ (ls==std::string::npos)
+ ? macaddress.c_str()
+ : macaddress.substr(ls+1).c_str()
+ )) ==CFG_PARSE_ERROR) {
+ if(cfg) cfg_free(cfg);
+ cfg=0;
+ throw std::runtime_error("failed to cfg_parse()");
+ }
+ }
+
+eyekinfig_t::~eyekinfig_t() {
+ if(cfg) cfg_free(cfg);
+}
+
+std::string eyekinfig_t::get_targetdir() {
+ assert(cfg);
+ return gnu::autosprintf(cfg_getstr(cfg,"targetdir"),macaddress.c_str());
+}
+
+std::string eyekinfig_t::get_upload_key() {
+ assert(cfg);
+ return cfg_getstr(cfg,"uploadkey");
+}
+
+std::string eyekinfig_t::get_on_start_session() {
+ assert(cfg);
+ return cfg_getstr(cfg,"on-start-session");
+}
+std::string eyekinfig_t::get_on_upload_photo() {
+ assert(cfg);
+ return cfg_getstr(cfg,"on-upload-photo");
+}
+
+std::string eyekinfig_t::get_on_mark_last_photo_in_roll() {
+ assert(cfg);
+ return cfg_getstr(cfg,"on-mark-last-photo-in-roll");
+}
+
+
+int eyekinfig_t::get_umask() {
+ assert(cfg);
+ return cfg_getint(cfg,"umask");
+}
diff --git a/src/eyekinfig.h b/src/eyekinfig.h
new file mode 100644
index 0000000..34f8d49
--- a/dev/null
+++ b/src/eyekinfig.h
@@ -0,0 +1,25 @@
+#ifndef __EYEKINFIG_H
+#define __EYEKINFIG_H
+
+#include <confuse.h>
+#include <string>
+
+class eyekinfig_t {
+ public:
+ std::string macaddress;
+ cfg_t *cfg;
+
+ eyekinfig_t(const std::string& ma);
+ ~eyekinfig_t();
+
+ std::string get_targetdir();
+ std::string get_upload_key();
+
+ std::string get_on_start_session();
+ std::string get_on_upload_photo();
+ std::string get_on_mark_last_photo_in_roll();
+
+ int get_umask();
+};
+
+#endif /* __EYEKINFIG_H */
diff --git a/src/eyetil.cc b/src/eyetil.cc
new file mode 100644
index 0000000..d00c2ee
--- a/dev/null
+++ b/src/eyetil.cc
@@ -0,0 +1,103 @@
+#include <stdlib.h>
+#include <syslog.h>
+#include <iostream>
+#include <cassert>
+#include <stdexcept>
+#include <openssl/md5.h>
+#include "eyetil.h"
+
+binary_t& binary_t::from_hex(const std::string& h) {
+ /* TODO: algorithmize */
+ std::string::size_type hs = h.length();
+ if(hs&1)
+ throw std::runtime_error("odd number of characters in hexadecimal number");
+ int rvs = hs>>1;
+ resize(rvs);
+ const unsigned char *hp = (const unsigned char*)h.data();
+ iterator oi=begin();
+ char t[3] = { 0,0,0 };
+ for(int i=0;i<rvs;++i) {
+ t[0]=*(hp++); t[1]=*(hp++);
+ *(oi++) = strtol(t,0,16);
+ }
+ return *this;
+}
+
+binary_t& binary_t::from_data(const void *d,size_t s) {
+ resize(s);
+ std::copy((const unsigned char*)d,(const unsigned char *)d+s,
+ begin() );
+ return *this;
+}
+
+std::string binary_t::hex() const {
+ std::string rv;
+ rv.reserve((size()<<1)+1);
+ char t[3] = {0,0,0};
+ for(const_iterator i=begin(),ie=end();i!=ie;++i) {
+ int rc = snprintf(t,sizeof(t),"%02x",*i);
+ assert(rc<sizeof(t));
+ rv += t;
+ }
+ return rv;
+}
+
+binary_t binary_t::md5() const {
+ binary_t rv(MD5_DIGEST_LENGTH);
+ if(!MD5(
+ (const unsigned char*)&(front()),size(),
+ (unsigned char*)&(rv.front()) ))
+ throw std::runtime_error("failed to md5()");
+ return rv;
+}
+
+tmpdir_t::tmpdir_t(const std::string& dt) : dir(dt) {
+ if(!mkdtemp((char*)dir.data()))
+ throw std::runtime_error("failed to mkdtmp()");
+}
+tmpdir_t::~tmpdir_t() {
+ assert(!dir.empty());
+ if(rmdir(dir.c_str())) {
+ syslog(LOG_WARNING,"Failed to remove '%s' directory",dir.c_str());
+ }
+}
+
+std::string tmpdir_t::get_file(const std::string& f) {
+ std::string::size_type ls = f.rfind('/');
+ return dir+'/'+(
+ (ls==std::string::npos)
+ ? f
+ : f.substr(ls+1)
+ );
+}
+
+tarchive_t::tarchive_t(void *p,size_t s) : a(archive_read_new()), e(0) {
+ if(!a) throw std::runtime_error("failed to archive_read_new()");
+ if(archive_read_support_format_tar(a)) {
+ archive_read_finish(a);
+ throw std::runtime_error("failed to archive_read_support_format_tar()");
+ }
+ if(archive_read_open_memory(a,p,s)) {
+ archive_read_finish(a);
+ throw std::runtime_error("failed to archive_read_open_memory()");
+ }
+}
+tarchive_t::~tarchive_t() {
+ assert(a);
+ archive_read_finish(a);
+}
+
+bool tarchive_t::read_next_header() {
+ assert(a);
+ return archive_read_next_header(a,&e)==ARCHIVE_OK;
+}
+
+std::string tarchive_t::entry_pathname() {
+ assert(a); assert(e);
+ return archive_entry_pathname(e);
+}
+
+bool tarchive_t::read_data_into_fd(int fd) {
+ assert(a);
+ return archive_read_data_into_fd(a,fd)==ARCHIVE_OK;
+}
diff --git a/src/eyetil.h b/src/eyetil.h
new file mode 100644
index 0000000..195d24f
--- a/dev/null
+++ b/src/eyetil.h
@@ -0,0 +1,48 @@
+#ifndef __EYETIL_H
+#define __EYETIL_H
+
+#include <vector>
+#include <string>
+#include <archive.h>
+#include <archive_entry.h>
+
+class binary_t : public std::vector<unsigned char> {
+ public:
+ binary_t() { }
+ binary_t(size_type n) : std::vector<unsigned char>(n) { }
+ binary_t(const std::string& h) { from_hex(h); }
+ binary_t(const void *d,size_t s) { from_data(d,s); }
+
+ binary_t& from_hex(const std::string& h);
+ binary_t& from_data(const void *d,size_t s);
+
+ std::string hex() const;
+ binary_t md5() const;
+};
+
+class tmpdir_t {
+ public:
+ std::string dir;
+
+ tmpdir_t(const std::string& dt);
+ ~tmpdir_t();
+
+ std::string get_file(const std::string& f);
+};
+
+class tarchive_t {
+ public:
+ struct archive *a;
+ struct archive_entry *e;
+
+ tarchive_t(void *p,size_t s);
+ ~tarchive_t();
+
+ bool read_next_header();
+
+ std::string entry_pathname();
+
+ bool read_data_into_fd(int fd);
+};
+
+#endif /* __EYETIL_H */
diff --git a/src/iiid.cc b/src/iiid.cc
new file mode 100644
index 0000000..6c23790
--- a/dev/null
+++ b/src/iiid.cc
@@ -0,0 +1,86 @@
+#include <syslog.h>
+#include <getopt.h>
+#include <iostream>
+#include <cassert>
+#include <stdexcept>
+#include "eyetil.h"
+#include "eyefiworker.h"
+
+#include "config.h"
+
+#include "eyefi.nsmap"
+
+#define PHEADER \
+ PACKAGE " Version " VERSION "\n" \
+ "Copyright (c) 2009 Klever Group"
+
+int main(int argc,char **argv) try {
+
+ int port = 59278;
+
+ while(true) {
+ static struct option opts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "usage", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'V' },
+ { "license", no_argument, 0, 'L' },
+ { "port", required_argument, 0, 'p' },
+ { NULL, 0, 0, 0 }
+ };
+ int c = getopt_long(argc,argv,"hVLp:",opts,NULL);
+ if(c==-1) break;
+ switch(c) {
+ case 'h':
+ std::cerr << PHEADER << std::endl << std::endl
+ << " " << argv[0] << " [options]" << std::endl
+ << std::endl <<
+ " -h, --help,\n"
+ " --usage display this text\n"
+ " -V, --version display version information\n"
+ " -L, --license show license\n"
+ " -p <port>, --port=<port> port to listen to\n"
+ " (you're not likely to ever need it)\n"
+ << std::endl << std::endl;
+ exit(0);
+ break;
+ case 'V':
+ std::cerr << VERSION << std::endl;
+ exit(0);
+ break;
+ case 'L':
+ extern const char *COPYING;
+ std::cerr << COPYING << std::endl;
+ exit(0);
+ break;
+ case 'p':
+ port = strtol(optarg,0,0);
+ if(errno) {
+ std::cerr << "Failed to parse port number" << std::endl;
+ exit(1);
+ }
+ break;
+ default:
+ std::cerr << "Huh?" << std::endl;
+ exit(1);
+ break;
+ }
+ }
+
+ const char *ident = rindex(*argv,'/');
+ if(ident)
+ ++ident;
+ else
+ ident = *argv;
+ openlog(ident,LOG_PERROR|LOG_PID,LOG_DAEMON);
+ syslog(LOG_INFO,"Starting iii eye-fi manager");
+
+ eyefiworker().run(port);
+
+ closelog();
+ return 0;
+} catch(std::exception& e) {
+ syslog(LOG_CRIT,"Exiting iii daemon, because of error condition");
+ syslog(LOG_CRIT,"Exception: %s",e.what());
+ return 1;
+}
+