sbMediaExportITunesAgentService.cpp
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2009 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25 */
26 
28 
29 #include <nsAppDirectoryServiceDefs.h>
30 #include <nsDirectoryServiceUtils.h>
31 #include <nsIProcess.h>
32 #include <nsIFileURL.h>
33 #include <nsNetUtil.h>
34 
35 #ifdef XP_MACOSX
36 #include <CoreServices/CoreServices.h>
37 #include <ApplicationServices/ApplicationServices.h>
38 #include "nsILocalFileMac.h"
39 #include <sys/types.h>
40 #include <sys/sysctl.h>
41 #include <signal.h>
42 #include <vector>
43 #include <string>
44 #elif XP_WIN
45 #include <windows.h>
46 #endif
47 
48 #ifdef XP_MACOSX
49 //------------------------------------------------------------------------------
50 // BSD System Process Helper methods
51 
52 typedef std::vector<pid_t> sbPIDVector;
53 typedef sbPIDVector::const_iterator sbPIDVectorIter;
54 
56 GetPidName(pid_t aPid)
57 {
58  std::string processName;
59 
60  int mib[] = {
61  CTL_KERN,
62  KERN_PROCARGS,
63  aPid
64  };
65 
66  // Get the size of the buffer needed for the process name.
67  size_t dataLength = 0;
68  if (sysctl(mib, 3, NULL, &dataLength, NULL, 0) >= 0) {
69  // Get the full path of the execYESutable.
70  char processPathStr[dataLength];
71  if (sysctl(mib, 3, &processPathStr[0], &dataLength, NULL, 0) >= 0) {
72  // Find the last part of the path to get the executable name.
73  std::string processPath(processPathStr);
74  size_t lastSlashIndex = processPath.rfind('/');
75  if (lastSlashIndex != std::string::npos) {
76  processName = processPath.substr(lastSlashIndex + 1);
77  }
78  }
79  }
80 
81  return processName;
82 }
83 
84 nsresult
85 GetActiveProcessesByName(const std::string & aProcessName,
86  sbPIDVector & aOutVector)
87 {
88  static int mib[] = {
89  CTL_KERN,
90  KERN_PROC,
91  KERN_PROC_UID,
92  geteuid()
93  };
94 
95  // Get the size of the kinfo_proc array buffer.
96  size_t bufferLength = 0;
97  if (sysctl(mib, 4, NULL, &bufferLength, NULL, 0) < 0) {
98  return NS_ERROR_FAILURE;
99  }
100 
101  // Create a buffer large enough to hold the list of |kinfo_proc| structs.
102  struct kinfo_proc *kp = (struct kinfo_proc *)malloc(bufferLength);
103  NS_ENSURE_TRUE(kp != NULL, NS_ERROR_OUT_OF_MEMORY);
104 
105  // Get the full list of |kinfo_proc| structs using the newly created buffer.
106  if (sysctl(mib, 4, kp, &bufferLength, NULL, 0) < 0) {
107  free(kp);
108  return NS_ERROR_FAILURE;
109  }
110 
111  PRInt32 entries = bufferLength / sizeof(struct kinfo_proc);
112  if (entries == 0) {
113  free(kp);
114  return NS_ERROR_FAILURE;
115  }
116 
117  for (PRInt32 i = entries; i >= 0; i--) {
118  std::string curProcessName = GetPidName((&kp[i])->kp_proc.p_pid);
119  if (curProcessName.compare(aProcessName) == 0) {
120  aOutVector.push_back((&kp[i])->kp_proc.p_pid);
121  }
122  }
123 
124  free(kp);
125  return NS_OK;
126 }
127 
128 #endif
129 
132 
134 {
135 }
136 
138 {
139 }
140 
141 NS_IMETHODIMP
142 sbMediaExportITunesAgentService::StartExportAgent()
143 {
144  return RunAgent(PR_FALSE);
145 }
146 
147 NS_IMETHODIMP
148 sbMediaExportITunesAgentService::UnregisterExportAgent()
149 {
150  return RunAgent(PR_TRUE);
151 }
152 
153 nsresult
155 {
156  nsresult rv;
157  nsCOMPtr<nsIURI> agentParentFolderURI;
158  rv = NS_NewURI(getter_AddRefs(agentParentFolderURI),
159  NS_LITERAL_STRING("resource://app"));
160  NS_ENSURE_SUCCESS(rv, rv);
161 
162  nsCOMPtr<nsIFileURL> parentFolderFileURL =
163  do_QueryInterface(agentParentFolderURI, &rv);
164  NS_ENSURE_SUCCESS(rv, rv);
165 
166  nsCOMPtr<nsIFile> agentFile;
167  rv = parentFolderFileURL->GetFile(getter_AddRefs(agentFile));
168  NS_ENSURE_SUCCESS(rv, rv);
169 
170  nsCOMPtr<nsIFile> appRegD;
171  rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
172  getter_AddRefs(appRegD));
173  NS_ENSURE_SUCCESS(rv, rv);
174 
175  nsString leafName;
176  rv = appRegD->GetLeafName(leafName);
177  NS_ENSURE_SUCCESS(rv, rv);
178 
179  NS_ConvertUTF16toUTF8 profile(leafName);
180 
181 #ifdef XP_MACOSX
182  // OS X is a little trickier since the agent needs to be started using
183  // LaunchServices and not using the path to the binary.
184  rv = agentFile->Append(NS_LITERAL_STRING("songbirditunesagent.app"));
185  NS_ENSURE_SUCCESS(rv, rv);
186 
187  nsCOMPtr<nsILocalFileMac> agentMacFile =
188  do_QueryInterface(agentFile, &rv);
189  NS_ENSURE_SUCCESS(rv, rv);
190 
191  FSRef agentFSRef;
192  rv = agentMacFile->GetFSRef(&agentFSRef);
193 
194  CFArrayRef argv = nsnull;
195  // Sadly, argv is a |CFArrayRef| so push the args into a
196  // CoreFoundation array.
197  if (aShouldUnregister) {
198  CFStringRef arg[1];
199  arg[0] = CFStringCreateWithCString(kCFAllocatorDefault,
200  "--unregister",
201  kCFStringEncodingUTF8);
202  argv = CFArrayCreate(kCFAllocatorDefault,
203  (const void **)arg,
204  1,
205  NULL); // callback
206  } else {
207  CFStringRef arg[2];
208  arg[0] = CFStringCreateWithCString(kCFAllocatorDefault,
209  "--profile",
210  kCFStringEncodingUTF8);
211  arg[1] = CFStringCreateWithCString(kCFAllocatorDefault,
212  NS_ConvertUTF16toUTF8(profile).get(),
213  kCFStringEncodingUTF8);
214  argv = CFArrayCreate(kCFAllocatorDefault,
215  (const void **)arg,
216  2,
217  NULL); // callback
218  }
219 
220  LSApplicationParameters appParams = {
221  0, // version
222  kLSLaunchDefaults, // launch flags
223  &agentFSRef, // app FSRef
224  nsnull, // asyncLaunchRefCon
225  nsnull, // enviroment variables
226  argv, // argv CFArrayRef
227  nsnull, // initial apple event
228  };
229 
230  ProcessSerialNumber outPSN;
231  OSStatus err = LSOpenApplication(&appParams, &outPSN);
232  NS_ENSURE_TRUE(err == noErr, NS_ERROR_FAILURE);
233 
234  CFRelease(argv);
235 
236 #elif XP_WIN
237  // Windows is simple, simply append the name of the agent + '.exe'
238  rv = agentFile->Append(NS_LITERAL_STRING("songbirditunesagent.exe"));
239  NS_ENSURE_SUCCESS(rv, rv);
240 
241  nsCOMPtr<nsIProcess> agentProcess =
242  do_CreateInstance(NS_PROCESS_CONTRACTID, &rv);
243  NS_ENSURE_SUCCESS(rv, rv);
244 
245  rv = agentProcess->Init(agentFile);
246  NS_ENSURE_SUCCESS(rv, rv);
247 
248  if (aShouldUnregister) {
249  const char* args[] = { "--unregister" };
250  rv = agentProcess->Run(PR_TRUE, args, 1); // only block for '--unregister'
251  NS_ENSURE_SUCCESS(rv, rv);
252  } else {
253  const char* args[] = { "--profile", profile.get() };
254  rv = agentProcess->Run(PR_FALSE, args, 2);
255  NS_ENSURE_SUCCESS(rv, rv);
256  }
257 #else
258  LOG(("%s: ERROR: Tried to start the export agent on a non-supported OS",
259  __FUNCTION__));
260 #endif
261 
262  return NS_OK;
263 }
264 
265 NS_IMETHODIMP
266 sbMediaExportITunesAgentService::GetIsAgentRunning(PRBool *aIsRunning)
267 {
268  NS_ENSURE_ARG_POINTER(aIsRunning);
269  *aIsRunning = PR_FALSE;
270 
271 #ifdef XP_MACOSX
272  sbPIDVector processes;
273  nsresult rv = GetActiveProcessesByName("songbirditunesagent", processes);
274  *aIsRunning = NS_SUCCEEDED(rv) && processes.size() > 0;
275 #elif XP_WIN
276  // The windows agent uses a mutex handle to prevent duplicate agents
277  // from running. Simply check for the mutex to find out if the agent
278  // is currently running.
279  HANDLE hMutex = OpenMutex(SYNCHRONIZE, PR_TRUE, L"songbirditunesagent");
280  *aIsRunning = hMutex != nsnull;
281  if (hMutex) {
282  CloseHandle(hMutex);
283  }
284 #endif
285 
286  return NS_OK;
287 }
288 
289 NS_IMETHODIMP
290 sbMediaExportITunesAgentService::KillActiveAgents()
291 {
292  // The itunes agent has a "--kill" (or "--roundhouse") argument that
293  // will kill all the active agents for us. Simply get the file spec to the
294  // platforms binary (we don't need to go through LS on macosx for this) and
295  // spawn a nsIProcess with the "--kill" argument.
296 
297  nsresult rv;
298  nsCOMPtr<nsIURI> agentParentFolderURI;
299  rv = NS_NewURI(getter_AddRefs(agentParentFolderURI),
300  NS_LITERAL_STRING("resource://app"));
301  NS_ENSURE_SUCCESS(rv, rv);
302 
303  nsCOMPtr<nsIFileURL> parentFolderFileURL =
304  do_QueryInterface(agentParentFolderURI, &rv);
305  NS_ENSURE_SUCCESS(rv, rv);
306 
307  nsCOMPtr<nsIFile> agentFile;
308  rv = parentFolderFileURL->GetFile(getter_AddRefs(agentFile));
309  NS_ENSURE_SUCCESS(rv, rv);
310 
311 #if XP_MACOSX
312  // Mac is slightly more tricky because we have to go inside the .app to
313  // find the physical binary.
314  nsString agentPath;
315  rv = agentFile->GetPath(agentPath);
316  NS_ENSURE_SUCCESS(rv, rv);
317 
318  agentPath.AppendLiteral("/songbirditunesagent.app/Contents/MacOS/songbirditunesagent");
319 
320  nsCOMPtr<nsILocalFileMac> macAgentFileSpec =
321  do_CreateInstance("@mozilla.org/file/local;1", &rv);
322  NS_ENSURE_SUCCESS(rv, rv);
323 
324  rv = macAgentFileSpec->InitWithPath(agentPath);
325  NS_ENSURE_SUCCESS(rv, rv);
326 
327  agentFile = do_QueryInterface(macAgentFileSpec, &rv);
328  NS_ENSURE_SUCCESS(rv, rv);
329 #elif XP_WIN
330  // Windows is simple, simply append the name of the agent + '.exe'
331  rv = agentFile->Append(NS_LITERAL_STRING("songbirditunesagent.exe"));
332  NS_ENSURE_SUCCESS(rv, rv);
333 #endif
334 
335  // Now that the platform specic chunk is done, spawn the process and wait
336  // for it to finish.
337  nsCOMPtr<nsIProcess> killProcess =
338  do_CreateInstance(NS_PROCESS_CONTRACTID, &rv);
339  NS_ENSURE_SUCCESS(rv, rv);
340 
341  rv = killProcess->Init(agentFile);
342  NS_ENSURE_SUCCESS(rv, rv);
343 
344  nsCString args("--kill");
345  const char *argsStr = args.get();
346 
347  // Run the agent with blocking turned on
348  rv = killProcess->Run(PR_TRUE, &argsStr, 1);
349  NS_ENSURE_SUCCESS(rv, rv);
350 
351  return NS_OK;
352 }
353 
var args
Definition: alert.js:8
return NS_OK
#define LOG(args)
nsresult RunAgent(PRBool aShouldUnregister)
NS_IMPL_ISUPPORTS1(sbMediaExportITunesAgentService, sbIMediaExportAgentService) sbMediaExportITunesAgentService
_getSelectedPageStyle s i