summaryrefslogtreecommitdiffabout
path: root/src/eyefiservice.cc
Side-by-side diff
Diffstat (limited to 'src/eyefiservice.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--src/eyefiservice.cc186
1 files changed, 186 insertions, 0 deletions
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;
+}