Disclaimer: in a comment in the answer of Joachim Isaksson I've suggested a variation on one of his query to the OP, who asked clarification, this is it.
Starting from the query with the modification
SELECT SQL_CALC_FOUND_ROWS c.user_id
FROM customer AS c
JOIN customer_activity AS ca
ON ca.user_id = c.user_id
WHERE ca.type IN('downloaded_software',
'filled_download_form',
'purchased')
GROUP BY c.user_id
HAVING COUNT(DISTINCT ca.type) = 2
AND COUNT(CASE WHEN ca.type = 'purchased' THEN 1 ELSE NULL END) = 0
ORDER BY c.user_id
LIMIT 0, 100
the part in bold is my suggested edit.
If something it's not clear outside the part I modified you should ask to Joachim Isaksson, as he is the one who wrote the query.
My edit does what it say on the tin: the first condition check that there are only two of the three valid values of type, the second one check that 'purchased' is the one left out. The second condition is equivalent to
SUM(CASE WHEN ca.type = 'purchased' THEN 1 ELSE 0 END) = 0
that is maybe more simple to read.
The whole query is equivalent to
SELECT SQL_CALC_FOUND_ROWS c.user_id
FROM customer AS c
JOIN customer_activity AS ca
ON ca.user_id = c.user_id
WHERE ca.type IN('downloaded_software',
'filled_download_form',
'purchased')
GROUP BY c.user_id
HAVING COUNT(DISTINCT
CASE WHEN ca.type = 'downloaded_software' THEN 1 ELSE NULL END) = 1
AND COUNT(DISTINCT
CASE WHEN ca.type = 'filled_download_form' THEN 1 ELSE NULL END) = 1
AND COUNT(DISTINCT
CASE WHEN ca.type = 'purchased' THEN 1 ELSE NULL END) = 0
ORDER BY c.user_id
LIMIT 0, 100
(if you only have those 3 type the WHERE is not necessary)
If you're writing the query from a programming language I will use this as the template
SELECT SQL_CALC_FOUND_ROWS c.user_id
FROM customer AS c
JOIN customer_activity AS ca
ON ca.user_id = c.user_id
WHERE ca.type IN('downloaded_software',
'filled_download_form',
'purchased')
GROUP BY c.user_id
HAVING COUNT(DISTINCT
CASE WHEN ca.type = 'downloaded_software'
THEN 1 ELSE NULL END) = ?downloaded?
AND COUNT(DISTINCT
CASE WHEN ca.type = 'filled_download_form'
THEN 1 ELSE NULL END) = ?filled?
AND COUNT(DISTINCT
CASE WHEN ca.type = 'purchased'
THEN 1 ELSE NULL END) = ?purchased?
ORDER BY c.user_id
LIMIT 0, 100
with ?downloaded?, ?filled? and ?purchased? as parameters. 1 mean that the type need to be present, 0 mean that the parameter need to be missing
To answer the other question For example, only target customers who have neither filled_download_form nor purchased. What would be the query for that? just fill the parameters accordingly.