summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-09-09 20:27:19 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-09-09 20:27:19 +0000
commitc6ca83d07d95e076b09bd802f66ba72d363b0235 (patch)
treef13000febb0c9c5a5da621b4bba53ba3eace022e /common
downloadkgtk-qt3-c6ca83d07d95e076b09bd802f66ba72d363b0235.tar.gz
kgtk-qt3-c6ca83d07d95e076b09bd802f66ba72d363b0235.zip
* Added kgtk-qt3
* Slight kpowersave message cleanup git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kgtk-qt3@1173604 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'common')
-rw-r--r--common/common.h237
-rw-r--r--common/connect.h311
2 files changed, 548 insertions, 0 deletions
diff --git a/common/common.h b/common/common.h
new file mode 100644
index 0000000..ca246b9
--- /dev/null
+++ b/common/common.h
@@ -0,0 +1,237 @@
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#define KDIALOGD_APP
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include "config.h"
+
+#ifdef __KDIALOGD_H__
+#include <kstandarddirs.h>
+#endif
+
+typedef enum
+{
+ OP_NULL = 0,
+ OP_FILE_OPEN = 1,
+ OP_FILE_OPEN_MULTIPLE = 2,
+ OP_FILE_SAVE = 3,
+ OP_FOLDER = 4
+} Operation;
+
+#define PID_DIR "kde-"
+#define PID_NAME "kdialogd.pid"
+
+static const char * getPidFileName()
+{
+ static char *pidfile=NULL;
+
+ if(!pidfile)
+ {
+ char *user=getenv("USER");
+
+ if(!user)
+ user=getenv("LOGNAME");
+
+ if(user)
+ {
+ char *tmp=getenv("KDETMP");
+
+ if(!tmp || !tmp[0])
+ tmp=getenv("TMPDIR");
+
+ if(!tmp || !tmp[0])
+ tmp=(char *)"/tmp";
+
+ pidfile=(char *)malloc(strlen(tmp)+strlen(PID_DIR)+strlen(user)+strlen(PID_NAME)+1);
+ pidfile=(char *)malloc(strlen(tmp)+strlen("/")+strlen(PID_DIR)+strlen(user)+strlen("/")+strlen(PID_NAME)+1);
+
+#ifdef __KDIALOGD_H__
+ // We are kdialogd - so create socket folder if it does not exist...
+ sprintf(pidfile, "%s/%s%s", tmp, PID_DIR, user);
+ KStandardDirs::makeDir(QString::fromAscii(pidfile));
+#endif
+
+ /* CPD: TODO get dispaly number! */
+ sprintf(pidfile, "%s/%s%s/%s", tmp, PID_DIR, user, PID_NAME);
+ }
+ }
+
+ return pidfile;
+}
+
+#define SOCK_DIR "ksocket-"
+#define SOCK_NAME "kdialogd"
+
+static const char * getSockName()
+{
+ static char *sock=NULL;
+
+ if(!sock)
+ {
+ char *user=getenv("USER");
+
+ if(!user)
+ user=getenv("LOGNAME");
+
+ if(user)
+ {
+ char *tmp=getenv("KDETMP");
+
+ if(!tmp || !tmp[0])
+ tmp=getenv("TMPDIR");
+
+ if(!tmp || !tmp[0])
+ tmp=(char *)"/tmp";
+
+ sock=(char *)malloc(strlen(tmp)+strlen("/")+strlen(SOCK_DIR)+strlen(user)+strlen("/")+strlen(SOCK_NAME)+strlen("18446744073709551616")+1);
+
+#ifdef __KDIALOGD_H__
+ // We are kdialogd - so create socket folder if it does not exist...
+ sprintf(sock, "%s/%s%s", tmp, SOCK_DIR, user);
+ KStandardDirs::makeDir(QString::fromAscii(sock));
+#endif
+
+ /* CPD: TODO get dispaly number! */
+ sprintf(sock, "%s/%s%s/%s-%d", tmp, SOCK_DIR, user, SOCK_NAME, 1);
+ }
+ }
+
+ return sock;
+}
+
+static int readBlock(int fd, char* pData, int size)
+{
+ int bytesToRead=size;
+
+ do
+ {
+ fd_set fdSet;
+
+ FD_ZERO(&fdSet);
+ FD_SET(fd, &fdSet);
+
+ if(select(fd + 1, &fdSet, NULL, NULL, NULL)<0)
+ return 0;
+
+ if(FD_ISSET(fd, &fdSet))
+ {
+ int bytesRead=read(fd, &pData[size-bytesToRead], bytesToRead);
+
+ if (bytesRead>0)
+ bytesToRead-=bytesRead;
+ else
+ return 0;
+ }
+ }
+ while(bytesToRead>0);
+
+ return 1;
+}
+
+static int writeBlock(int fd, const char *pData, int size)
+{
+ int bytesToWrite=size;
+
+ do
+ {
+ fd_set fdSet;
+
+ FD_ZERO(&fdSet);
+ FD_SET(fd, &fdSet);
+
+ if(select(fd + 1, NULL, &fdSet, NULL, NULL)<0)
+ return 0;
+
+ if(FD_ISSET(fd, &fdSet))
+ {
+ int bytesWritten=write(fd, (char *)&pData[size-bytesToWrite], bytesToWrite);
+
+ if (bytesWritten>0)
+ bytesToWrite-=bytesWritten;
+ else
+ return 0;
+ }
+ }
+ while(bytesToWrite>0);
+
+ return 1;
+}
+
+#ifdef KDIALOGD_APP
+/*
+ So that kdailogd can terminate when the last app exits, need a way of synchronising the Gtk/Qt
+ apps that may wish to connect, and the removal of the socket.
+
+ To this en, a lockfile is created,and used to guard around the critical sections
+*/
+static int lockFd=-1;
+
+#define LOCK_EXT ".lock"
+
+const char * getLockName()
+{
+ static char *lockName=NULL;
+
+ if(!lockName)
+ {
+ const char *sock=getSockName();
+
+ if(sock)
+ {
+ lockName=(char *)malloc(strlen(sock)+strlen(LOCK_EXT)+1);
+ sprintf(lockName, "%s%s", sock, LOCK_EXT);
+ }
+ }
+
+ return lockName;
+}
+
+/* Lock is stale if it does not exist or is older than 2 seconds */
+static int isStale(const char *fname)
+{
+ struct stat stat_buf;
+
+ return 0!=stat(fname, &stat_buf) ||
+ abs(stat_buf.st_mtime-time(NULL))>2;
+}
+
+static int grabLock(int tries)
+{
+ do
+ {
+ lockFd=open(getLockName(), O_WRONLY | O_CREAT | O_EXCL, 0777);
+ if (lockFd<0 && errno==EEXIST)
+ {
+ /* Hmm, lock file already exists. Is it stale? */
+ if(isStale(getLockName()))
+ {
+ tries++; /* Increment tries so that we try again... */
+ unlink(getLockName());
+ }
+ else if(tries)
+ usleep(100000);
+ }
+ }
+ while(lockFd<0 && --tries);
+
+ return lockFd;
+}
+
+static void releaseLock()
+{
+ if(lockFd>0)
+ {
+ close(lockFd);
+ unlink(getLockName());
+ }
+}
+#endif
+
+#endif
diff --git a/common/connect.h b/common/connect.h
new file mode 100644
index 0000000..2499054
--- /dev/null
+++ b/common/connect.h
@@ -0,0 +1,311 @@
+#ifndef __CONNECT_H__
+#define __CONNECT_H__
+
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include "config.h"
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+
+#ifndef SUN_LEN
+#define SUN_LEN(ptr) ((socklen_t) (((struct sockaddr_un *) 0)->sun_path) \
+ + strlen ((ptr)->sun_path))
+#endif
+
+#include "common.h"
+#include "config.h"
+
+#ifdef __cplusplus
+typedef bool kgtk_bool;
+#define KGTK_TRUE true
+#define KGTK_FALSE false
+#else
+typedef gboolean kgtk_bool;
+#define KGTK_TRUE TRUE
+#define KGTK_FALSE FALSE
+#endif
+
+
+static int kdialogdSocket=-1;
+
+/* From kdelibs/kdesu */
+#ifdef KDIALOGD_APP
+static int createSocketConnectionReal()
+#else
+static int createSocketConnection()
+#endif
+{
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection A\n");
+#endif
+ int sockfd=-1;
+ const char *sock=getSockName();
+ struct sockaddr_un addr;
+
+ if (access(sock, R_OK|W_OK))
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - Could not access socket, %s\n", sock);
+#endif
+ return -1;
+ }
+
+ sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sockfd < 0)
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - Could not create socket, %d\n", errno);
+#endif
+ return -1;
+ }
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, sock);
+
+ if (connect(sockfd, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0)
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - Could not connect socket, %d\n", errno);
+#endif
+ close(sockfd);
+ return -1;
+ }
+
+#if !defined(SO_PEERCRED) || !defined(HAVE_STRUCT_UCRED)
+# if defined(HAVE_GETPEEREID)
+ {
+ uid_t euid;
+ gid_t egid;
+ /* Security: if socket exists, we must own it */
+ if (getpeereid(sockfd, &euid, &egid) == 0)
+ {
+ if (euid != getuid())
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", euid);
+#endif
+ close(sockfd);
+ return -1;
+ }
+ }
+ }
+# else
+# ifdef __GNUC__
+# warning "Using sloppy security checks"
+# endif
+ /* We check the owner of the socket after we have connected.
+ If the socket was somehow not ours an attacker will be able
+ to delete it after we connect but shouldn't be able to
+ create a socket that is owned by us. */
+ {
+ struct stat s;
+ if (lstat(sock, &s)!=0)
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - stat failed %s\n", sock);
+#endif
+ close(sockfd);
+ return -1;
+ }
+ if (s.st_uid != getuid())
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", s.st_uid);
+#endif
+ close(sockfd);
+ return -1;
+ }
+ if (!S_ISSOCK(s.st_mode))
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - socket is not a socket %s\n", sock);
+#endif
+ close(sockfd);
+ return -1;
+ }
+ }
+# endif
+#else
+ {
+ struct ucred cred;
+ socklen_t siz = sizeof(cred);
+
+ /* Security: if socket exists, we must own it */
+ if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) == 0)
+ {
+ if (cred.uid != getuid())
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - socket not owned by me! socket uid %d\n", cred.uid);
+#endif
+ close(sockfd);
+ return -1;
+ }
+ }
+ }
+#endif
+
+#ifdef KGTK_DEBUG
+ printf("KGTK::createSocketConnection - sockfd:%d\n", sockfd);
+#endif
+ return sockfd;
+}
+
+#ifdef KDIALOGD_APP
+static int createSocketConnection()
+{
+ int rv=-1,
+ tries=0;
+
+ do
+ {
+ if(-1==(rv=createSocketConnectionReal()))
+ usleep(10000);
+ }
+ while(-1==rv && ++tries<50);
+
+ if(-1==rv)
+ fprintf(stderr, "ERROR: Could not talk to KDialogD!!!\n");
+ return rv;
+}
+#endif
+
+static int kdialogdPid=-1;
+
+static kgtk_bool processIsRunning()
+{
+#ifdef KGTK_DEBUG
+ printf("KGTK::processIsRunning\n");
+#endif
+
+ if(-1!=kdialogdPid && 0==kill(kdialogdPid, 0))
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::processIsRunning (%d) YES\n", kdialogdPid);
+#endif
+ return KGTK_TRUE;
+ }
+ else
+ {
+ FILE *f=fopen(getPidFileName(), "r");
+
+ if(f)
+ {
+ int pid=0;
+
+ if(1==fscanf(f, "%d", &pid))
+ {
+ fclose(f);
+
+ if(-1!=kdialogdPid && kdialogdPid!=pid)
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::processIsRunning pid has changed from:%d to %d - need to reconnect\n", kdialogdPid, pid);
+#endif
+ kdialogdPid=pid;
+ return KGTK_FALSE;
+ }
+#ifdef KGTK_DEBUG
+ printf("KGTK::processIsRunning file has pid:%d\n", pid);
+#endif
+ if(0==kill(pid, 0))
+ {
+#ifdef KGTK_DEBUG
+ printf("KGTK::processIsRunning (file:%d) YES\n", pid);
+#endif
+ kdialogdPid=pid;
+ return KGTK_TRUE;
+ }
+
+ kdialogdPid=-1; /* Process is not running! */
+ }
+ }
+ }
+#ifdef KGTK_DEBUG
+ printf("KGTK::processIsRunning NO\n");
+#endif
+ return KGTK_FALSE;
+}
+
+static void closeConnection()
+{
+#ifdef KGTK_DEBUG
+ printf("KGTK::closeConnection\n");
+#endif
+ close(kdialogdSocket);
+ kdialogdSocket=-1;
+}
+
+/* Note: Calling 'fork' seems to mess things up with eclipse! */
+#define KGTK_USE_SYSTEM_CALL
+
+static kgtk_bool connectToKDialogD(const char *appName)
+{
+#ifdef KGTK_DEBUG
+ printf("KGTK::connectToKDialogD %s\n", appName ? appName : "<null>");
+#endif
+ if(!processIsRunning())
+ closeConnection();
+
+ if(-1!=kdialogdSocket)
+ return KGTK_TRUE;
+ else
+ {
+ unsigned int slen=strlen(appName);
+ kgtk_bool rv=KGTK_TRUE;
+
+ if(slen)
+ slen++;
+
+#ifdef KGTK_DEBUG
+ printf("KGTK::connectToKDialogD - start wrapper\n");
+#endif
+
+#ifdef KDIALOGD_APP
+ grabLock(5);
+#ifdef KGTK_USE_SYSTEM_CALL
+ system("kdialogd-wrapper &");
+#else
+ switch(fork())
+ {
+ case -1:
+ rv=KGTK_FALSE;
+ printf("ERROR: Could not start fork :-(\n");
+ break;
+ case 0:
+ execl(KDIALOGD_LOCATION"/kdialogd-wrapper", "kdialogd-wrapper", (char *)NULL);
+ break;
+ default:
+ {
+ int status=0;
+ wait(&status);
+ }
+ }
+#endif
+ releaseLock();
+#endif
+
+ if(!rv)
+ return rv;
+
+ rv=
+#ifdef KDIALOGD_APP
+ grabLock(3)>0 &&
+#else
+ 0==system("dcop kded kded loadModule kdialogd") &&
+#endif
+ -1!=(kdialogdSocket=createSocketConnection()) &&
+ writeBlock(kdialogdSocket, (char *)&slen, 4) &&
+ (0==slen || writeBlock(kdialogdSocket, appName, slen));
+#ifdef KDIALOGD_APP
+ releaseLock();
+#endif
+ return rv;
+ }
+}
+
+#endif