- //#define USE_KWIN
-
- #include "kdialogd.h"
- #include <iostream>
- #include <tdediroperator.h>
- #include <kuniqueapplication.h>
- #include <tqsocketnotifier.h>
- #include <tdeio/netaccess.h>
- #include <tdemessagebox.h>
- #include <tdelocale.h>
- #include <tdeconfig.h>
- #include <kurlcombobox.h>
- #ifdef USE_KWIN
- #include <twin.h>
- #else
- #include <X11/Xlib.h>
- #endif
- #include <sys/un.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/errno.h>
- #include <ksockaddr.h>
- #include <kdebug.h>
- #include <tdeversion.h>
- #include <tqtimer.h>
- #ifdef KDIALOGD_APP
- #include <tdecmdlineargs.h>
- #include <tdeaboutdata.h>
- #endif
- #include <fstream>
-
- TDEConfig *KDialogD::theirConfig=NULL;
-
- #define CFG_KEY_DIALOG_SIZE "KDialogDSize"
- #define CFG_TIMEOUT_GROUP "General"
- #ifdef KDIALOGD_APP
- #define CFG_TIMEOUT_KEY "Timeout"
- #define DEFAULT_TIMEOUT 30
- #endif
-
- static TQString groupName(const TQString &app, bool fileDialog=true)
- {
- return TQString(fileDialog ? "KFileDialog " : "KDirSelectDialog ")+app;
- }
-
- // from tdebase/tdesu
- static int createSocket()
- {
- int sockitsFd;
- ksocklen_t addrlen;
- struct stat s;
- const char *sock=getSockName();
- int stat_err=lstat(sock, &s);
-
- if(!stat_err && S_ISLNK(s.st_mode))
- {
- kdWarning() << "Someone is running a symlink attack on you" << endl;
- if(unlink(sock))
- {
- kdWarning() << "Could not delete symlink" << endl;
- return -1;
- }
- }
-
- if (!access(sock, R_OK|W_OK))
- {
- kdWarning() << "stale socket exists" << endl;
- if (unlink(sock))
- {
- kdWarning() << "Could not delete stale socket" << endl;
- return -1;
- }
- }
-
- sockitsFd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (sockitsFd < 0)
- {
- kdError() << "socket(): " << errno << endl;
- return -1;
- }
-
- struct sockaddr_un addr;
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, sock, sizeof(addr.sun_path)-1);
- addr.sun_path[sizeof(addr.sun_path)-1] = '\000';
- addrlen = SUN_LEN(&addr);
- if (bind(sockitsFd, (struct sockaddr *)&addr, addrlen) < 0)
- {
- kdError() << "bind(): " << errno << endl;
- return -1;
- }
-
- struct linger lin;
- lin.l_onoff = lin.l_linger = 0;
- if (setsockopt(sockitsFd, SOL_SOCKET, SO_LINGER, (char *) &lin, sizeof(linger)) < 0)
- {
- kdError() << "setsockopt(SO_LINGER): " << errno << endl;
- return -1;
- }
-
- int opt = 1;
- if (setsockopt(sockitsFd, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)) < 0)
- {
- kdError() << "setsockopt(SO_REUSEADDR): " << errno << endl;
- return -1;
- }
- opt = 1;
- if (setsockopt(sockitsFd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt)) < 0)
- {
- kdError() << "setsockopt(SO_KEEPALIVE): " << errno << endl;
- return -1;
- }
-
- if(::listen(sockitsFd, 1)<0)
- {
- kdError() << "listen(1): " << errno << endl;
- return -1;
- }
-
- //chmod(sock, 0600);
- return sockitsFd;
- }
-
- static void urls2Local(KURL::List &urls, TQStringList &items, TQWidget *parent)
- {
- KURL::List::Iterator it(urls.begin()),
- end(urls.end());
-
- for(; it!=end; ++it)
- if((*it).isLocalFile())
- items.append((*it).path());
- else
- {
- #if KDE_IS_VERSION(3, 5, 0)
- KURL url(TDEIO::NetAccess::mostLocalURL(*it, parent));
-
- if(url.isLocalFile())
- items.append(url.path());
- else
- break;
- #else
- break;
- #endif
- }
- }
-
- KDialogD::KDialogD(TQObject *parent)
- : TQObject(parent),
- #ifdef KDIALOGD_APP
- itsTimer(NULL),
- itsTimeoutVal(DEFAULT_TIMEOUT),
- #endif
- itsFd(::createSocket()),
- itsNumConnections(0)
- {
- if(itsFd<0)
- {
- kdError() << "KDialogD could not create socket" << endl;
- #ifdef KDIALOGD_APP
- kapp->exit();
- #endif
- }
- else
- {
- std::ofstream f(getPidFileName());
-
- if(f)
- {
- f << getpid();
- f.close();
- }
- if(!theirConfig)
- theirConfig=new TDEConfig("kdialogdrc", false, false);
-
- connect(new TQSocketNotifier(itsFd, TQSocketNotifier::Read, this),
- TQT_SIGNAL(activated(int)), this, TQT_SLOT(newConnection()));
-
- #ifdef KDIALOGD_APP
- if(theirConfig->hasGroup(CFG_TIMEOUT_GROUP))
- {
- theirConfig->setGroup(CFG_TIMEOUT_GROUP);
- itsTimeoutVal=theirConfig->readNumEntry(CFG_TIMEOUT_KEY, DEFAULT_TIMEOUT);
- if(itsTimeoutVal<0)
- itsTimeoutVal=DEFAULT_TIMEOUT;
- theirConfig->setGroup(TQString());
- }
-
- kdDebug() << "Timeout:" << itsTimeoutVal << endl;
- if(itsTimeoutVal)
- connect(itsTimer=new TQTimer(this), TQT_SIGNAL(timeout()), this, TQT_SLOT(timeout()));
- #endif
- }
- }
-
- KDialogD::~KDialogD()
- {
- if(-1!=itsFd)
- close(itsFd);
- if(theirConfig)
- delete theirConfig;
- theirConfig=NULL;
- }
-
- void KDialogD::newConnection()
- {
- kdDebug() << "New connection" << endl;
-
- ksocklen_t addrlen = 64;
- struct sockaddr_un clientname;
- int connectedFD;
-
- if((connectedFD=::accept(itsFd, (struct sockaddr *) &clientname, &addrlen))>=0)
- {
- int appNameLen;
-
- if(readBlock(connectedFD, (char *)&appNameLen, 4))
- {
- bool ok=true;
- TQCString appName;
-
- if(0==appNameLen)
- appName="Generic";
- else
- {
- appName.resize(appNameLen);
- ok=readBlock(connectedFD, appName.data(), appNameLen);
- }
-
- if(ok)
- {
- itsNumConnections++;
- #ifdef KDIALOGD_APP
- if(itsTimer)
- itsTimer->stop();
- #endif
- connect(new KDialogDClient(connectedFD, appName, this),
- TQT_SIGNAL(error(KDialogDClient *)),
- this, TQT_SLOT(deleteConnection(KDialogDClient *)));
- }
- }
- }
- }
-
- void KDialogD::deleteConnection(KDialogDClient *client)
- {
- kdDebug() << "Delete client" << endl;
- delete client;
-
- #ifdef KDIALOGD_APP
- if(0==--itsNumConnections)
- if(itsTimeoutVal)
- itsTimer->start(itsTimeoutVal*1000, true); // Only single shot...
- else
- timeout();
- #endif
- }
-
- void KDialogD::timeout()
- {
- #ifdef KDIALOGD_APP
- if(0==itsNumConnections)
- if(grabLock(0)>0) // 0=> no wait...
- {
- kdDebug() << "Timeout occured, and no connections, so exit" << endl;
- kapp->exit();
- }
- else //...unlock lock file...
- {
- kdDebug() << "Timeout occured, but unable to grab lock file - app must be connecting" << endl;
- releaseLock();
- }
- #endif
- }
-
- KDialogDClient::KDialogDClient(int sock, const TQString &an, TQObject *parent)
- : TQObject(parent),
- itsFd(sock),
- itsDlg(NULL),
- itsAccepted(false),
- itsAppName(an)
- {
- kdDebug() << "new client..." << itsAppName << " (" << itsFd << ")" << endl;
- connect(new TQSocketNotifier(itsFd, TQSocketNotifier::Read, this), TQT_SIGNAL(activated(int)), this, TQT_SLOT(read()));
- connect(new TQSocketNotifier(itsFd, TQSocketNotifier::Exception, this), TQT_SIGNAL(activated(int)), this, TQT_SLOT(close()));
- }
-
- KDialogDClient::~KDialogDClient()
- {
- kdDebug() << "Deleted client" << endl;
- if(-1!=itsFd)
- ::close(itsFd);
- if(KDialogD::config())
- KDialogD::config()->sync();
- }
-
- void KDialogDClient::close()
- {
- kdDebug() << "close " << itsFd << endl;
-
- ::close(itsFd);
- itsFd=-1;
- if(itsDlg)
- {
- itsDlg->close();
- itsDlg->delayedDestruct();
- itsDlg=NULL;
- }
- emit error(this);
- }
-
- void KDialogDClient::read()
- {
- kdDebug() << "read" << endl;
-
- if(-1==itsFd)
- return;
-
- char request;
- TQString caption;
- unsigned int xid=0;
-
- if(!itsDlg && readData(&request, 1) && request>=(char)OP_FILE_OPEN && request<=(char)OP_FOLDER &&
- readData((char *)&xid, 4) && readString(caption))
- {
- if("."==caption)
- switch((Operation)request)
- {
- case OP_FILE_OPEN:
- case OP_FILE_OPEN_MULTIPLE:
- caption=i18n("Open");
- break;
- case OP_FILE_SAVE:
- caption=i18n("Save As");
- break;
- case OP_FOLDER:
- caption=i18n("Select Folder");
- break;
- default:
- break;
- }
-
- if(OP_FOLDER==(Operation)request)
- {
- TQString intialFolder;
-
- if(readString(intialFolder))
- {
- initDialog(caption, new KDialogDDirSelectDialog(itsAppName, intialFolder, true, NULL,
- "folderdialog", false), xid);
- return;
- }
- }
- else
- {
- TQString intialFolder,
- filter;
- char overW=0;
-
- if(readString(intialFolder) && readString(filter) &&
- (OP_FILE_SAVE!=(Operation)request || readData(&overW, 1)))
- {
- initDialog(caption, new KDialogDFileDialog(itsAppName, (Operation)request, intialFolder,
- filter, overW ? true : false), xid);
- return;
- }
- }
- }
-
- kdDebug() << "Comms error, closing connection..." << itsFd << endl;
- // If we get here something was wrong, close connection...
- close();
- }
-
- void KDialogDClient::finished()
- {
- if(-1==itsFd)
- return;
-
- //
- // * finished is emitted when a dialog is ok'ed/cancel'ed/closed
- // * if the user just closes the dialog - neither ok nor cancel are emitted
- // * the dir select dialog doesnt seem to set the TQDialog result parameter
- // when it is accepted - so for this reason if ok is clicked we store an
- // 'accepted' value there, and check for that after the dialog is finished.
- kdDebug() << "finished" << endl;
- if(itsDlg && !(itsAccepted || TQDialog::Accepted==itsDlg->result()))
- cancel();
- }
-
- void KDialogDClient::ok(const TQStringList &items)
- {
- kdDebug() << "ok" << endl;
-
- int num=items.count();
- TQStringList::ConstIterator it(items.begin()),
- end(items.end());
- bool error=!writeData((char *)&num, 4);
-
- for(; !error && it!=end; ++it)
- error=!writeString(*it);
-
- if(error)
- close();
- else
- itsAccepted=true;
- if(itsDlg)
- itsDlg->delayedDestruct();
- itsDlg=NULL;
- }
-
- void KDialogDClient::cancel()
- {
- if(itsDlg)
- {
- kdDebug() << "cancel" << endl;
-
- int rv=0;
-
- if(!writeData((char *)&rv, 4))
- close();
- if(itsDlg)
- itsDlg->delayedDestruct();
- itsDlg=NULL;
- }
- }
-
- bool KDialogDClient::readData(TQCString &buffer, int size)
- {
- buffer.resize(size);
- return ::readBlock(itsFd, buffer.data(), size);
- }
-
- bool KDialogDClient::readString(TQString &str)
- {
- int size;
-
- if(!readData((char *)&size, 4))
- return false;
-
- TQCString buffer;
- buffer.resize(size);
-
- if(!readData(buffer.data(), size))
- return false;
-
- str=TQString::fromUtf8(buffer.data());
- return true;
- }
-
- bool KDialogDClient::writeString(const TQString &str)
- {
- TQCString utf8(str.utf8());
-
- int size=utf8.length()+1;
-
- return writeData((char *)&size, 4) && writeData(utf8.data(), size);
- }
-
- void KDialogDClient::initDialog(const TQString &caption, KDialogBase *d, unsigned int xid)
- {
- itsAccepted=false;
- itsDlg=d;
-
- if(!caption.isEmpty())
- itsDlg->setPlainCaption(caption);
-
- if(xid)
- {
- #ifdef USE_KWIN
- KWin::setMainWindow(itsDlg, xid);
- KWin::setState(itsDlg->winId(), NET::Modal);
-
- KWin::WindowInfo wi(KWin::windowInfo(xid, NET::WMGeometry, NET::WM2UserTime));
- TQRect geom(wi.geometry());
- int rx=geom.x(),
- ry=geom.y();
-
- rx=(rx+(geom.width()/2))-(itsDlg->width()/2);
- if(rx<0)
- rx=0;
- ry=(ry+(geom.height()/2))-(itsDlg->height()/2);
- if(ry<0)
- ry=0;
- itsDlg->move(rx, ry);
- #else
- XWindowAttributes attr;
- int rx, ry;
- Window juntwin;
-
- XSetTransientForHint(tqt_xdisplay(), itsDlg->winId(), xid);
- if(XGetWindowAttributes(tqt_xdisplay(), xid, &attr))
- {
- XTranslateCoordinates(tqt_xdisplay(), xid, attr.root,
- -attr.border_width, -16,
- &rx, &ry, &juntwin);
-
- rx=(rx+(attr.width/2))-(itsDlg->width()/2);
- if(rx<0)
- rx=0;
- ry=(ry+(attr.height/2))-(itsDlg->height()/2);
- if(ry<0)
- ry=0;
- itsDlg->move(rx, ry);
- }
- #endif
- }
-
- connect(itsDlg, TQT_SIGNAL(ok(const TQStringList &)), this, TQT_SLOT(ok(const TQStringList &)));
- connect(itsDlg, TQT_SIGNAL(finished()), this, TQT_SLOT(finished()));
- itsDlg->show();
- }
-
- KDialogDFileDialog::KDialogDFileDialog(TQString &an, Operation op, const TQString &startDir,
- const TQString &filter, bool confirmOw)
- : KFileDialog(startDir.isEmpty() || "~"==startDir ? TQDir::homeDirPath() : startDir,
- filter, NULL, NULL, false),
- itsConfirmOw(confirmOw),
- itsAppName(an)
- {
- kdDebug() << "startDir:" << startDir << endl;
-
- switch(op)
- {
- case OP_FILE_OPEN:
- setOperationMode(KFileDialog::Opening);
- setMode((KFile::Mode)(KFile::File | KFile::ExistingOnly));
- break;
- case OP_FILE_OPEN_MULTIPLE:
- setOperationMode(KFileDialog::Opening);
- setMode((KFile::Mode)(KFile::Files | KFile::ExistingOnly));
- break;
- case OP_FILE_SAVE:
- setOperationMode(KFileDialog::Saving);
- setMode(KFile::File);
- break;
- default:
- break;
- }
-
- if(KDialogD::config())
- {
- TQString oldGrp(KDialogD::config()->group()),
- grp(groupName(itsAppName));
- TQSize defaultSize(600, 400);
-
- readConfig(KDialogD::config(), grp);
- KDialogD::config()->setGroup(grp);
- resize(KDialogD::config()->readSizeEntry(CFG_KEY_DIALOG_SIZE, &defaultSize));
- KDialogD::config()->setGroup(oldGrp);
- }
-
- ops->clearHistory();
- }
-
- void KDialogDFileDialog::accept()
- {
- kdDebug() << "KDialogDFileDialog::accept" << endl;
- }
-
- void KDialogDFileDialog::slotOk()
- {
- setResult(TQDialog::Accepted);
- KFileDialog::slotOk();
-
- kdDebug() << "KDialogDFileDialog::slotOk" << endl;
- KURL::List urls;
- TQStringList items;
- bool good=true;
-
- if(mode()&KFile::Files)
- urls=selectedURLs();
- else if(!locationEdit->currentText().isEmpty())
- urls.append(selectedURL());
-
- if(urls.count())
- {
- urls2Local(urls, items, this);
-
- if(urls.count()!=items.count())
- {
- KMessageBox::sorry(this, i18n("You can only select local files."),
- i18n("Remote Files Not Accepted"));
- good=false;
- }
- else if(itsConfirmOw && KFileDialog::Saving==operationMode())
- good=!TDEIO::NetAccess::exists(urls.first(), false, this) ||
- KMessageBox::Continue==KMessageBox::warningContinueCancel(this,
- i18n("File %1 exists.\nDo you want to replace it?")
- .arg(urls.first().prettyURL()),
- i18n("File Exists"),
- KGuiItem(i18n("Replace"), "document-save-as"), TQString(),
- KMessageBox::Notify|KMessageBox::PlainCaption);
-
- if(good)
- {
- TQString filter(currentFilter());
-
- if(!filter.isEmpty())
- items.append(filter);
-
- emit ok(items);
- hide();
- KFileDialog::accept();
- }
- else
- setResult(TQDialog::Rejected);
- }
- }
-
- KDialogDFileDialog::~KDialogDFileDialog()
- {
- kdDebug() << "~KDialogDFileDialog" << endl;
-
- if(KDialogD::config())
- {
- TQString oldGrp(KDialogD::config()->group()),
- grp(groupName(itsAppName));
-
- writeConfig(KDialogD::config(), grp);
- KDialogD::config()->setGroup(grp);
- KDialogD::config()->writeEntry(CFG_KEY_DIALOG_SIZE, size());
- KDialogD::config()->setGroup(oldGrp);
- }
- }
-
- KDialogDDirSelectDialog::KDialogDDirSelectDialog(TQString &an, const TQString &startDir, bool localOnly,
- TQWidget *parent, const char *name, bool modal)
- : KDirSelectDialog(startDir.isEmpty() || "~"==startDir
- ? TQDir::homeDirPath() : startDir,
- localOnly, parent, name, modal),
- itsAppName(an)
- {
- kdDebug() << "startDir:" << startDir << endl;
-
- if(KDialogD::config())
- {
- TQString oldGrp(KDialogD::config()->group()),
- grp(groupName(itsAppName, false));
- TQSize defaultSize(600, 400);
-
- //readConfig(KDialogD::config(), grp);
- KDialogD::config()->setGroup(grp);
- resize(KDialogD::config()->readSizeEntry(CFG_KEY_DIALOG_SIZE, &defaultSize));
- KDialogD::config()->setGroup(oldGrp);
- }
- }
-
- KDialogDDirSelectDialog::~KDialogDDirSelectDialog()
- {
- kdDebug() << "~KDialogDDirSelectDialog" << endl;
-
- if(KDialogD::config())
- {
- TQString oldGrp(KDialogD::config()->group()),
- grp(groupName(itsAppName, false));
-
- //writeConfig(KDialogD::config(), grp);
- KDialogD::config()->setGroup(grp);
- KDialogD::config()->writeEntry(CFG_KEY_DIALOG_SIZE, size());
- KDialogD::config()->setGroup(oldGrp);
- }
- }
-
- void KDialogDDirSelectDialog::slotOk()
- {
- kdDebug() << "KDialogDDirSelectDialog::slotOk" << endl;
-
- KURL::List urls;
- TQStringList items;
-
- urls.append(url());
- urls2Local(urls, items, this);
-
- if(urls.count()!=items.count())
- KMessageBox::sorry(this, i18n("You can only select local folders."),
- i18n("Remote Folders Not Accepted"));
- else
- {
- emit ok(items);
- hide();
- }
- }
-
- #ifdef KDIALOGD_APP
- static TDEAboutData aboutData("kdialogd3", I18N_NOOP("KDialog Daemon"), VERSION,
- I18N_NOOP("Use TDE dialogs from non-TDE apps."),
- TDEAboutData::License_GPL,
- I18N_NOOP("(c) Craig Drummond, 2006-2007"));
-
- int main(int argc, char **argv)
- {
- TDECmdLineArgs::init(argc, argv, &aboutData);
-
- KUniqueApplication *app=new KUniqueApplication;
- KDialogD kdialogd;
- int rv=app->exec();
-
- delete app;
-
- unlink(getSockName());
- releaseLock();
- return rv;
- }
- #else
- extern "C"
- {
- KDE_EXPORT KDEDModule *create_kdialogd(const TQCString &obj)
- {
- return new KDialogDKDED(obj);
- }
- };
-
- KDialogDKDED::KDialogDKDED(const TQCString &obj)
- : KDEDModule(obj)
- {
- new KDialogD(this);
- }
- #endif
-
- #include "kdialogd.moc"
-
|