Esempio n. 1
0
/*	piano wrapper: prepare/execute http request and pass result back to
 *	libpiano (updates data structures)
 *	@param piano handle
 *	@param request type
 *	@param waitress handle
 *	@param data pointer (used as request data)
 *	@return 1 on success, 0 otherwise
 */
int BarUiPianoCall (PianoHandle_t *ph, PianoRequestType_t type,
		WaitressHandle_t *waith, void *data, PianoReturn_t *pRet,
		WaitressReturn_t *wRet) {
	PianoRequest_t req;

	memset (&req, 0, sizeof (req));

	/* repeat as long as there are http requests to do */
	do {
		req.data = data;

		*pRet = PianoRequest (ph, &req, type);
		if (*pRet != PIANO_RET_OK) {
			BarUiMsg (MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
			PianoDestroyRequest (&req);
			return 0;
		}

		*wRet = BarPianoHttpRequest (waith, &req);
		if (*wRet != WAITRESS_RET_OK) {
			BarUiMsg (MSG_NONE, "Network error: %s\n", WaitressErrorToStr (*wRet));
			PianoDestroyRequest (&req);
			if (req.responseData != NULL) {
				free (req.responseData);
			}
			return 0;
		}

		*pRet = PianoResponse (ph, &req);
		if (*pRet != PIANO_RET_CONTINUE_REQUEST) {
			if (*pRet != PIANO_RET_OK) {
				BarUiMsg (MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
				PianoDestroyRequest (&req);
				if (req.responseData != NULL) {
					free (req.responseData);
				}
				return 0;
			} else {
				BarUiMsg (MSG_NONE, "Ok.\n");
			}
		}
		/* we can destroy the request at this point, even when this call needs
		 * more than one http request. persistend data (step counter, e.g.) is
		 * stored in req.data */
		if (req.responseData != NULL) {
			free (req.responseData);
		}
		PianoDestroyRequest (&req);
	} while (*pRet == PIANO_RET_CONTINUE_REQUEST);

	return 1;
}
Esempio n. 2
0
/*	prints human readable status message based on return value
 *	@param piano return value
 */
inline PianoReturn_t BarUiPrintPianoStatus (PianoReturn_t ret) {
	if (ret != PIANO_RET_OK) {
		BarUiMsg (MSG_NONE, "Error: %s\n", PianoErrorToStr (ret));
	} else {
		BarUiMsg (MSG_NONE, "Ok.\n");
	}
	return ret;
}
Esempio n. 3
0
/*	Excute external event handler
 *	@param settings containing the cmdline
 *	@param event type
 *	@param current station
 *	@param current song
 *	@param piano error-code (PIANO_RET_OK if not applicable)
 *	@param waitress error-code (WAITRESS_RET_OK if not applicable)
 */
void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
		const PianoStation_t *curStation, const PianoSong_t *curSong,
		const struct audioPlayer *player, PianoStation_t *stations,
                PianoReturn_t pRet, WaitressReturn_t wRet) {
	pid_t chld;
	int pipeFd[2];

	if (settings->eventCmd == NULL) {
		/* nothing to do... */
		return;
	}

	if (pipe (pipeFd) == -1) {
		BarUiMsg (settings, MSG_ERR, "Cannot create eventcmd pipe. (%s)\n", strerror (errno));
		return;
	}

	chld = fork ();
	if (chld == 0) {
		/* child */
		close (pipeFd[1]);
		dup2 (pipeFd[0], fileno (stdin));
		execl (settings->eventCmd, settings->eventCmd, type, (char *) NULL);
		BarUiMsg (settings, MSG_ERR, "Cannot start eventcmd. (%s)\n", strerror (errno));
		close (pipeFd[0]);
		exit (1);
	} else if (chld == -1) {
		BarUiMsg (settings, MSG_ERR, "Cannot fork eventcmd. (%s)\n", strerror (errno));
	} else {
		/* parent */
		int status;
		PianoStation_t *songStation = NULL;
		FILE *pipeWriteFd;

		close (pipeFd[0]);

		pipeWriteFd = fdopen (pipeFd[1], "w");

		if (curSong != NULL && stations != NULL && curStation->isQuickMix) {
			songStation = PianoFindStationById (stations, curSong->stationId);
		}

		fprintf (pipeWriteFd,
				"artist=%s\n"
				"title=%s\n"
				"album=%s\n"
				"coverArt=%s\n"
				"stationName=%s\n"
				"songStationName=%s\n"
				"pRet=%i\n"
				"pRetStr=%s\n"
				"wRet=%i\n"
				"wRetStr=%s\n"
				"songDuration=%lu\n"
				"songPlayed=%lu\n"
				"rating=%i\n"
				"detailUrl=%s\n",
				curSong == NULL ? "" : curSong->artist,
				curSong == NULL ? "" : curSong->title,
				curSong == NULL ? "" : curSong->album,
				curSong == NULL ? "" : curSong->coverArt,
				curStation == NULL ? "" : curStation->name,
				songStation == NULL ? "" : songStation->name,
				pRet,
				PianoErrorToStr (pRet),
				wRet,
				WaitressErrorToStr (wRet),
				player->songDuration,
				player->songPlayed,
				curSong == NULL ? PIANO_RATE_NONE : curSong->rating,
				curSong == NULL ? "" : curSong->detailUrl
				);

		if (stations != NULL) {
			/* send station list */
			PianoStation_t **sortedStations = NULL;
			size_t stationCount;
			sortedStations = BarSortedStations (stations, &stationCount,
					settings->sortOrder);
			assert (sortedStations != NULL);

			fprintf (pipeWriteFd, "stationCount=%zd\n", stationCount);

			for (size_t i = 0; i < stationCount; i++) {
				const PianoStation_t *currStation = sortedStations[i];
				fprintf (pipeWriteFd, "station%zd=%s\n", i,
						currStation->name);
			}
			free (sortedStations);
		} else {
			const char * const msg = "stationCount=0\n";
			fwrite (msg, sizeof (*msg), strlen (msg), pipeWriteFd);
		}
	
		/* closes pipeFd[1] as well */
		fclose (pipeWriteFd);
		/* wait to get rid of the zombie */
		waitpid (chld, &status, 0);
	}
}
Esempio n. 4
0
/*	piano wrapper: prepare/execute http request and pass result back to
 *	libpiano (updates data structures)
 *	@param app handle
 *	@param request type
 *	@param request data
 *	@param stores piano return code
 *	@param stores waitress return code
 *	@return 1 on success, 0 otherwise
 */
int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type,
		void *data, PianoReturn_t *pRet, WaitressReturn_t *wRet) {
	PianoRequest_t req;

	memset (&req, 0, sizeof (req));

	/* repeat as long as there are http requests to do */
	do {
		req.data = data;

		*pRet = PianoRequest (&app->ph, &req, type);
		if (*pRet != PIANO_RET_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
			PianoDestroyRequest (&req);
			return 0;
		}

		*wRet = BarPianoHttpRequest (&app->waith, &req);
		if (*wRet != WAITRESS_RET_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Network error: %s\n", WaitressErrorToStr (*wRet));
			if (req.responseData != NULL) {
				free (req.responseData);
			}
			PianoDestroyRequest (&req);
			return 0;
		}

		*pRet = PianoResponse (&app->ph, &req);
		if (*pRet != PIANO_RET_CONTINUE_REQUEST) {
			/* checking for request type avoids infinite loops */
			if (*pRet == PIANO_RET_P_INVALID_AUTH_TOKEN &&
					type != PIANO_REQUEST_LOGIN) {
				/* reauthenticate */
				PianoReturn_t authpRet;
				WaitressReturn_t authwRet;
				PianoRequestDataLogin_t reqData;
				reqData.user = app->settings.username;
				reqData.password = app->settings.password;
				reqData.step = 0;

				BarUiMsg (&app->settings, MSG_NONE, "Reauthentication required... ");
				if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &authpRet,
						&authwRet)) {
					*pRet = authpRet;
					*wRet = authwRet;
					if (req.responseData != NULL) {
						free (req.responseData);
					}
					PianoDestroyRequest (&req);
					return 0;
				} else {
					/* try again */
					*pRet = PIANO_RET_CONTINUE_REQUEST;
					BarUiMsg (&app->settings, MSG_INFO, "Trying again... ");
				}
			} else if (*pRet != PIANO_RET_OK) {
				BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
				if (req.responseData != NULL) {
					free (req.responseData);
				}
				PianoDestroyRequest (&req);
				return 0;
			} else {
				BarUiMsg (&app->settings, MSG_NONE, "Ok.\n");
			}
		}
		/* we can destroy the request at this point, even when this call needs
		 * more than one http request. persistent data (step counter, e.g.) is
		 * stored in req.data */
		if (req.responseData != NULL) {
			free (req.responseData);
		}
		PianoDestroyRequest (&req);
	} while (*pRet == PIANO_RET_CONTINUE_REQUEST);

	return 1;
}
Esempio n. 5
0
int main (int argc, char **argv) {
	static BarApp_t app;

	memset (&app, 0, sizeof (app));

	/* save terminal attributes, before disabling echoing */
	BarTermInit ();

	/* signals */
	signal (SIGPIPE, SIG_IGN);

	/* init some things */
	gcry_check_version (NULL);
	gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
	gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
	BarPlayerInit ();

	BarSettingsInit (&app.settings);
	BarSettingsRead (&app.settings);

	PianoReturn_t pret;
	if ((pret = PianoInit (&app.ph, app.settings.partnerUser,
			app.settings.partnerPassword, app.settings.device,
			app.settings.inkey, app.settings.outkey)) != PIANO_RET_OK) {
		BarUiMsg (&app.settings, MSG_ERR, "Initialization failed:"
				" %s\n", PianoErrorToStr (pret));
		return 0;
	}

	BarUiMsg (&app.settings, MSG_NONE,
			"Welcome to " PACKAGE " (" VERSION ")! ");
	if (app.settings.keys[BAR_KS_HELP] == BAR_KS_DISABLED) {
		BarUiMsg (&app.settings, MSG_NONE, "\n");
	} else {
		BarUiMsg (&app.settings, MSG_NONE,
				"Press %c for a list of commands.\n",
				app.settings.keys[BAR_KS_HELP]);
	}

	curl_global_init (CURL_GLOBAL_DEFAULT);
	app.http = curl_easy_init ();
	assert (app.http != NULL);

	/* init fds */
	FD_ZERO(&app.input.set);

        int fifo_uses_this_fd = 0;
	app.input.fds[0] = STDIN_FILENO;
        if (isatty(fileno(stdin))) {
	    fifo_uses_this_fd = 1;
	    FD_SET(app.input.fds[0], &app.input.set);
            }

	/* open fifo read/write so it won't EOF if nobody writes to it */
	assert (sizeof (app.input.fds) / sizeof (*app.input.fds) >= 2);
	app.input.fds[fifo_uses_this_fd] = open (app.settings.fifo, O_RDWR);
	if (app.input.fds[fifo_uses_this_fd] != -1) {
		struct stat s;

		/* check for file type, must be fifo */
		fstat (app.input.fds[fifo_uses_this_fd], &s);
		if (!S_ISFIFO (s.st_mode)) {
			BarUiMsg (&app.settings, MSG_ERR, "File at %s is not a fifo\n", app.settings.fifo);
			close (app.input.fds[fifo_uses_this_fd]);
			app.input.fds[fifo_uses_this_fd] = -1;
		} else {
			FD_SET(app.input.fds[fifo_uses_this_fd], &app.input.set);
			BarUiMsg (&app.settings, MSG_INFO, "Control fifo at %s opened\n",
					app.settings.fifo);
		}
	}
        app.input.maxfd = app.input.fds[0];
        if (fifo_uses_this_fd>0)
		app.input.maxfd = app.input.fds[0] > app.input.fds[1] ? app.input.fds[0] : app.input.fds[1];
	++app.input.maxfd;

	BarMainLoop (&app);

	if (app.input.fds[fifo_uses_this_fd] != -1) {
		close (app.input.fds[fifo_uses_this_fd]);
	}

	/* write statefile */
	BarSettingsWrite (app.curStation, &app.settings);

	PianoDestroy (&app.ph);
	PianoDestroyPlaylist (app.songHistory);
	PianoDestroyPlaylist (app.playlist);
	curl_easy_cleanup (app.http);
	curl_global_cleanup ();
	BarPlayerDestroy ();
	BarSettingsDestroy (&app.settings);

	/* restore terminal attributes, zsh doesn't need this, bash does... */
	BarTermRestore ();

	return 0;
}
Esempio n. 6
0
int
MythPianoService::PianoCall(PianoRequestType_t type,
			    void *data,
			    PianoReturn_t *pRet,
			    WaitressReturn_t *wRet) {
  if (!m_Piano)
    return -1;

  PianoRequest_t req;
  memset (&req, 0, sizeof (req));

  /* repeat as long as there are http requests to do */
  do {
    req.data = data;

    *pRet = PianoRequest (m_Piano, &req, type);

    if (*pRet != PIANO_RET_OK) {
      BroadcastMessage("Error: %s\n", PianoErrorToStr (*pRet));
      PianoDestroyRequest (&req);
      return 0;
    }

    *wRet = PianoHttpRequest(&m_Waith, &req);
    if (*wRet != WAITRESS_RET_OK) {
      BroadcastMessage ("Network error: %s\n", WaitressErrorToStr (*wRet));
      if (req.responseData != NULL) {
	free (req.responseData);
      }
      PianoDestroyRequest (&req);
      return 0;
    }

    *pRet = PianoResponse (m_Piano, &req);
    if (*pRet != PIANO_RET_CONTINUE_REQUEST) {
      /* checking for request type avoids infinite loops */
      if (*pRet == PIANO_RET_AUTH_TOKEN_INVALID &&
	  type != PIANO_REQUEST_LOGIN) {
	/* reauthenticate */
        PianoReturn_t authpRet;
        WaitressReturn_t authwRet;
        PianoRequestDataLogin_t reqData;

        QString username = gCoreContext->GetSetting("pandora-username");
        QString password = gCoreContext->GetSetting("pandora-password");

        //wtf really?
        char* usernameBuff = strndup(username.toUtf8().data(), 1024);
        char* passwordBuff = strndup(password.toUtf8().data(), 1024);

        reqData.user = usernameBuff;
        reqData.password = passwordBuff;
        reqData.step = 0;

        BroadcastMessage ("Reauthentication required... ");
        if (!PianoCall(PIANO_REQUEST_LOGIN, &reqData, &authpRet, &authwRet)) {
          *pRet = authpRet;
          *wRet = authwRet;
          if (req.responseData != NULL) {
            free (req.responseData);
          }
          PianoDestroyRequest (&req);
          return 0;
        } else {
          /* try again */
          *pRet = PIANO_RET_CONTINUE_REQUEST;
          BroadcastMessage("Trying again... ");
        }

        // wtf
        free(usernameBuff);
        free(passwordBuff);

      } else if (*pRet != PIANO_RET_OK) {
	BroadcastMessage("Error: %s\n", PianoErrorToStr (*pRet));
	if (req.responseData != NULL) {
	  free (req.responseData);
	}
	PianoDestroyRequest (&req);
	return 0;
      } else {
	BroadcastMessage("Login Ok.\n");
      }
    }
    /* we can destroy the request at this point, even when this call needs
     * more than one http request. persistent data (step counter, e.g.) is
     * stored in req.data */
    if (req.responseData != NULL) {
      free (req.responseData);
    }
    PianoDestroyRequest (&req);
  } while (*pRet == PIANO_RET_CONTINUE_REQUEST);

  return 1;
}
Esempio n. 7
0
int main (int argc, char **argv) {
	static BarApp_t app;
	/* terminal attributes _before_ we started messing around with ~ECHO */
	struct termios termOrig;

	memset (&app, 0, sizeof (app));

	/* save terminal attributes, before disabling echoing */
	BarTermSave (&termOrig);
	BarTermSetEcho (0);
	BarTermSetBuffer (0);

	/* signals */
	signal (SIGPIPE, SIG_IGN);

	/* init some things */
	gcry_check_version (NULL);
	gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
	gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
	gnutls_global_init ();
	BarPlayerInit ();

	BarSettingsInit (&app.settings);
	BarSettingsRead (&app.settings);

	PianoReturn_t pret;
	if ((pret = PianoInit (&app.ph, app.settings.partnerUser,
			app.settings.partnerPassword, app.settings.device,
			app.settings.inkey, app.settings.outkey)) != PIANO_RET_OK) {
		BarUiMsg (&app.settings, MSG_ERR, "Initialization failed:"
				" %s\n", PianoErrorToStr (pret));
		return 0;
	}

	BarUiMsg (&app.settings, MSG_NONE,
			"Welcome to " PACKAGE " (" VERSION ")! ");
	if (app.settings.keys[BAR_KS_HELP] == BAR_KS_DISABLED) {
		BarUiMsg (&app.settings, MSG_NONE, "\n");
	} else {
		BarUiMsg (&app.settings, MSG_NONE,
				"Press %c for a list of commands.\n",
				app.settings.keys[BAR_KS_HELP]);
	}

	WaitressInit (&app.waith);
	app.waith.url.host = app.settings.rpcHost;
	app.waith.url.tlsPort = app.settings.rpcTlsPort;
	app.waith.tlsFingerprint = app.settings.tlsFingerprint;

	/* init fds */
	FD_ZERO(&app.input.set);
	app.input.fds[0] = STDIN_FILENO;
	FD_SET(app.input.fds[0], &app.input.set);

	/* open fifo read/write so it won't EOF if nobody writes to it */
	assert (sizeof (app.input.fds) / sizeof (*app.input.fds) >= 2);
	app.input.fds[1] = open (app.settings.fifo, O_RDWR);
	if (app.input.fds[1] != -1) {
		struct stat s;

		/* check for file type, must be fifo */
		fstat (app.input.fds[1], &s);
		if (!S_ISFIFO (s.st_mode)) {
			BarUiMsg (&app.settings, MSG_ERR, "File at %s is not a fifo\n", app.settings.fifo);
			close (app.input.fds[1]);
			app.input.fds[1] = -1;
		} else {
			FD_SET(app.input.fds[1], &app.input.set);
			BarUiMsg (&app.settings, MSG_INFO, "Control fifo at %s opened\n",
					app.settings.fifo);
		}
	}
	app.input.maxfd = app.input.fds[0] > app.input.fds[1] ? app.input.fds[0] :
			app.input.fds[1];
	++app.input.maxfd;

	BarMainLoop (&app);

	if (app.input.fds[1] != -1) {
		close (app.input.fds[1]);
	}

	/* write statefile */
	BarSettingsWrite (app.curStation, &app.settings);

	PianoDestroy (&app.ph);
	PianoDestroyPlaylist (app.songHistory);
	PianoDestroyPlaylist (app.playlist);
	WaitressFree (&app.waith);
	BarPlayerDestroy ();
	gnutls_global_deinit ();
	BarSettingsDestroy (&app.settings);

	/* restore terminal attributes, zsh doesn't need this, bash does... */
	BarTermRestore (&termOrig);

	return 0;
}
Esempio n. 8
0
File: ui.c Progetto: biorisk/panpigo
/*	Excute external event handler
 *	@param settings containing the cmdline
 *	@param event type
 *	@param current station
 *	@param current song
 *	@param piano error-code (PIANO_RET_OK if not applicable)
 *	@param waitress error-code (WAITRESS_RET_OK if not applicable)
 */
void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
		const PianoStation_t *curStation, const PianoSong_t *curSong,
		const struct audioPlayer *player, PianoStation_t *stations,
                PianoReturn_t pRet, WaitressReturn_t wRet) {

	int status;
	PianoStation_t *songStation = NULL;

	if (curSong != NULL && stations != NULL && curStation->isQuickMix) {
		songStation = PianoFindStationById (stations, curSong->stationId);
	}

	printf ("current\tartist=%s\n"
			"current\ttitle=%s\n"
			"current\talbum=%s\n"
			"current\tcoverArt=%s\n"
			"current\tstationName=%s\n"
			"songStationName=%s\n"
			"pRet=%i\n"
			"pRetStr=%s\n"
			"wRet=%i\n"
			"wRetStr=%s\n"
			"songDuration=%lu\n"
			"songPlayed=%lu\n"
			"rating=%i\n"
			"detailUrl=%s\n",
			curSong == NULL ? "" : curSong->artist,
			curSong == NULL ? "" : curSong->title,
			curSong == NULL ? "" : curSong->album,
			curSong == NULL ? "" : curSong->coverArt,
			curStation == NULL ? "" : curStation->name,
			songStation == NULL ? "" : songStation->name,
			pRet,
			PianoErrorToStr (pRet),
			wRet,
			WaitressErrorToStr (wRet),
			player->songDuration,
			player->songPlayed,
			curSong == NULL ? PIANO_RATE_NONE : curSong->rating,
			curSong == NULL ? "" : curSong->detailUrl
			);

	if (stations != NULL) {
		/* send station list */
		PianoStation_t **sortedStations = NULL;
		size_t stationCount;
		sortedStations = BarSortedStations (stations, &stationCount,
				settings->sortOrder);
		assert (sortedStations != NULL);

		printf ("station\tstationCount=%zd\n", stationCount);

		for (size_t i = 0; i < stationCount; i++) {
			const PianoStation_t *currStation = sortedStations[i];
			printf ("station\tstation%zd=%s\n", i,
					currStation->name);
		}

		free (sortedStations);
	}
}
Esempio n. 9
0
/*	piano wrapper: prepare/execute http request and pass result back to
 *	libpiano
 */
bool BarUiPianoCall (BarApp_t * const app, const PianoRequestType_t type,
		void * const data, PianoReturn_t * const pRet, CURLcode * const wRet) {
	PianoReturn_t pRetLocal = PIANO_RET_OK;
	CURLcode wRetLocal = CURLE_OK;
	bool ret = false;

	/* repeat as long as there are http requests to do */
	do {
		PianoRequest_t req = { .data = data, .responseData = NULL };

		pRetLocal = PianoRequest (&app->ph, &req, type);
		if (pRetLocal != PIANO_RET_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n",
					PianoErrorToStr (pRetLocal));
			goto cleanup;
		}

		wRetLocal = BarPianoHttpRequest (app->http, &app->settings, &req);
		if (wRetLocal == CURLE_ABORTED_BY_CALLBACK) {
			BarUiMsg (&app->settings, MSG_NONE, "Interrupted.\n");
			goto cleanup;
		} else if (wRetLocal != CURLE_OK) {
			BarUiMsg (&app->settings, MSG_NONE, "Network error: %s\n",
					curl_easy_strerror (wRetLocal));
			goto cleanup;
		}

		pRetLocal = PianoResponse (&app->ph, &req);
		if (pRetLocal != PIANO_RET_CONTINUE_REQUEST) {
			/* checking for request type avoids infinite loops */
			if (pRetLocal == PIANO_RET_P_INVALID_AUTH_TOKEN &&
					type != PIANO_REQUEST_LOGIN) {
				/* reauthenticate */
				PianoRequestDataLogin_t reqData;
				reqData.user = app->settings.username;
				reqData.password = app->settings.password;
				reqData.step = 0;

				BarUiMsg (&app->settings, MSG_NONE,
						"Reauthentication required... ");
				if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData,
						&pRetLocal, &wRetLocal)) {
					goto cleanup;
				} else {
					/* try again */
					pRetLocal = PIANO_RET_CONTINUE_REQUEST;
					BarUiMsg (&app->settings, MSG_INFO, "Trying again... ");
				}
			} else if (pRetLocal != PIANO_RET_OK) {
				BarUiMsg (&app->settings, MSG_NONE, "Error: %s\n",
						PianoErrorToStr (pRetLocal));
				goto cleanup;
			} else {
				BarUiMsg (&app->settings, MSG_NONE, "Ok.\n");
				ret = true;
			}
		}

cleanup:
		/* persistent data is stored in req.data */
		free (req.responseData);
		PianoDestroyRequest (&req);
	} while (pRetLocal == PIANO_RET_CONTINUE_REQUEST);

	*pRet = pRetLocal;
	*wRet = wRetLocal;

	return ret;
}
Esempio n. 10
0
/*	Excute external event handler
 *	@param settings containing the cmdline
 *	@param event type
 *	@param current station
 *	@param current song
 *	@param piano error-code (PIANO_RET_OK if not applicable)
 *	@param waitress error-code (WAITRESS_RET_OK if not applicable)
 */
void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
		const PianoStation_t *curStation, const PianoSong_t *curSong,
		const struct audioPlayer *player, PianoReturn_t pRet,
		WaitressReturn_t wRet) {
	pid_t chld;
	char pipeBuf[1024];
	int pipeFd[2];

	if (settings->eventCmd == NULL) {
		/* nothing to do... */
		return;
	}

	/* prepare stdin content */
	memset (pipeBuf, 0, sizeof (pipeBuf));
	snprintf (pipeBuf, sizeof (pipeBuf),
			"artist=%s\n"
			"title=%s\n"
			"album=%s\n"
			"stationName=%s\n"
			"pRet=%i\n"
			"pRetStr=%s\n"
			"wRet=%i\n"
			"wRetStr=%s\n"
			"songDuration=%lu\n"
			"songPlayed=%lu\n"
			"rating=%i\n",
			curSong == NULL ? "" : curSong->artist,
			curSong == NULL ? "" : curSong->title,
			curSong == NULL ? "" : curSong->album,
			curStation == NULL ? "" : curStation->name,
			pRet,
			PianoErrorToStr (pRet),
			wRet,
			WaitressErrorToStr (wRet),
			player->songDuration,
			player->songPlayed,
			curSong == NULL ? PIANO_RATE_NONE : curSong->rating
			);
	
	if (pipe (pipeFd) == -1) {
		BarUiMsg (MSG_ERR, "Cannot create eventcmd pipe. (%s)\n", strerror (errno));
		return;
	}

	chld = fork ();
	if (chld == 0) {
		/* child */
		close (pipeFd[1]);
		dup2 (pipeFd[0], fileno (stdin));
		execl (settings->eventCmd, settings->eventCmd, type, (char *) NULL);
		BarUiMsg (MSG_ERR, "Cannot start eventcmd. (%s)\n", strerror (errno));
		close (pipeFd[0]);
		exit (1);
	} else if (chld == -1) {
		BarUiMsg (MSG_ERR, "Cannot fork eventcmd. (%s)\n", strerror (errno));
	} else {
		/* parent */
		int status;
		close (pipeFd[0]);
		write (pipeFd[1], pipeBuf, strlen (pipeBuf));
		close (pipeFd[1]);
		/* wait to get rid of the zombie */
		waitpid (chld, &status, 0);
	}
}