File indexing completed on 2024-04-21 15:55:40

0001 /***************************************************************************
0002     begin                : Sat Sept 9 2003
0003     edit         : Wed Jan 14 2009
0004     copyright            : (C) 2003 by Jeroen Wijnhout, 2007-2009 by Thomas Braun
0005     email                : Jeroen.Wijnhout@kdemail.net
0006  ***************************************************************************/
0007 
0008 /***************************************************************************
0009  *                                                                         *
0010  *   This program is free software; you can redistribute it and/or modify  *
0011  *   it under the terms of the GNU General Public License as published by  *
0012  *   the Free Software Foundation; either version 2 of the License, or     *
0013  *   (at your option) any later version.                                   *
0014  *                                                                         *
0015  ***************************************************************************/
0016 
0017 #include "kilelyxserver.h"
0018 
0019 #include <sys/stat.h>
0020 #include <stdlib.h> //getenv
0021 #ifndef _MSC_VER
0022 #include <unistd.h> //read
0023 #else
0024 #include <io.h>
0025 #endif
0026 #include <fcntl.h>
0027 
0028 #include "kileactions.h"
0029 #include "kiledebug.h"
0030 
0031 #include <QDir>
0032 #include <QFile>
0033 #include <QFileInfo>
0034 #include <QSocketNotifier>
0035 #include <QRegExp>
0036 
0037 #include <KLocalizedString>
0038 
0039 KileLyxServer::KileLyxServer(bool startMe) :
0040     m_running(false)
0041 {
0042 #ifndef _MSC_VER
0043     m_perms = S_IRUSR | S_IWUSR;
0044 #else
0045     m_perms = 0;
0046 #endif
0047     KILE_DEBUG_MAIN << "===KileLyxServer::KileLyxServer(bool" << startMe << ")=== ";
0048 
0049     m_tempDir = new QTemporaryDir();
0050     if(!m_tempDir->isValid()) {
0051         KILE_DEBUG_MAIN << "an error occurred while creating a tempfile" ;
0052         return;
0053     }
0054 
0055     m_links << ".lyxpipe.in" << ".lyx/lyxpipe.in";
0056     m_links << ".lyxpipe.out" << ".lyx/lyxpipe.out";
0057 
0058     for(int i = 0; i < m_links.count() ; ++i) {
0059         m_pipes.append( m_tempDir->path() + QDir::separator() + m_links[i] );
0060         m_links[i].prepend(QDir::homePath() + QDir::separator() );
0061         KILE_DEBUG_MAIN << "m_pipes[" << i << "]=" << m_pipes[i];
0062         KILE_DEBUG_MAIN << "m_links[" << i << "]=" << m_links[i];
0063     }
0064 
0065     if(startMe) {
0066         start();
0067     }
0068 }
0069 
0070 KileLyxServer::~KileLyxServer()
0071 {
0072     stop();
0073     removePipes();
0074 
0075     delete m_tempDir;
0076 
0077     for(QList<QFile*>::iterator i = m_pipeIn.begin(); i != m_pipeIn.end(); ++i) {
0078         delete *i;
0079     }
0080 
0081     for(QList<QSocketNotifier*>::iterator i = m_notifier.begin(); i != m_notifier.end(); ++i) {
0082         delete *i;
0083     }
0084 }
0085 
0086 bool KileLyxServer::start()
0087 {
0088     if (m_running) {
0089         stop();
0090     }
0091 
0092     KILE_DEBUG_MAIN << "Starting the LyX server...";
0093 
0094     if (openPipes()) {
0095         QSocketNotifier *notifier;
0096         for(QList<QFile*>::iterator it = m_pipeIn.begin(); it != m_pipeIn.end(); ++it) {
0097             if ((*it)->fileName().right(3) == ".in" ) {
0098                 notifier = new QSocketNotifier((*it)->handle(), QSocketNotifier::Read, this);
0099                 connect(notifier, SIGNAL(activated(int)), this, SLOT(receive(int)));
0100                 m_notifier.append(notifier);
0101                 KILE_DEBUG_MAIN << "Created notifier for " << (*it)->fileName();
0102             }
0103             else {
0104                 KILE_DEBUG_MAIN << "No notifier created for " << (*it)->fileName();
0105             }
0106         }
0107         m_running=true;
0108     }
0109 
0110     return m_running;
0111 }
0112 
0113 bool KileLyxServer::openPipes()
0114 {
0115     KILE_DEBUG_MAIN << "===bool KileLyxServer::openPipes()===";
0116 
0117 #ifdef Q_OS_WIN
0118     qCritical() << "kile's lyx server can not work on windows since we don't have pipes";
0119     qCritical() << "And also lyx itself does not support it, see  https://wiki.lyx.org/LyX/LyXServer";
0120     return false;
0121 #else
0122     bool opened = false;
0123     QFileInfo pipeInfo,linkInfo;
0124     QFile *file;
0125     struct stat buf;
0126     struct stat *stats = &buf;
0127 
0128     QDir lyxDir(QDir::homePath() + QDir::separator() + ".lyx");
0129     if(!lyxDir.exists()) {
0130         KILE_DEBUG_MAIN << "Directory " << lyxDir.absolutePath() << " does not exist";
0131         if(mkdir(QFile::encodeName( lyxDir.path() ), m_perms | S_IXUSR) == -1) {
0132             qCritical() << "Could not create directory";
0133         }
0134         else {
0135             KILE_DEBUG_MAIN << "Directory created successfully";
0136         }
0137     }
0138 
0139     for(int i = 0; i < m_pipes.count(); ++i) {
0140         pipeInfo.setFile(m_pipes[i]);
0141         linkInfo.setFile(m_links[i]);
0142 
0143         QFile::remove(linkInfo.absoluteFilePath());
0144         linkInfo.refresh();
0145 
0146         KILE_DEBUG_MAIN << "pipe=" << m_pipes[i] << Qt::endl;
0147         KILE_DEBUG_MAIN << "link=" << m_links[i] << Qt::endl;
0148 
0149         if(!pipeInfo.exists()) {
0150             //create the dir first
0151             if(!QFileInfo::exists(pipeInfo.absolutePath())) {
0152                 if(mkdir(QFile::encodeName( pipeInfo.path() ), m_perms | S_IXUSR) == -1) {
0153                     qCritical() << "Could not create directory for pipe";
0154                     continue;
0155                 }
0156                 else {
0157                     KILE_DEBUG_MAIN << "Created directory " << pipeInfo.path();
0158                 }
0159             }
0160             if (mkfifo(QFile::encodeName( pipeInfo.absoluteFilePath() ), m_perms) != 0) {
0161                 qCritical() << "Could not create pipe: " << pipeInfo.absoluteFilePath();
0162                 continue;
0163             }
0164             else {
0165                 KILE_DEBUG_MAIN << "Created pipe: " << pipeInfo.absoluteFilePath();
0166             }
0167         }
0168 
0169         if(symlink(QFile::encodeName(pipeInfo.absoluteFilePath()),QFile::encodeName(linkInfo.absoluteFilePath())) != 0) {
0170             qCritical() << "Could not create symlink: " << linkInfo.absoluteFilePath() << " --> " << pipeInfo.absoluteFilePath();
0171             continue;
0172         }
0173 
0174         // the file object will be deleted at the shutdown of the server in KileLyxServer::stop()
0175         file  = new QFile(pipeInfo.absoluteFilePath());
0176         pipeInfo.refresh();
0177 
0178         if(pipeInfo.exists() && file->open(QIODevice::ReadWrite)) { // in that order we don't create the file if it does not exist
0179             KILE_DEBUG_MAIN << "Opened file: " << pipeInfo.absoluteFilePath();
0180             fstat(file->handle(),stats);
0181             if(!S_ISFIFO(stats->st_mode)) {
0182                 qCritical() << "The file " << pipeInfo.absoluteFilePath() <<  "we just created is not a pipe!";
0183                 file->close();
0184                 delete file;
0185                 continue;
0186             }
0187             else {
0188                 m_pipeIn.append(file);
0189                 m_file.insert(file->handle(), file);
0190                 opened = true;
0191                 KILE_DEBUG_MAIN << "everything is correct :)" << Qt::endl;
0192             }
0193         }
0194         else {
0195             qCritical() << "Could not open " << pipeInfo.absoluteFilePath();
0196         }
0197     }
0198     return opened;
0199 #endif
0200 }
0201 
0202 void KileLyxServer::stop()
0203 {
0204     KILE_DEBUG_MAIN << "Stopping the LyX server...";
0205 
0206     for(QList<QFile*>::iterator it = m_pipeIn.begin(); it != m_pipeIn.end(); ++it) {
0207         (*it)->close();
0208         delete *it;
0209     }
0210 
0211     for(QList<QSocketNotifier*>::iterator i = m_notifier.begin(); i != m_notifier.end(); ++i) {
0212         delete *i;
0213     }
0214 
0215     m_pipeIn.clear();
0216     m_notifier.clear();
0217 
0218     m_running=false;
0219 }
0220 
0221 void KileLyxServer::removePipes()
0222 {
0223     for (int i = 0; i < m_links.count(); ++i) {
0224         QFile::remove(m_links[i]);
0225     }
0226     for (int i = 0; i < m_pipes.count(); ++i) {
0227         QFile::remove(m_pipes[i]);
0228     }
0229 }
0230 
0231 void KileLyxServer::processLine(const QString &line)
0232 {
0233     KILE_DEBUG_MAIN << "===void KileLyxServer::processLine(const QString " << line << ")===";
0234 
0235     QRegExp reCite(":citation-insert:(.*)$");
0236     QRegExp reBibtexdbadd(":bibtex-database-add:(.*)$");
0237     QRegExp rePaste(":paste:(.*)$");
0238 
0239     if(line.indexOf(reCite) != -1) {
0240         emit(insert(KileAction::TagData(i18n("Cite"), "\\cite{"+reCite.cap(1)+'}')));
0241     }
0242     else if(line.indexOf(reBibtexdbadd) != -1) {
0243         emit(insert(KileAction::TagData(i18n("Add BibTeX database"), "\\bibliography{"+ reBibtexdbadd.cap(1) + '}')));
0244     }
0245     else if(line.indexOf(rePaste) != -1) {
0246         emit(insert(KileAction::TagData(i18n("Paste"), rePaste.cap(1))));
0247     }
0248 }
0249 
0250 void KileLyxServer::receive(int fd)
0251 {
0252     if(m_file[fd]) {
0253         int bytesRead;
0254         int const size = 256;
0255         char buffer[size];
0256         if((bytesRead = read(fd, buffer, size - 1)) > 0) {
0257             buffer[bytesRead] = '\0'; // turn it into a c string
0258             QStringList cmds = QString(buffer).trimmed().split('\n');
0259             for(int i = 0; i < cmds.count(); ++i) {
0260                 processLine(cmds[i]);
0261             }
0262         }
0263     }
0264 }
0265