1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=2:tabstop=2:
3  */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 
8 #include "nsUnixRemoteServer.h"
9 #include "nsGTKToolkit.h"
10 #include "nsCOMPtr.h"
11 #include "nsICommandLineRunner.h"
12 #include "nsCommandLine.h"
13 #include "nsIFile.h"
14 
15 // Set desktop startup ID to the passed ID, if there is one, so that any created
16 // windows get created with the right window manager metadata, and any windows
17 // that get new tabs and are activated also get the right WM metadata.
18 // The timestamp will be used if there is no desktop startup ID, or if we're
19 // raising an existing window rather than showing a new window for the first
20 // time.
SetDesktopStartupIDOrTimestamp(const nsACString & aDesktopStartupID,uint32_t aTimestamp)21 void nsUnixRemoteServer::SetDesktopStartupIDOrTimestamp(
22     const nsACString& aDesktopStartupID, uint32_t aTimestamp) {
23   nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
24   if (!toolkit) return;
25 
26   if (!aDesktopStartupID.IsEmpty()) {
27     toolkit->SetDesktopStartupID(aDesktopStartupID);
28   }
29 
30   toolkit->SetFocusTimestamp(aTimestamp);
31 }
32 
FindExtensionParameterInCommand(const char * aParameterName,const nsACString & aCommand,char aSeparator,nsACString * aValue)33 static bool FindExtensionParameterInCommand(const char* aParameterName,
34                                             const nsACString& aCommand,
35                                             char aSeparator,
36                                             nsACString* aValue) {
37   nsAutoCString searchFor;
38   searchFor.Append(aSeparator);
39   searchFor.Append(aParameterName);
40   searchFor.Append('=');
41 
42   nsACString::const_iterator start, end;
43   aCommand.BeginReading(start);
44   aCommand.EndReading(end);
45   if (!FindInReadable(searchFor, start, end)) return false;
46 
47   nsACString::const_iterator charStart, charEnd;
48   charStart = end;
49   aCommand.EndReading(charEnd);
50   nsACString::const_iterator idStart = charStart, idEnd;
51   if (FindCharInReadable(aSeparator, charStart, charEnd)) {
52     idEnd = charStart;
53   } else {
54     idEnd = charEnd;
55   }
56   *aValue = nsDependentCSubstring(idStart, idEnd);
57   return true;
58 }
59 
HandleCommandLine(const char * aBuffer,uint32_t aTimestamp)60 const char* nsUnixRemoteServer::HandleCommandLine(const char* aBuffer,
61                                                   uint32_t aTimestamp) {
62   nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine());
63 
64   // the commandline property is constructed as an array of int32_t
65   // followed by a series of null-terminated strings:
66   //
67   // [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
68   // (offset is from the beginning of the buffer)
69 
70   int32_t argc = TO_LITTLE_ENDIAN32(*reinterpret_cast<const int32_t*>(aBuffer));
71   const char* wd = aBuffer + ((argc + 1) * sizeof(int32_t));
72 
73   nsCOMPtr<nsIFile> lf;
74   nsresult rv =
75       NS_NewNativeLocalFile(nsDependentCString(wd), true, getter_AddRefs(lf));
76   if (NS_FAILED(rv)) return "509 internal error";
77 
78   nsAutoCString desktopStartupID;
79 
80   const char** argv = (const char**)malloc(sizeof(char*) * argc);
81   if (!argv) return "509 internal error";
82 
83   const int32_t* offset = reinterpret_cast<const int32_t*>(aBuffer) + 1;
84 
85   for (int i = 0; i < argc; ++i) {
86     argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]);
87 
88     if (i == 0) {
89       nsDependentCString cmd(argv[0]);
90       FindExtensionParameterInCommand("DESKTOP_STARTUP_ID", cmd, ' ',
91                                       &desktopStartupID);
92     }
93   }
94 
95   rv = cmdline->Init(argc, argv, lf, nsICommandLine::STATE_REMOTE_AUTO);
96 
97   free(argv);
98   if (NS_FAILED(rv)) {
99     return "509 internal error";
100   }
101 
102   SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
103 
104   rv = cmdline->Run();
105 
106   if (NS_ERROR_ABORT == rv) return "500 command not parseable";
107 
108   if (NS_FAILED(rv)) return "509 internal error";
109 
110   return "200 executed command";
111 }
112